1//===- unittests/Analysis/FlowSensitive/TransferTest.cpp ------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "TestingSupport.h"
10#include "clang/AST/ASTContext.h"
11#include "clang/AST/Decl.h"
12#include "clang/ASTMatchers/ASTMatchers.h"
13#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
14#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
15#include "clang/Analysis/FlowSensitive/NoopAnalysis.h"
16#include "clang/Analysis/FlowSensitive/RecordOps.h"
17#include "clang/Analysis/FlowSensitive/StorageLocation.h"
18#include "clang/Analysis/FlowSensitive/Value.h"
19#include "clang/Basic/LangStandard.h"
20#include "clang/Testing/TestAST.h"
21#include "llvm/ADT/SmallVector.h"
22#include "llvm/ADT/StringRef.h"
23#include "llvm/Testing/Support/Error.h"
24#include "gmock/gmock.h"
25#include "gtest/gtest.h"
26#include <optional>
27#include <string>
28#include <utility>
29
30namespace {
31
32using namespace clang;
33using namespace dataflow;
34using namespace test;
35using ::testing::Eq;
36using ::testing::IsNull;
37using ::testing::Ne;
38using ::testing::NotNull;
39using ::testing::UnorderedElementsAre;
40
41// Declares a minimal coroutine library.
42constexpr llvm::StringRef CoroutineLibrary = R"cc(
43struct promise;
44struct task;
45
46namespace std {
47template <class, class...>
48struct coroutine_traits {};
49template <>
50struct coroutine_traits<task> {
51 using promise_type = promise;
52};
53
54template <class Promise = void>
55struct coroutine_handle {
56 static constexpr coroutine_handle from_address(void *addr) { return {}; }
57};
58} // namespace std
59
60struct awaitable {
61 bool await_ready() const noexcept;
62 void await_suspend(std::coroutine_handle<promise>) const noexcept;
63 void await_resume() const noexcept;
64};
65struct task {};
66struct promise {
67 task get_return_object();
68 awaitable initial_suspend();
69 awaitable final_suspend() noexcept;
70 void unhandled_exception();
71 void return_void();
72};
73)cc";
74
75void runDataflow(
76 llvm::StringRef Code,
77 std::function<
78 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
79 ASTContext &)>
80 VerifyResults,
81 DataflowAnalysisOptions Options,
82 LangStandard::Kind Std = LangStandard::lang_cxx17,
83 llvm::StringRef TargetFun = "target") {
84 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code, VerifyResults, Options,
85 Std, TargetFun),
86 llvm::Succeeded());
87}
88
89void runDataflow(
90 llvm::StringRef Code,
91 std::function<
92 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
93 ASTContext &)>
94 VerifyResults,
95 LangStandard::Kind Std = LangStandard::lang_cxx17,
96 bool ApplyBuiltinTransfer = true, llvm::StringRef TargetFun = "target") {
97 runDataflow(Code, VerifyResults: std::move(VerifyResults),
98 Options: {.BuiltinOpts: ApplyBuiltinTransfer ? BuiltinOptions{}
99 : std::optional<BuiltinOptions>()},
100 Std, TargetFun);
101}
102
103void runDataflowOnLambda(
104 llvm::StringRef Code,
105 std::function<
106 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
107 ASTContext &)>
108 VerifyResults,
109 DataflowAnalysisOptions Options,
110 LangStandard::Kind Std = LangStandard::lang_cxx17) {
111 ASSERT_THAT_ERROR(
112 checkDataflowWithNoopAnalysis(
113 Code,
114 ast_matchers::hasDeclContext(
115 ast_matchers::cxxRecordDecl(ast_matchers::isLambda())),
116 VerifyResults, Options, Std),
117 llvm::Succeeded());
118}
119
120void runDataflowOnLambda(
121 llvm::StringRef Code,
122 std::function<
123 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
124 ASTContext &)>
125 VerifyResults,
126 LangStandard::Kind Std = LangStandard::lang_cxx17,
127 bool ApplyBuiltinTransfer = true) {
128 runDataflowOnLambda(Code, VerifyResults: std::move(VerifyResults),
129 Options: {.BuiltinOpts: ApplyBuiltinTransfer ? BuiltinOptions{}
130 : std::optional<BuiltinOptions>()},
131 Std);
132}
133
134const Formula &getFormula(const ValueDecl &D, const Environment &Env) {
135 return cast<BoolValue>(Val: Env.getValue(D))->formula();
136}
137
138TEST(TransferTest, CNotSupported) {
139 TestInputs Inputs("void target() {}");
140 Inputs.Language = TestLanguage::Lang_C89;
141 clang::TestAST AST(Inputs);
142 const auto *Target =
143 cast<FunctionDecl>(Val: test::findValueDecl(ASTCtx&: AST.context(), Name: "target"));
144 ASSERT_THAT_ERROR(AdornedCFG::build(*Target).takeError(),
145 llvm::FailedWithMessage("Can only analyze C++"));
146}
147
148TEST(TransferTest, ObjectiveCNotSupported) {
149 TestInputs Inputs("void target() {}");
150 Inputs.Language = TestLanguage::Lang_OBJC;
151 clang::TestAST AST(Inputs);
152 const auto *Target =
153 cast<FunctionDecl>(Val: test::findValueDecl(ASTCtx&: AST.context(), Name: "target"));
154 ASSERT_THAT_ERROR(AdornedCFG::build(*Target).takeError(),
155 llvm::FailedWithMessage("Can only analyze C++"));
156}
157
158TEST(TransferTest, ObjectiveCXXNotSupported) {
159 TestInputs Inputs("void target() {}");
160 Inputs.Language = TestLanguage::Lang_OBJCXX;
161 clang::TestAST AST(Inputs);
162 const auto *Target =
163 cast<FunctionDecl>(Val: test::findValueDecl(ASTCtx&: AST.context(), Name: "target"));
164 ASSERT_THAT_ERROR(AdornedCFG::build(*Target).takeError(),
165 llvm::FailedWithMessage("Can only analyze C++"));
166}
167
168TEST(TransferTest, IntVarDeclNotTrackedWhenTransferDisabled) {
169 std::string Code = R"(
170 void target() {
171 int Foo;
172 // [[p]]
173 }
174 )";
175 runDataflow(
176 Code,
177 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
178 ASTContext &ASTCtx) {
179 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
180 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
181
182 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
183 ASSERT_THAT(FooDecl, NotNull());
184
185 EXPECT_EQ(Env.getStorageLocation(*FooDecl), nullptr);
186 },
187 Std: LangStandard::lang_cxx17,
188 /*ApplyBuiltinTransfer=*/false);
189}
190
191TEST(TransferTest, BoolVarDecl) {
192 std::string Code = R"(
193 void target() {
194 bool Foo;
195 // [[p]]
196 }
197 )";
198 runDataflow(
199 Code,
200 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
201 ASTContext &ASTCtx) {
202 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
203 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
204
205 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
206 ASSERT_THAT(FooDecl, NotNull());
207
208 const StorageLocation *FooLoc = Env.getStorageLocation(D: *FooDecl);
209 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
210
211 const Value *FooVal = Env.getValue(Loc: *FooLoc);
212 EXPECT_TRUE(isa_and_nonnull<BoolValue>(FooVal));
213 });
214}
215
216TEST(TransferTest, IntVarDecl) {
217 std::string Code = R"(
218 void target() {
219 int Foo;
220 // [[p]]
221 }
222 )";
223 runDataflow(
224 Code,
225 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
226 ASTContext &ASTCtx) {
227 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
228 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
229
230 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
231 ASSERT_THAT(FooDecl, NotNull());
232
233 const StorageLocation *FooLoc = Env.getStorageLocation(D: *FooDecl);
234 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
235
236 const Value *FooVal = Env.getValue(Loc: *FooLoc);
237 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
238 });
239}
240
241TEST(TransferTest, StructIncomplete) {
242 std::string Code = R"(
243 struct A;
244
245 void target() {
246 A* Foo;
247 // [[p]]
248 }
249 )";
250 runDataflow(
251 Code,
252 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
253 ASTContext &ASTCtx) {
254 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
255 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
256
257 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
258 ASSERT_THAT(FooDecl, NotNull());
259 auto *FooValue = dyn_cast_or_null<PointerValue>(Val: Env.getValue(D: *FooDecl));
260 ASSERT_THAT(FooValue, NotNull());
261
262 EXPECT_TRUE(isa<RecordStorageLocation>(FooValue->getPointeeLoc()));
263 });
264}
265
266// As a memory optimization, we prevent modeling fields nested below a certain
267// level (currently, depth 3). This test verifies this lack of modeling. We also
268// include a regression test for the case that the unmodeled field is a
269// reference to a struct; previously, we crashed when accessing such a field.
270TEST(TransferTest, StructFieldUnmodeled) {
271 std::string Code = R"(
272 struct S { int X; };
273 S GlobalS;
274 struct A { S &Unmodeled = GlobalS; };
275 struct B { A F3; };
276 struct C { B F2; };
277 struct D { C F1; };
278
279 void target() {
280 D Bar;
281 A &Foo = Bar.F1.F2.F3;
282 int Zab = Foo.Unmodeled.X;
283 // [[p]]
284 }
285 )";
286 runDataflow(
287 Code,
288 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
289 ASTContext &ASTCtx) {
290 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
291 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
292
293 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
294 ASSERT_THAT(FooDecl, NotNull());
295 QualType FooReferentType = FooDecl->getType()->getPointeeType();
296 ASSERT_TRUE(FooReferentType->isStructureType());
297 auto FooFields = FooReferentType->getAsRecordDecl()->fields();
298
299 FieldDecl *UnmodeledDecl = nullptr;
300 for (FieldDecl *Field : FooFields) {
301 if (Field->getNameAsString() == "Unmodeled") {
302 UnmodeledDecl = Field;
303 } else {
304 FAIL() << "Unexpected field: " << Field->getNameAsString();
305 }
306 }
307 ASSERT_THAT(UnmodeledDecl, NotNull());
308
309 const auto *FooLoc =
310 cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
311 const auto &UnmodeledLoc =
312 *cast<RecordStorageLocation>(Val: FooLoc->getChild(*UnmodeledDecl));
313 StorageLocation &UnmodeledXLoc = getFieldLoc(UnmodeledLoc, "X", ASTCtx);
314 EXPECT_EQ(Env.getValue(UnmodeledXLoc), nullptr);
315
316 const ValueDecl *ZabDecl = findValueDecl(ASTCtx, Name: "Zab");
317 ASSERT_THAT(ZabDecl, NotNull());
318 EXPECT_THAT(Env.getValue(*ZabDecl), NotNull());
319 });
320}
321
322TEST(TransferTest, StructVarDecl) {
323 std::string Code = R"(
324 struct A {
325 int Bar;
326 };
327
328 void target() {
329 A Foo;
330 (void)Foo.Bar;
331 // [[p]]
332 }
333 )";
334 runDataflow(
335 Code,
336 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
337 ASTContext &ASTCtx) {
338 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
339 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
340
341 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
342 ASSERT_THAT(FooDecl, NotNull());
343
344 ASSERT_TRUE(FooDecl->getType()->isStructureType());
345 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
346
347 FieldDecl *BarDecl = nullptr;
348 for (FieldDecl *Field : FooFields) {
349 if (Field->getNameAsString() == "Bar") {
350 BarDecl = Field;
351 } else {
352 FAIL() << "Unexpected field: " << Field->getNameAsString();
353 }
354 }
355 ASSERT_THAT(BarDecl, NotNull());
356
357 const auto *FooLoc =
358 cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
359 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
360 });
361}
362
363TEST(TransferTest, StructVarDeclWithInit) {
364 std::string Code = R"(
365 struct A {
366 int Bar;
367 };
368
369 A Gen();
370
371 void target() {
372 A Foo = Gen();
373 (void)Foo.Bar;
374 // [[p]]
375 }
376 )";
377 runDataflow(
378 Code,
379 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
380 ASTContext &ASTCtx) {
381 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
382 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
383
384 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
385 ASSERT_THAT(FooDecl, NotNull());
386
387 ASSERT_TRUE(FooDecl->getType()->isStructureType());
388 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
389
390 FieldDecl *BarDecl = nullptr;
391 for (FieldDecl *Field : FooFields) {
392 if (Field->getNameAsString() == "Bar") {
393 BarDecl = Field;
394 } else {
395 FAIL() << "Unexpected field: " << Field->getNameAsString();
396 }
397 }
398 ASSERT_THAT(BarDecl, NotNull());
399
400 const auto *FooLoc =
401 cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
402 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
403 });
404}
405
406TEST(TransferTest, StructArrayVarDecl) {
407 std::string Code = R"(
408 struct A {};
409
410 void target() {
411 A Array[2];
412 // [[p]]
413 }
414 )";
415 runDataflow(
416 Code,
417 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
418 ASTContext &ASTCtx) {
419 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
420
421 const ValueDecl *ArrayDecl = findValueDecl(ASTCtx, Name: "Array");
422
423 // We currently don't create values for arrays.
424 ASSERT_THAT(Env.getValue(*ArrayDecl), IsNull());
425 });
426}
427
428TEST(TransferTest, ClassVarDecl) {
429 std::string Code = R"(
430 class A {
431 public:
432 int Bar;
433 };
434
435 void target() {
436 A Foo;
437 (void)Foo.Bar;
438 // [[p]]
439 }
440 )";
441 runDataflow(
442 Code,
443 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
444 ASTContext &ASTCtx) {
445 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
446 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
447
448 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
449 ASSERT_THAT(FooDecl, NotNull());
450
451 ASSERT_TRUE(FooDecl->getType()->isClassType());
452 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
453
454 FieldDecl *BarDecl = nullptr;
455 for (FieldDecl *Field : FooFields) {
456 if (Field->getNameAsString() == "Bar") {
457 BarDecl = Field;
458 } else {
459 FAIL() << "Unexpected field: " << Field->getNameAsString();
460 }
461 }
462 ASSERT_THAT(BarDecl, NotNull());
463
464 const auto *FooLoc =
465 cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
466 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
467 });
468}
469
470TEST(TransferTest, ReferenceVarDecl) {
471 std::string Code = R"(
472 struct A {};
473
474 A &getA();
475
476 void target() {
477 A &Foo = getA();
478 // [[p]]
479 }
480 )";
481 runDataflow(
482 Code,
483 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
484 ASTContext &ASTCtx) {
485 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
486 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
487
488 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
489 ASSERT_THAT(FooDecl, NotNull());
490
491 const StorageLocation *FooLoc = Env.getStorageLocation(D: *FooDecl);
492 ASSERT_TRUE(isa_and_nonnull<RecordStorageLocation>(FooLoc));
493 });
494}
495
496TEST(TransferTest, SelfReferentialReferenceVarDecl) {
497 std::string Code = R"(
498 struct A;
499
500 struct B {};
501
502 struct C {
503 A &FooRef;
504 A *FooPtr;
505 B &BazRef;
506 B *BazPtr;
507 };
508
509 struct A {
510 C &Bar;
511 };
512
513 A &getA();
514
515 void target() {
516 A &Foo = getA();
517 (void)Foo.Bar.FooRef;
518 (void)Foo.Bar.FooPtr;
519 (void)Foo.Bar.BazRef;
520 (void)Foo.Bar.BazPtr;
521 // [[p]]
522 }
523 )";
524 runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>>
525 &Results,
526 ASTContext &ASTCtx) {
527 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
528 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
529
530 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
531 ASSERT_THAT(FooDecl, NotNull());
532
533 ASSERT_TRUE(FooDecl->getType()->isReferenceType());
534 ASSERT_TRUE(FooDecl->getType().getNonReferenceType()->isStructureType());
535 const auto FooFields =
536 FooDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields();
537
538 FieldDecl *BarDecl = nullptr;
539 for (FieldDecl *Field : FooFields) {
540 if (Field->getNameAsString() == "Bar") {
541 BarDecl = Field;
542 } else {
543 FAIL() << "Unexpected field: " << Field->getNameAsString();
544 }
545 }
546 ASSERT_THAT(BarDecl, NotNull());
547
548 ASSERT_TRUE(BarDecl->getType()->isReferenceType());
549 ASSERT_TRUE(BarDecl->getType().getNonReferenceType()->isStructureType());
550 const auto BarFields =
551 BarDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields();
552
553 FieldDecl *FooRefDecl = nullptr;
554 FieldDecl *FooPtrDecl = nullptr;
555 FieldDecl *BazRefDecl = nullptr;
556 FieldDecl *BazPtrDecl = nullptr;
557 for (FieldDecl *Field : BarFields) {
558 if (Field->getNameAsString() == "FooRef") {
559 FooRefDecl = Field;
560 } else if (Field->getNameAsString() == "FooPtr") {
561 FooPtrDecl = Field;
562 } else if (Field->getNameAsString() == "BazRef") {
563 BazRefDecl = Field;
564 } else if (Field->getNameAsString() == "BazPtr") {
565 BazPtrDecl = Field;
566 } else {
567 FAIL() << "Unexpected field: " << Field->getNameAsString();
568 }
569 }
570 ASSERT_THAT(FooRefDecl, NotNull());
571 ASSERT_THAT(FooPtrDecl, NotNull());
572 ASSERT_THAT(BazRefDecl, NotNull());
573 ASSERT_THAT(BazPtrDecl, NotNull());
574
575 const auto &FooLoc =
576 *cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
577
578 const auto &BarLoc =
579 *cast<RecordStorageLocation>(Val: FooLoc.getChild(*BarDecl));
580
581 const auto &FooReferentLoc =
582 *cast<RecordStorageLocation>(BarLoc.getChild(*FooRefDecl));
583 EXPECT_EQ(Env.getValue(*cast<RecordStorageLocation>(
584 FooReferentLoc.getChild(*BarDecl))
585 ->getChild(*FooPtrDecl)),
586 nullptr);
587
588 const auto &FooPtrVal =
589 *cast<PointerValue>(getFieldValue(&BarLoc, *FooPtrDecl, Env));
590 const auto &FooPtrPointeeLoc =
591 cast<RecordStorageLocation>(FooPtrVal.getPointeeLoc());
592 EXPECT_EQ(Env.getValue(*cast<RecordStorageLocation>(
593 FooPtrPointeeLoc.getChild(*BarDecl))
594 ->getChild(*FooPtrDecl)),
595 nullptr);
596
597 EXPECT_TRUE(isa<PointerValue>(getFieldValue(&BarLoc, *BazPtrDecl, Env)));
598 });
599}
600
601TEST(TransferTest, PointerVarDecl) {
602 std::string Code = R"(
603 struct A {};
604
605 A *getA();
606
607 void target() {
608 A *Foo = getA();
609 // [[p]]
610 }
611 )";
612 runDataflow(
613 Code,
614 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
615 ASTContext &ASTCtx) {
616 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
617 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
618
619 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
620 ASSERT_THAT(FooDecl, NotNull());
621
622 const StorageLocation *FooLoc = Env.getStorageLocation(D: *FooDecl);
623 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
624
625 const PointerValue *FooVal = cast<PointerValue>(Val: Env.getValue(Loc: *FooLoc));
626 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
627 EXPECT_TRUE(isa<RecordStorageLocation>(&FooPointeeLoc));
628 });
629}
630
631TEST(TransferTest, SelfReferentialPointerVarDecl) {
632 std::string Code = R"(
633 struct A;
634
635 struct B {};
636
637 struct C {
638 A &FooRef;
639 A *FooPtr;
640 B &BazRef;
641 B *BazPtr;
642 };
643
644 struct A {
645 C *Bar;
646 };
647
648 A *getA();
649
650 void target() {
651 A *Foo = getA();
652 (void)Foo->Bar->FooRef;
653 (void)Foo->Bar->FooPtr;
654 (void)Foo->Bar->BazRef;
655 (void)Foo->Bar->BazPtr;
656 // [[p]]
657 }
658 )";
659 runDataflow(
660 Code,
661 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
662 ASTContext &ASTCtx) {
663 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
664 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
665
666 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
667 ASSERT_THAT(FooDecl, NotNull());
668
669 ASSERT_TRUE(FooDecl->getType()->isPointerType());
670 ASSERT_TRUE(FooDecl->getType()
671 ->getAs<PointerType>()
672 ->getPointeeType()
673 ->isStructureType());
674 const auto FooFields = FooDecl->getType()
675 ->getAs<PointerType>()
676 ->getPointeeType()
677 ->getAsRecordDecl()
678 ->fields();
679
680 FieldDecl *BarDecl = nullptr;
681 for (FieldDecl *Field : FooFields) {
682 if (Field->getNameAsString() == "Bar") {
683 BarDecl = Field;
684 } else {
685 FAIL() << "Unexpected field: " << Field->getNameAsString();
686 }
687 }
688 ASSERT_THAT(BarDecl, NotNull());
689
690 ASSERT_TRUE(BarDecl->getType()->isPointerType());
691 ASSERT_TRUE(BarDecl->getType()
692 ->getAs<PointerType>()
693 ->getPointeeType()
694 ->isStructureType());
695 const auto BarFields = BarDecl->getType()
696 ->getAs<PointerType>()
697 ->getPointeeType()
698 ->getAsRecordDecl()
699 ->fields();
700
701 FieldDecl *FooRefDecl = nullptr;
702 FieldDecl *FooPtrDecl = nullptr;
703 FieldDecl *BazRefDecl = nullptr;
704 FieldDecl *BazPtrDecl = nullptr;
705 for (FieldDecl *Field : BarFields) {
706 if (Field->getNameAsString() == "FooRef") {
707 FooRefDecl = Field;
708 } else if (Field->getNameAsString() == "FooPtr") {
709 FooPtrDecl = Field;
710 } else if (Field->getNameAsString() == "BazRef") {
711 BazRefDecl = Field;
712 } else if (Field->getNameAsString() == "BazPtr") {
713 BazPtrDecl = Field;
714 } else {
715 FAIL() << "Unexpected field: " << Field->getNameAsString();
716 }
717 }
718 ASSERT_THAT(FooRefDecl, NotNull());
719 ASSERT_THAT(FooPtrDecl, NotNull());
720 ASSERT_THAT(BazRefDecl, NotNull());
721 ASSERT_THAT(BazPtrDecl, NotNull());
722
723 const auto &FooLoc =
724 *cast<ScalarStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
725 const auto &FooVal = *cast<PointerValue>(Val: Env.getValue(FooLoc));
726 const auto &FooPointeeLoc =
727 cast<RecordStorageLocation>(FooVal.getPointeeLoc());
728
729 const auto &BarVal =
730 *cast<PointerValue>(getFieldValue(&FooPointeeLoc, *BarDecl, Env));
731 const auto &BarPointeeLoc =
732 cast<RecordStorageLocation>(BarVal.getPointeeLoc());
733
734 const auto &FooPtrVal = *cast<PointerValue>(
735 getFieldValue(&BarPointeeLoc, *FooPtrDecl, Env));
736 const auto &FooPtrPointeeLoc =
737 cast<RecordStorageLocation>(FooPtrVal.getPointeeLoc());
738 EXPECT_EQ(Env.getValue(*FooPtrPointeeLoc.getChild(*BarDecl)), nullptr);
739
740 EXPECT_TRUE(
741 isa<PointerValue>(getFieldValue(&BarPointeeLoc, *BazPtrDecl, Env)));
742 });
743}
744
745TEST(TransferTest, DirectlySelfReferentialReference) {
746 std::string Code = R"(
747 struct target {
748 target() {
749 (void)0;
750 // [[p]]
751 }
752 target &self = *this;
753 };
754 )";
755 runDataflow(
756 Code,
757 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
758 ASTContext &ASTCtx) {
759 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
760 const ValueDecl *SelfDecl = findValueDecl(ASTCtx, Name: "self");
761
762 auto *ThisLoc = Env.getThisPointeeStorageLocation();
763 ASSERT_EQ(ThisLoc->getChild(*SelfDecl), ThisLoc);
764 });
765}
766
767TEST(TransferTest, MultipleVarsDecl) {
768 std::string Code = R"(
769 void target() {
770 int Foo, Bar;
771 (void)0;
772 // [[p]]
773 }
774 )";
775 runDataflow(
776 Code,
777 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
778 ASTContext &ASTCtx) {
779 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
780 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
781
782 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
783 ASSERT_THAT(FooDecl, NotNull());
784
785 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
786 ASSERT_THAT(BarDecl, NotNull());
787
788 const StorageLocation *FooLoc = Env.getStorageLocation(D: *FooDecl);
789 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
790
791 const StorageLocation *BarLoc = Env.getStorageLocation(D: *BarDecl);
792 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
793
794 const Value *FooVal = Env.getValue(Loc: *FooLoc);
795 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
796
797 const Value *BarVal = Env.getValue(Loc: *BarLoc);
798 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
799 });
800}
801
802TEST(TransferTest, JoinVarDecl) {
803 std::string Code = R"(
804 void target(bool B) {
805 int Foo;
806 // [[p1]]
807 if (B) {
808 int Bar;
809 // [[p2]]
810 } else {
811 int Baz;
812 // [[p3]]
813 }
814 (void)0;
815 // [[p4]]
816 }
817 )";
818 runDataflow(Code, VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>>
819 &Results,
820 ASTContext &ASTCtx) {
821 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2", "p3", "p4"));
822
823 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
824 ASSERT_THAT(FooDecl, NotNull());
825
826 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
827 ASSERT_THAT(BarDecl, NotNull());
828
829 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
830 ASSERT_THAT(BazDecl, NotNull());
831
832 const Environment &Env1 = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p1");
833
834 const StorageLocation *FooLoc = Env1.getStorageLocation(D: *FooDecl);
835 EXPECT_THAT(FooLoc, NotNull());
836 EXPECT_THAT(Env1.getStorageLocation(*BarDecl), IsNull());
837 EXPECT_THAT(Env1.getStorageLocation(*BazDecl), IsNull());
838
839 const Environment &Env2 = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p2");
840 EXPECT_EQ(Env2.getStorageLocation(*FooDecl), FooLoc);
841 EXPECT_THAT(Env2.getStorageLocation(*BarDecl), NotNull());
842 EXPECT_THAT(Env2.getStorageLocation(*BazDecl), IsNull());
843
844 const Environment &Env3 = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p3");
845 EXPECT_EQ(Env3.getStorageLocation(*FooDecl), FooLoc);
846 EXPECT_THAT(Env3.getStorageLocation(*BarDecl), IsNull());
847 EXPECT_THAT(Env3.getStorageLocation(*BazDecl), NotNull());
848
849 const Environment &Env4 = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p4");
850 EXPECT_EQ(Env4.getStorageLocation(*FooDecl), FooLoc);
851 EXPECT_THAT(Env4.getStorageLocation(*BarDecl), IsNull());
852 EXPECT_THAT(Env4.getStorageLocation(*BazDecl), IsNull());
853 });
854}
855
856TEST(TransferTest, BinaryOperatorAssign) {
857 std::string Code = R"(
858 void target() {
859 int Foo;
860 int Bar;
861 (Bar) = (Foo);
862 // [[p]]
863 }
864 )";
865 runDataflow(
866 Code,
867 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
868 ASTContext &ASTCtx) {
869 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
870 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
871
872 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
873 ASSERT_THAT(FooDecl, NotNull());
874
875 const Value *FooVal = Env.getValue(D: *FooDecl);
876 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
877
878 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
879 ASSERT_THAT(BarDecl, NotNull());
880
881 EXPECT_EQ(Env.getValue(*BarDecl), FooVal);
882 });
883}
884
885TEST(TransferTest, BinaryOperatorAssignIntegerLiteral) {
886 std::string Code = R"(
887 void target() {
888 int Foo = 1;
889 // [[before]]
890 Foo = 2;
891 // [[after]]
892 }
893 )";
894 runDataflow(
895 Code,
896 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
897 ASTContext &ASTCtx) {
898 const Environment &Before =
899 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "before");
900 const Environment &After = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "after");
901
902 const auto &ValBefore =
903 getValueForDecl<IntegerValue>(ASTCtx, Env: Before, Name: "Foo");
904 const auto &ValAfter =
905 getValueForDecl<IntegerValue>(ASTCtx, Env: After, Name: "Foo");
906 EXPECT_NE(&ValBefore, &ValAfter);
907 });
908}
909
910TEST(TransferTest, VarDeclInitAssign) {
911 std::string Code = R"(
912 void target() {
913 int Foo;
914 int Bar = Foo;
915 // [[p]]
916 }
917 )";
918 runDataflow(
919 Code,
920 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
921 ASTContext &ASTCtx) {
922 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
923 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
924
925 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
926 ASSERT_THAT(FooDecl, NotNull());
927
928 const Value *FooVal = Env.getValue(D: *FooDecl);
929 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
930
931 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
932 ASSERT_THAT(BarDecl, NotNull());
933
934 EXPECT_EQ(Env.getValue(*BarDecl), FooVal);
935 });
936}
937
938TEST(TransferTest, VarDeclInitAssignChained) {
939 std::string Code = R"(
940 void target() {
941 int Foo;
942 int Bar;
943 int Baz = (Bar = Foo);
944 // [[p]]
945 }
946 )";
947 runDataflow(
948 Code,
949 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
950 ASTContext &ASTCtx) {
951 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
952 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
953
954 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
955 ASSERT_THAT(FooDecl, NotNull());
956
957 const Value *FooVal = Env.getValue(D: *FooDecl);
958 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
959
960 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
961 ASSERT_THAT(BarDecl, NotNull());
962
963 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
964 ASSERT_THAT(BazDecl, NotNull());
965
966 EXPECT_EQ(Env.getValue(*BarDecl), FooVal);
967 EXPECT_EQ(Env.getValue(*BazDecl), FooVal);
968 });
969}
970
971TEST(TransferTest, VarDeclInitAssignPtrDeref) {
972 std::string Code = R"(
973 void target() {
974 int Foo;
975 int *Bar;
976 *(Bar) = Foo;
977 int Baz = *(Bar);
978 // [[p]]
979 }
980 )";
981 runDataflow(
982 Code,
983 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
984 ASTContext &ASTCtx) {
985 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
986 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
987
988 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
989 ASSERT_THAT(FooDecl, NotNull());
990
991 const Value *FooVal = Env.getValue(D: *FooDecl);
992 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
993
994 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
995 ASSERT_THAT(BarDecl, NotNull());
996
997 const auto *BarVal = cast<PointerValue>(Val: Env.getValue(D: *BarDecl));
998 EXPECT_EQ(Env.getValue(BarVal->getPointeeLoc()), FooVal);
999
1000 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
1001 ASSERT_THAT(BazDecl, NotNull());
1002
1003 EXPECT_EQ(Env.getValue(*BazDecl), FooVal);
1004 });
1005}
1006
1007TEST(TransferTest, AssignToAndFromReference) {
1008 std::string Code = R"(
1009 void target() {
1010 int Foo;
1011 int Bar;
1012 int &Baz = Foo;
1013 // [[p1]]
1014 Baz = Bar;
1015 int Qux = Baz;
1016 int &Quux = Baz;
1017 // [[p2]]
1018 }
1019 )";
1020 runDataflow(
1021 Code,
1022 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1023 ASTContext &ASTCtx) {
1024 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
1025 const Environment &Env1 = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p1");
1026 const Environment &Env2 = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p2");
1027
1028 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
1029 ASSERT_THAT(FooDecl, NotNull());
1030
1031 const Value *FooVal = Env1.getValue(D: *FooDecl);
1032 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
1033
1034 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
1035 ASSERT_THAT(BarDecl, NotNull());
1036
1037 const Value *BarVal = Env1.getValue(D: *BarDecl);
1038 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1039
1040 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
1041 ASSERT_THAT(BazDecl, NotNull());
1042
1043 EXPECT_EQ(Env1.getValue(*BazDecl), FooVal);
1044
1045 EXPECT_EQ(Env2.getValue(*BazDecl), BarVal);
1046 EXPECT_EQ(Env2.getValue(*FooDecl), BarVal);
1047
1048 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, Name: "Qux");
1049 ASSERT_THAT(QuxDecl, NotNull());
1050 EXPECT_EQ(Env2.getValue(*QuxDecl), BarVal);
1051
1052 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, Name: "Quux");
1053 ASSERT_THAT(QuuxDecl, NotNull());
1054 EXPECT_EQ(Env2.getValue(*QuuxDecl), BarVal);
1055 });
1056}
1057
1058TEST(TransferTest, MultipleParamDecls) {
1059 std::string Code = R"(
1060 void target(int Foo, int Bar) {
1061 (void)0;
1062 // [[p]]
1063 }
1064 )";
1065 runDataflow(
1066 Code,
1067 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1068 ASTContext &ASTCtx) {
1069 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1070 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
1071
1072 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
1073 ASSERT_THAT(FooDecl, NotNull());
1074
1075 const StorageLocation *FooLoc = Env.getStorageLocation(D: *FooDecl);
1076 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
1077
1078 const Value *FooVal = Env.getValue(Loc: *FooLoc);
1079 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
1080
1081 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
1082 ASSERT_THAT(BarDecl, NotNull());
1083
1084 const StorageLocation *BarLoc = Env.getStorageLocation(D: *BarDecl);
1085 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1086
1087 const Value *BarVal = Env.getValue(Loc: *BarLoc);
1088 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1089 });
1090}
1091
1092TEST(TransferTest, StructParamDecl) {
1093 std::string Code = R"(
1094 struct A {
1095 int Bar;
1096 };
1097
1098 void target(A Foo) {
1099 (void)Foo.Bar;
1100 // [[p]]
1101 }
1102 )";
1103 runDataflow(
1104 Code,
1105 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1106 ASTContext &ASTCtx) {
1107 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1108 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
1109
1110 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
1111 ASSERT_THAT(FooDecl, NotNull());
1112
1113 ASSERT_TRUE(FooDecl->getType()->isStructureType());
1114 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1115
1116 FieldDecl *BarDecl = nullptr;
1117 for (FieldDecl *Field : FooFields) {
1118 if (Field->getNameAsString() == "Bar") {
1119 BarDecl = Field;
1120 } else {
1121 FAIL() << "Unexpected field: " << Field->getNameAsString();
1122 }
1123 }
1124 ASSERT_THAT(BarDecl, NotNull());
1125
1126 const auto *FooLoc =
1127 cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
1128 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
1129 });
1130}
1131
1132TEST(TransferTest, ReferenceParamDecl) {
1133 std::string Code = R"(
1134 struct A {};
1135
1136 void target(A &Foo) {
1137 (void)0;
1138 // [[p]]
1139 }
1140 )";
1141 runDataflow(
1142 Code,
1143 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1144 ASTContext &ASTCtx) {
1145 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1146 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
1147
1148 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
1149 ASSERT_THAT(FooDecl, NotNull());
1150
1151 const StorageLocation *FooLoc = Env.getStorageLocation(D: *FooDecl);
1152 ASSERT_TRUE(isa_and_nonnull<RecordStorageLocation>(FooLoc));
1153 });
1154}
1155
1156TEST(TransferTest, PointerParamDecl) {
1157 std::string Code = R"(
1158 struct A {};
1159
1160 void target(A *Foo) {
1161 (void)0;
1162 // [[p]]
1163 }
1164 )";
1165 runDataflow(
1166 Code,
1167 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1168 ASTContext &ASTCtx) {
1169 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1170 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
1171
1172 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
1173 ASSERT_THAT(FooDecl, NotNull());
1174
1175 const StorageLocation *FooLoc = Env.getStorageLocation(D: *FooDecl);
1176 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
1177
1178 const PointerValue *FooVal = cast<PointerValue>(Val: Env.getValue(Loc: *FooLoc));
1179 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
1180 EXPECT_TRUE(isa<RecordStorageLocation>(&FooPointeeLoc));
1181 });
1182}
1183
1184TEST(TransferTest, StructMember) {
1185 std::string Code = R"(
1186 struct A {
1187 int Bar;
1188 };
1189
1190 void target(A Foo) {
1191 int Baz = Foo.Bar;
1192 // [[p]]
1193 }
1194 )";
1195 runDataflow(
1196 Code,
1197 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1198 ASTContext &ASTCtx) {
1199 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1200 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
1201
1202 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
1203 ASSERT_THAT(FooDecl, NotNull());
1204
1205 ASSERT_TRUE(FooDecl->getType()->isStructureType());
1206 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1207
1208 FieldDecl *BarDecl = nullptr;
1209 for (FieldDecl *Field : FooFields) {
1210 if (Field->getNameAsString() == "Bar") {
1211 BarDecl = Field;
1212 } else {
1213 FAIL() << "Unexpected field: " << Field->getNameAsString();
1214 }
1215 }
1216 ASSERT_THAT(BarDecl, NotNull());
1217
1218 const auto *FooLoc =
1219 cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
1220 const auto *BarVal =
1221 cast<IntegerValue>(Val: getFieldValue(FooLoc, *BarDecl, Env));
1222
1223 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
1224 ASSERT_THAT(BazDecl, NotNull());
1225
1226 EXPECT_EQ(Env.getValue(*BazDecl), BarVal);
1227 });
1228}
1229
1230TEST(TransferTest, StructMemberEnum) {
1231 std::string Code = R"(
1232 struct A {
1233 int Bar;
1234 enum E { ONE, TWO };
1235 };
1236
1237 void target(A Foo) {
1238 A::E Baz = Foo.ONE;
1239 // [[p]]
1240 }
1241 )";
1242 // Minimal expectations -- we're just testing that it doesn't crash, since
1243 // enums aren't interpreted.
1244 runDataflow(
1245 Code,
1246 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1247 ASTContext &ASTCtx) {
1248 EXPECT_THAT(Results.keys(), UnorderedElementsAre("p"));
1249 });
1250}
1251
1252TEST(TransferTest, DerivedBaseMemberClass) {
1253 std::string Code = R"(
1254 class A {
1255 int ADefault;
1256 protected:
1257 int AProtected;
1258 private:
1259 int APrivate;
1260 public:
1261 int APublic;
1262
1263 private:
1264 friend void target();
1265 };
1266
1267 class B : public A {
1268 int BDefault;
1269 protected:
1270 int BProtected;
1271 private:
1272 int BPrivate;
1273
1274 private:
1275 friend void target();
1276 };
1277
1278 void target() {
1279 B Foo;
1280 (void)Foo.ADefault;
1281 (void)Foo.AProtected;
1282 (void)Foo.APrivate;
1283 (void)Foo.APublic;
1284 (void)Foo.BDefault;
1285 (void)Foo.BProtected;
1286 (void)Foo.BPrivate;
1287 // [[p]]
1288 }
1289 )";
1290 runDataflow(
1291 Code,
1292 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1293 ASTContext &ASTCtx) {
1294 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1295 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
1296
1297 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
1298 ASSERT_THAT(FooDecl, NotNull());
1299 ASSERT_TRUE(FooDecl->getType()->isRecordType());
1300
1301 // Derived-class fields.
1302 const FieldDecl *BDefaultDecl = nullptr;
1303 const FieldDecl *BProtectedDecl = nullptr;
1304 const FieldDecl *BPrivateDecl = nullptr;
1305 for (const FieldDecl *Field :
1306 FooDecl->getType()->getAsRecordDecl()->fields()) {
1307 if (Field->getNameAsString() == "BDefault") {
1308 BDefaultDecl = Field;
1309 } else if (Field->getNameAsString() == "BProtected") {
1310 BProtectedDecl = Field;
1311 } else if (Field->getNameAsString() == "BPrivate") {
1312 BPrivateDecl = Field;
1313 } else {
1314 FAIL() << "Unexpected field: " << Field->getNameAsString();
1315 }
1316 }
1317 ASSERT_THAT(BDefaultDecl, NotNull());
1318 ASSERT_THAT(BProtectedDecl, NotNull());
1319 ASSERT_THAT(BPrivateDecl, NotNull());
1320
1321 // Base-class fields.
1322 const FieldDecl *ADefaultDecl = nullptr;
1323 const FieldDecl *APrivateDecl = nullptr;
1324 const FieldDecl *AProtectedDecl = nullptr;
1325 const FieldDecl *APublicDecl = nullptr;
1326 for (const clang::CXXBaseSpecifier &Base :
1327 FooDecl->getType()->getAsCXXRecordDecl()->bases()) {
1328 QualType BaseType = Base.getType();
1329 ASSERT_TRUE(BaseType->isRecordType());
1330 for (const FieldDecl *Field : BaseType->getAsRecordDecl()->fields()) {
1331 if (Field->getNameAsString() == "ADefault") {
1332 ADefaultDecl = Field;
1333 } else if (Field->getNameAsString() == "AProtected") {
1334 AProtectedDecl = Field;
1335 } else if (Field->getNameAsString() == "APrivate") {
1336 APrivateDecl = Field;
1337 } else if (Field->getNameAsString() == "APublic") {
1338 APublicDecl = Field;
1339 } else {
1340 FAIL() << "Unexpected field: " << Field->getNameAsString();
1341 }
1342 }
1343 }
1344 ASSERT_THAT(ADefaultDecl, NotNull());
1345 ASSERT_THAT(AProtectedDecl, NotNull());
1346 ASSERT_THAT(APrivateDecl, NotNull());
1347 ASSERT_THAT(APublicDecl, NotNull());
1348
1349 ASSERT_TRUE(
1350 isa<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)));
1351 });
1352}
1353
1354static void derivedBaseMemberExpectations(
1355 const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1356 ASTContext &ASTCtx) {
1357 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1358 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
1359
1360 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
1361 ASSERT_THAT(FooDecl, NotNull());
1362
1363 ASSERT_TRUE(FooDecl->getType()->isRecordType());
1364 const FieldDecl *BarDecl = nullptr;
1365 for (const clang::CXXBaseSpecifier &Base :
1366 FooDecl->getType()->getAsCXXRecordDecl()->bases()) {
1367 QualType BaseType = Base.getType();
1368 ASSERT_TRUE(BaseType->isStructureType());
1369
1370 for (const FieldDecl *Field : BaseType->getAsRecordDecl()->fields()) {
1371 if (Field->getNameAsString() == "Bar") {
1372 BarDecl = Field;
1373 } else {
1374 FAIL() << "Unexpected field: " << Field->getNameAsString();
1375 }
1376 }
1377 }
1378 ASSERT_THAT(BarDecl, NotNull());
1379
1380 const auto &FooLoc =
1381 *cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
1382 EXPECT_NE(Env.getValue(*FooLoc.getChild(*BarDecl)), nullptr);
1383}
1384
1385TEST(TransferTest, DerivedBaseMemberStructDefault) {
1386 std::string Code = R"(
1387 struct A {
1388 int Bar;
1389 };
1390 struct B : public A {
1391 };
1392
1393 void target() {
1394 B Foo;
1395 (void)Foo.Bar;
1396 // [[p]]
1397 }
1398 )";
1399 runDataflow(Code, VerifyResults: derivedBaseMemberExpectations);
1400}
1401
1402TEST(TransferTest, DerivedBaseMemberPrivateFriend) {
1403 // Include an access to `Foo.Bar` to verify the analysis doesn't crash on that
1404 // access.
1405 std::string Code = R"(
1406 struct A {
1407 private:
1408 friend void target();
1409 int Bar;
1410 };
1411 struct B : public A {
1412 };
1413
1414 void target() {
1415 B Foo;
1416 (void)Foo.Bar;
1417 // [[p]]
1418 }
1419 )";
1420 runDataflow(Code, VerifyResults: derivedBaseMemberExpectations);
1421}
1422
1423TEST(TransferTest, ClassMember) {
1424 std::string Code = R"(
1425 class A {
1426 public:
1427 int Bar;
1428 };
1429
1430 void target(A Foo) {
1431 int Baz = Foo.Bar;
1432 // [[p]]
1433 }
1434 )";
1435 runDataflow(
1436 Code,
1437 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1438 ASTContext &ASTCtx) {
1439 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1440 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
1441
1442 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
1443 ASSERT_THAT(FooDecl, NotNull());
1444
1445 ASSERT_TRUE(FooDecl->getType()->isClassType());
1446 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1447
1448 FieldDecl *BarDecl = nullptr;
1449 for (FieldDecl *Field : FooFields) {
1450 if (Field->getNameAsString() == "Bar") {
1451 BarDecl = Field;
1452 } else {
1453 FAIL() << "Unexpected field: " << Field->getNameAsString();
1454 }
1455 }
1456 ASSERT_THAT(BarDecl, NotNull());
1457
1458 const auto *FooLoc =
1459 cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
1460 const auto *BarVal =
1461 cast<IntegerValue>(Val: getFieldValue(FooLoc, *BarDecl, Env));
1462
1463 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
1464 ASSERT_THAT(BazDecl, NotNull());
1465
1466 EXPECT_EQ(Env.getValue(*BazDecl), BarVal);
1467 });
1468}
1469
1470TEST(TransferTest, BaseClassInitializer) {
1471 using ast_matchers::cxxConstructorDecl;
1472 using ast_matchers::hasName;
1473 using ast_matchers::ofClass;
1474
1475 std::string Code = R"(
1476 class A {
1477 public:
1478 A(int I) : Bar(I) {}
1479 int Bar;
1480 };
1481
1482 class B : public A {
1483 public:
1484 B(int I) : A(I) {
1485 (void)0;
1486 // [[p]]
1487 }
1488 };
1489 )";
1490 ASSERT_THAT_ERROR(
1491 checkDataflow<NoopAnalysis>(
1492 AnalysisInputs<NoopAnalysis>(
1493 Code, cxxConstructorDecl(ofClass(hasName("B"))),
1494 [](ASTContext &C, Environment &) { return NoopAnalysis(C); })
1495 .withASTBuildArgs(
1496 {"-fsyntax-only", "-fno-delayed-template-parsing",
1497 "-std=" + std::string(LangStandard::getLangStandardForKind(
1498 LangStandard::lang_cxx17)
1499 .getName())}),
1500 /*VerifyResults=*/
1501 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1502 const AnalysisOutputs &) {
1503 // Regression test to verify that base-class initializers do not
1504 // trigger an assertion. If we add support for such initializers in
1505 // the future, we can expand this test to check more specific
1506 // properties.
1507 EXPECT_THAT(Results.keys(), UnorderedElementsAre("p"));
1508 }),
1509 llvm::Succeeded());
1510}
1511
1512TEST(TransferTest, FieldsDontHaveValuesInConstructor) {
1513 // In a constructor, unlike in regular member functions, we don't want fields
1514 // to be pre-initialized with values, because doing so is the job of the
1515 // constructor.
1516 std::string Code = R"(
1517 struct target {
1518 target() {
1519 0;
1520 // [[p]]
1521 // Mention the field so it is modeled;
1522 Val;
1523 }
1524
1525 int Val;
1526 };
1527 )";
1528 runDataflow(
1529 Code,
1530 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1531 ASTContext &ASTCtx) {
1532 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
1533 EXPECT_EQ(getFieldValue(Env.getThisPointeeStorageLocation(), "Val",
1534 ASTCtx, Env),
1535 nullptr);
1536 });
1537}
1538
1539TEST(TransferTest, FieldsDontHaveValuesInConstructorWithBaseClass) {
1540 // See above, but for a class with a base class.
1541 std::string Code = R"(
1542 struct Base {
1543 int BaseVal;
1544 };
1545
1546 struct target : public Base {
1547 target() {
1548 0;
1549 // [[p]]
1550 // Mention the fields so they are modeled.
1551 BaseVal;
1552 Val;
1553 }
1554
1555 int Val;
1556 };
1557 )";
1558 runDataflow(
1559 Code,
1560 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1561 ASTContext &ASTCtx) {
1562 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
1563 // The field of the base class should already have been initialized with
1564 // a value by the base constructor.
1565 EXPECT_NE(getFieldValue(Env.getThisPointeeStorageLocation(), "BaseVal",
1566 ASTCtx, Env),
1567 nullptr);
1568 EXPECT_EQ(getFieldValue(Env.getThisPointeeStorageLocation(), "Val",
1569 ASTCtx, Env),
1570 nullptr);
1571 });
1572}
1573
1574TEST(TransferTest, StructModeledFieldsWithAccessor) {
1575 std::string Code = R"(
1576 class S {
1577 int *Ptr;
1578 int *PtrNonConst;
1579 int Int;
1580 int IntWithInc;
1581 int IntNotAccessed;
1582 int IntRef;
1583 public:
1584 int *getPtr() const { return Ptr; }
1585 int *getPtrNonConst() { return PtrNonConst; }
1586 int getInt(int i) const { return Int; }
1587 int getWithInc(int i) { IntWithInc += i; return IntWithInc; }
1588 int getIntNotAccessed() const { return IntNotAccessed; }
1589 int getIntNoDefinition() const;
1590 int &getIntRef() { return IntRef; }
1591 void returnVoid() const { return; }
1592 };
1593
1594 void target() {
1595 S s;
1596 int *p1 = s.getPtr();
1597 int *p2 = s.getPtrNonConst();
1598 int i1 = s.getInt(1);
1599 int i2 = s.getWithInc(1);
1600 int i3 = s.getIntNoDefinition();
1601 int &iref = s.getIntRef();
1602
1603 // Regression test: Don't crash on an indirect call (which doesn't have
1604 // an associated `CXXMethodDecl`).
1605 auto ptr_to_member_fn = &S::getPtr;
1606 p1 = (s.*ptr_to_member_fn)();
1607
1608 // Regression test: Don't crash on a return statement without a value.
1609 s.returnVoid();
1610 // [[p]]
1611 }
1612 )";
1613 runDataflow(
1614 Code,
1615 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1616 ASTContext &ASTCtx) {
1617 const Environment &Env =
1618 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
1619 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, Name: "s");
1620 std::vector<const ValueDecl*> Fields;
1621 for (auto [Field, _] : SLoc.children())
1622 Fields.push_back(x: Field);
1623 // Only the fields that have simple accessor methods (that have a
1624 // single statement body that returns the member variable) should be
1625 // modeled.
1626 ASSERT_THAT(Fields, UnorderedElementsAre(
1627 findValueDecl(ASTCtx, "Ptr"), findValueDecl(ASTCtx, "PtrNonConst"),
1628 findValueDecl(ASTCtx, "Int"), findValueDecl(ASTCtx, "IntRef")));
1629 });
1630}
1631
1632TEST(TransferTest, StructModeledFieldsWithComplicatedInheritance) {
1633 std::string Code = R"(
1634 struct Base1 {
1635 int base1_1;
1636 int base1_2;
1637 };
1638 struct Intermediate : Base1 {
1639 int intermediate_1;
1640 int intermediate_2;
1641 };
1642 struct Base2 {
1643 int base2_1;
1644 int base2_2;
1645 };
1646 struct MostDerived : public Intermediate, Base2 {
1647 int most_derived_1;
1648 int most_derived_2;
1649 };
1650
1651 void target() {
1652 MostDerived MD;
1653 MD.base1_2 = 1;
1654 MD.intermediate_2 = 1;
1655 MD.base2_2 = 1;
1656 MD.most_derived_2 = 1;
1657 // [[p]]
1658 }
1659 )";
1660 runDataflow(
1661 Code,
1662 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1663 ASTContext &ASTCtx) {
1664 const Environment &Env =
1665 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
1666
1667 // Only the accessed fields should exist in the model.
1668 auto &MDLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, Name: "MD");
1669 std::vector<const ValueDecl*> Fields;
1670 for (auto [Field, _] : MDLoc.children())
1671 Fields.push_back(x: Field);
1672 ASSERT_THAT(Fields, UnorderedElementsAre(
1673 findValueDecl(ASTCtx, "base1_2"),
1674 findValueDecl(ASTCtx, "intermediate_2"),
1675 findValueDecl(ASTCtx, "base2_2"),
1676 findValueDecl(ASTCtx, "most_derived_2")));
1677 });
1678}
1679
1680TEST(TransferTest, StructInitializerListWithComplicatedInheritance) {
1681 std::string Code = R"(
1682 struct Base1 {
1683 int base1;
1684 };
1685 struct Intermediate : Base1 {
1686 int intermediate;
1687 };
1688 struct Base2 {
1689 int base2;
1690 };
1691 struct MostDerived : public Intermediate, Base2 {
1692 int most_derived;
1693 };
1694
1695 void target() {
1696 MostDerived MD = {};
1697 // [[p]]
1698 }
1699 )";
1700 runDataflow(
1701 Code,
1702 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1703 ASTContext &ASTCtx) {
1704 const Environment &Env =
1705 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
1706
1707 // When a struct is initialized with a initializer list, all the
1708 // fields are considered "accessed", and therefore do exist.
1709 auto &MD = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, Name: "MD");
1710 ASSERT_THAT(cast<IntegerValue>(
1711 getFieldValue(&MD, *findValueDecl(ASTCtx, "base1"), Env)),
1712 NotNull());
1713 ASSERT_THAT(cast<IntegerValue>(
1714 getFieldValue(&MD, *findValueDecl(ASTCtx, "intermediate"), Env)),
1715 NotNull());
1716 ASSERT_THAT(cast<IntegerValue>(
1717 getFieldValue(&MD, *findValueDecl(ASTCtx, "base2"), Env)),
1718 NotNull());
1719 ASSERT_THAT(cast<IntegerValue>(
1720 getFieldValue(&MD, *findValueDecl(ASTCtx, "most_derived"), Env)),
1721 NotNull());
1722 });
1723}
1724
1725TEST(TransferTest, ReferenceMember) {
1726 std::string Code = R"(
1727 struct A {
1728 int &Bar;
1729 };
1730
1731 void target(A Foo) {
1732 int Baz = Foo.Bar;
1733 // [[p]]
1734 }
1735 )";
1736 runDataflow(
1737 Code,
1738 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1739 ASTContext &ASTCtx) {
1740 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1741 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
1742
1743 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
1744 ASSERT_THAT(FooDecl, NotNull());
1745
1746 ASSERT_TRUE(FooDecl->getType()->isStructureType());
1747 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1748
1749 FieldDecl *BarDecl = nullptr;
1750 for (FieldDecl *Field : FooFields) {
1751 if (Field->getNameAsString() == "Bar") {
1752 BarDecl = Field;
1753 } else {
1754 FAIL() << "Unexpected field: " << Field->getNameAsString();
1755 }
1756 }
1757 ASSERT_THAT(BarDecl, NotNull());
1758
1759 const auto *FooLoc =
1760 cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
1761 const auto *BarReferentVal =
1762 cast<IntegerValue>(Val: getFieldValue(FooLoc, *BarDecl, Env));
1763
1764 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
1765 ASSERT_THAT(BazDecl, NotNull());
1766
1767 EXPECT_EQ(Env.getValue(*BazDecl), BarReferentVal);
1768 });
1769}
1770
1771TEST(TransferTest, StructThisMember) {
1772 std::string Code = R"(
1773 struct A {
1774 int Bar;
1775
1776 struct B {
1777 int Baz;
1778 };
1779
1780 B Qux;
1781
1782 void target() {
1783 int Foo = Bar;
1784 int Quux = Qux.Baz;
1785 // [[p]]
1786 }
1787 };
1788 )";
1789 runDataflow(
1790 Code,
1791 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1792 ASTContext &ASTCtx) {
1793 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1794 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
1795
1796 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
1797 ASSERT_THAT(ThisLoc, NotNull());
1798
1799 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
1800 ASSERT_THAT(BarDecl, NotNull());
1801
1802 const auto *BarLoc =
1803 cast<ScalarStorageLocation>(Val: ThisLoc->getChild(D: *BarDecl));
1804 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1805
1806 const Value *BarVal = Env.getValue(*BarLoc);
1807 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1808
1809 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
1810 ASSERT_THAT(FooDecl, NotNull());
1811 EXPECT_EQ(Env.getValue(*FooDecl), BarVal);
1812
1813 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, Name: "Qux");
1814 ASSERT_THAT(QuxDecl, NotNull());
1815
1816 ASSERT_TRUE(QuxDecl->getType()->isStructureType());
1817 auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields();
1818
1819 FieldDecl *BazDecl = nullptr;
1820 for (FieldDecl *Field : QuxFields) {
1821 if (Field->getNameAsString() == "Baz") {
1822 BazDecl = Field;
1823 } else {
1824 FAIL() << "Unexpected field: " << Field->getNameAsString();
1825 }
1826 }
1827 ASSERT_THAT(BazDecl, NotNull());
1828
1829 const auto *QuxLoc =
1830 cast<RecordStorageLocation>(Val: ThisLoc->getChild(D: *QuxDecl));
1831
1832 const auto *BazVal =
1833 cast<IntegerValue>(Val: getFieldValue(QuxLoc, *BazDecl, Env));
1834
1835 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, Name: "Quux");
1836 ASSERT_THAT(QuuxDecl, NotNull());
1837 EXPECT_EQ(Env.getValue(*QuuxDecl), BazVal);
1838 });
1839}
1840
1841TEST(TransferTest, ClassThisMember) {
1842 std::string Code = R"(
1843 class A {
1844 int Bar;
1845
1846 class B {
1847 public:
1848 int Baz;
1849 };
1850
1851 B Qux;
1852
1853 void target() {
1854 int Foo = Bar;
1855 int Quux = Qux.Baz;
1856 // [[p]]
1857 }
1858 };
1859 )";
1860 runDataflow(
1861 Code,
1862 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1863 ASTContext &ASTCtx) {
1864 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1865 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
1866
1867 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
1868
1869 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
1870 ASSERT_THAT(BarDecl, NotNull());
1871
1872 const auto *BarLoc =
1873 cast<ScalarStorageLocation>(Val: ThisLoc->getChild(D: *BarDecl));
1874 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1875
1876 const Value *BarVal = Env.getValue(*BarLoc);
1877 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1878
1879 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
1880 ASSERT_THAT(FooDecl, NotNull());
1881 EXPECT_EQ(Env.getValue(*FooDecl), BarVal);
1882
1883 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, Name: "Qux");
1884 ASSERT_THAT(QuxDecl, NotNull());
1885
1886 ASSERT_TRUE(QuxDecl->getType()->isClassType());
1887 auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields();
1888
1889 FieldDecl *BazDecl = nullptr;
1890 for (FieldDecl *Field : QuxFields) {
1891 if (Field->getNameAsString() == "Baz") {
1892 BazDecl = Field;
1893 } else {
1894 FAIL() << "Unexpected field: " << Field->getNameAsString();
1895 }
1896 }
1897 ASSERT_THAT(BazDecl, NotNull());
1898
1899 const auto *QuxLoc =
1900 cast<RecordStorageLocation>(Val: ThisLoc->getChild(D: *QuxDecl));
1901
1902 const auto *BazVal =
1903 cast<IntegerValue>(Val: getFieldValue(QuxLoc, *BazDecl, Env));
1904
1905 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, Name: "Quux");
1906 ASSERT_THAT(QuuxDecl, NotNull());
1907 EXPECT_EQ(Env.getValue(*QuuxDecl), BazVal);
1908 });
1909}
1910
1911TEST(TransferTest, UnionThisMember) {
1912 std::string Code = R"(
1913 union A {
1914 int Foo;
1915 int Bar;
1916
1917 void target() {
1918 A a;
1919 // Mention the fields to ensure they're included in the analysis.
1920 (void)a.Foo;
1921 (void)a.Bar;
1922 // [[p]]
1923 }
1924 };
1925 )";
1926 runDataflow(
1927 Code,
1928 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1929 ASTContext &ASTCtx) {
1930 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1931 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
1932
1933 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
1934 ASSERT_THAT(ThisLoc, NotNull());
1935
1936 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
1937 ASSERT_THAT(FooDecl, NotNull());
1938
1939 const auto *FooLoc =
1940 cast<ScalarStorageLocation>(Val: ThisLoc->getChild(D: *FooDecl));
1941 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
1942
1943 const Value *FooVal = Env.getValue(*FooLoc);
1944 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
1945
1946 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
1947 ASSERT_THAT(BarDecl, NotNull());
1948
1949 const auto *BarLoc =
1950 cast<ScalarStorageLocation>(Val: ThisLoc->getChild(D: *BarDecl));
1951 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1952
1953 const Value *BarVal = Env.getValue(*BarLoc);
1954 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1955 });
1956}
1957
1958TEST(TransferTest, StructThisInLambda) {
1959 std::string ThisCaptureCode = R"(
1960 struct A {
1961 void frob() {
1962 [this]() {
1963 int Foo = Bar;
1964 // [[p1]]
1965 }();
1966 }
1967
1968 int Bar;
1969 };
1970 )";
1971 runDataflow(
1972 ThisCaptureCode,
1973 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1974 ASTContext &ASTCtx) {
1975 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1"));
1976 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p1");
1977
1978 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
1979 ASSERT_THAT(ThisLoc, NotNull());
1980
1981 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
1982 ASSERT_THAT(BarDecl, NotNull());
1983
1984 const auto *BarLoc =
1985 cast<ScalarStorageLocation>(Val: ThisLoc->getChild(D: *BarDecl));
1986 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1987
1988 const Value *BarVal = Env.getValue(*BarLoc);
1989 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1990
1991 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
1992 ASSERT_THAT(FooDecl, NotNull());
1993 EXPECT_EQ(Env.getValue(*FooDecl), BarVal);
1994 },
1995 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()");
1996
1997 std::string RefCaptureDefaultCode = R"(
1998 struct A {
1999 void frob() {
2000 [&]() {
2001 int Foo = Bar;
2002 // [[p2]]
2003 }();
2004 }
2005
2006 int Bar;
2007 };
2008 )";
2009 runDataflow(
2010 RefCaptureDefaultCode,
2011 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2012 ASTContext &ASTCtx) {
2013 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p2"));
2014 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p2");
2015
2016 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
2017 ASSERT_THAT(ThisLoc, NotNull());
2018
2019 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
2020 ASSERT_THAT(BarDecl, NotNull());
2021
2022 const auto *BarLoc =
2023 cast<ScalarStorageLocation>(Val: ThisLoc->getChild(D: *BarDecl));
2024 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
2025
2026 const Value *BarVal = Env.getValue(*BarLoc);
2027 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
2028
2029 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
2030 ASSERT_THAT(FooDecl, NotNull());
2031 EXPECT_EQ(Env.getValue(*FooDecl), BarVal);
2032 },
2033 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()");
2034
2035 std::string FreeFunctionLambdaCode = R"(
2036 void foo() {
2037 int Bar;
2038 [&]() {
2039 int Foo = Bar;
2040 // [[p3]]
2041 }();
2042 }
2043 )";
2044 runDataflow(
2045 Code: FreeFunctionLambdaCode,
2046 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2047 ASTContext &ASTCtx) {
2048 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p3"));
2049 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p3");
2050
2051 EXPECT_THAT(Env.getThisPointeeStorageLocation(), IsNull());
2052 },
2053 Std: LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, TargetFun: "operator()");
2054}
2055
2056TEST(TransferTest, ConstructorInitializer) {
2057 std::string Code = R"(
2058 struct target {
2059 int Bar;
2060
2061 target(int Foo) : Bar(Foo) {
2062 int Qux = Bar;
2063 // [[p]]
2064 }
2065 };
2066 )";
2067 runDataflow(
2068 Code,
2069 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2070 ASTContext &ASTCtx) {
2071 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2072 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
2073
2074 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
2075 ASSERT_THAT(ThisLoc, NotNull());
2076
2077 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
2078 ASSERT_THAT(FooDecl, NotNull());
2079
2080 const auto *FooVal = cast<IntegerValue>(Val: Env.getValue(D: *FooDecl));
2081
2082 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, Name: "Qux");
2083 ASSERT_THAT(QuxDecl, NotNull());
2084 EXPECT_EQ(Env.getValue(*QuxDecl), FooVal);
2085 });
2086}
2087
2088TEST(TransferTest, DefaultInitializer) {
2089 std::string Code = R"(
2090 struct target {
2091 int Bar;
2092 int Baz = Bar;
2093
2094 target(int Foo) : Bar(Foo) {
2095 int Qux = Baz;
2096 // [[p]]
2097 }
2098 };
2099 )";
2100 runDataflow(
2101 Code,
2102 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2103 ASTContext &ASTCtx) {
2104 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2105 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
2106
2107 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
2108 ASSERT_THAT(ThisLoc, NotNull());
2109
2110 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
2111 ASSERT_THAT(FooDecl, NotNull());
2112
2113 const auto *FooVal = cast<IntegerValue>(Val: Env.getValue(D: *FooDecl));
2114
2115 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, Name: "Qux");
2116 ASSERT_THAT(QuxDecl, NotNull());
2117 EXPECT_EQ(Env.getValue(*QuxDecl), FooVal);
2118 });
2119}
2120
2121TEST(TransferTest, DefaultInitializerReference) {
2122 std::string Code = R"(
2123 struct target {
2124 int &Bar;
2125 int &Baz = Bar;
2126
2127 target(int &Foo) : Bar(Foo) {
2128 int &Qux = Baz;
2129 // [[p]]
2130 }
2131 };
2132 )";
2133 runDataflow(
2134 Code,
2135 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2136 ASTContext &ASTCtx) {
2137 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2138 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
2139
2140 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
2141 ASSERT_THAT(ThisLoc, NotNull());
2142
2143 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
2144 ASSERT_THAT(FooDecl, NotNull());
2145
2146 const auto *FooLoc = Env.getStorageLocation(D: *FooDecl);
2147
2148 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, Name: "Qux");
2149 ASSERT_THAT(QuxDecl, NotNull());
2150
2151 const auto *QuxLoc = Env.getStorageLocation(D: *QuxDecl);
2152 EXPECT_EQ(QuxLoc, FooLoc);
2153 });
2154}
2155
2156TEST(TransferTest, TemporaryObject) {
2157 std::string Code = R"(
2158 struct A {
2159 int Bar;
2160 };
2161
2162 void target() {
2163 A Foo = A();
2164 (void)Foo.Bar;
2165 // [[p]]
2166 }
2167 )";
2168 runDataflow(
2169 Code,
2170 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2171 ASTContext &ASTCtx) {
2172 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2173 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
2174
2175 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
2176 ASSERT_THAT(FooDecl, NotNull());
2177
2178 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
2179 ASSERT_THAT(BarDecl, NotNull());
2180
2181 const auto *FooLoc =
2182 cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
2183 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
2184 });
2185}
2186
2187TEST(TransferTest, ElidableConstructor) {
2188 // This test is effectively the same as TransferTest.TemporaryObject, but
2189 // the code is compiled as C++14.
2190 std::string Code = R"(
2191 struct A {
2192 int Bar;
2193 };
2194
2195 void target() {
2196 A Foo = A();
2197 (void)Foo.Bar;
2198 // [[p]]
2199 }
2200 )";
2201 runDataflow(
2202 Code,
2203 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2204 ASTContext &ASTCtx) {
2205 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2206 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
2207
2208 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
2209 ASSERT_THAT(FooDecl, NotNull());
2210
2211 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
2212 ASSERT_THAT(BarDecl, NotNull());
2213
2214 const auto *FooLoc =
2215 cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
2216 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
2217 },
2218 Std: LangStandard::lang_cxx14);
2219}
2220
2221TEST(TransferTest, AssignmentOperator) {
2222 std::string Code = R"(
2223 struct A {
2224 int Baz;
2225 };
2226
2227 void target() {
2228 A Foo = { 1 };
2229 A Bar = { 2 };
2230 // [[p1]]
2231 Foo = Bar;
2232 // [[p2]]
2233 Foo.Baz = 3;
2234 // [[p3]]
2235 }
2236 )";
2237 runDataflow(
2238 Code,
2239 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2240 ASTContext &ASTCtx) {
2241 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
2242 ASSERT_THAT(FooDecl, NotNull());
2243
2244 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
2245 ASSERT_THAT(BarDecl, NotNull());
2246
2247 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
2248 ASSERT_THAT(BazDecl, NotNull());
2249
2250 // Before copy assignment.
2251 {
2252 const Environment &Env1 = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p1");
2253
2254 const auto *FooLoc1 =
2255 cast<RecordStorageLocation>(Val: Env1.getStorageLocation(D: *FooDecl));
2256 const auto *BarLoc1 =
2257 cast<RecordStorageLocation>(Val: Env1.getStorageLocation(D: *BarDecl));
2258 EXPECT_FALSE(recordsEqual(*FooLoc1, *BarLoc1, Env1));
2259
2260 const auto *FooBazVal1 =
2261 cast<IntegerValue>(Val: getFieldValue(Loc: FooLoc1, Field: *BazDecl, Env: Env1));
2262 const auto *BarBazVal1 =
2263 cast<IntegerValue>(Val: getFieldValue(Loc: BarLoc1, Field: *BazDecl, Env: Env1));
2264 EXPECT_NE(FooBazVal1, BarBazVal1);
2265 }
2266
2267 // After copy assignment.
2268 {
2269 const Environment &Env2 = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p2");
2270
2271 const auto *FooLoc2 =
2272 cast<RecordStorageLocation>(Val: Env2.getStorageLocation(D: *FooDecl));
2273 const auto *BarLoc2 =
2274 cast<RecordStorageLocation>(Val: Env2.getStorageLocation(D: *BarDecl));
2275
2276 EXPECT_TRUE(recordsEqual(*FooLoc2, *BarLoc2, Env2));
2277
2278 const auto *FooBazVal2 =
2279 cast<IntegerValue>(Val: getFieldValue(Loc: FooLoc2, Field: *BazDecl, Env: Env2));
2280 const auto *BarBazVal2 =
2281 cast<IntegerValue>(Val: getFieldValue(Loc: BarLoc2, Field: *BazDecl, Env: Env2));
2282 EXPECT_EQ(FooBazVal2, BarBazVal2);
2283 }
2284
2285 // After value update.
2286 {
2287 const Environment &Env3 = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p3");
2288
2289 const auto *FooLoc3 =
2290 cast<RecordStorageLocation>(Val: Env3.getStorageLocation(D: *FooDecl));
2291 const auto *BarLoc3 =
2292 cast<RecordStorageLocation>(Val: Env3.getStorageLocation(D: *BarDecl));
2293 EXPECT_FALSE(recordsEqual(*FooLoc3, *BarLoc3, Env3));
2294
2295 const auto *FooBazVal3 =
2296 cast<IntegerValue>(Val: getFieldValue(Loc: FooLoc3, Field: *BazDecl, Env: Env3));
2297 const auto *BarBazVal3 =
2298 cast<IntegerValue>(Val: getFieldValue(Loc: BarLoc3, Field: *BazDecl, Env: Env3));
2299 EXPECT_NE(FooBazVal3, BarBazVal3);
2300 }
2301 });
2302}
2303
2304// It's legal for the assignment operator to take its source parameter by value.
2305// Check that we handle this correctly. (This is a repro -- we used to
2306// assert-fail on this.)
2307TEST(TransferTest, AssignmentOperator_ArgByValue) {
2308 std::string Code = R"(
2309 struct A {
2310 int Baz;
2311 A &operator=(A);
2312 };
2313
2314 void target() {
2315 A Foo = { 1 };
2316 A Bar = { 2 };
2317 Foo = Bar;
2318 // [[p]]
2319 }
2320 )";
2321 runDataflow(
2322 Code,
2323 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2324 ASTContext &ASTCtx) {
2325 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
2326 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
2327
2328 const auto &FooLoc =
2329 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, Name: "Foo");
2330 const auto &BarLoc =
2331 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, Name: "Bar");
2332
2333 const auto *FooBazVal =
2334 cast<IntegerValue>(Val: getFieldValue(Loc: &FooLoc, Field: *BazDecl, Env));
2335 const auto *BarBazVal =
2336 cast<IntegerValue>(Val: getFieldValue(Loc: &BarLoc, Field: *BazDecl, Env));
2337 EXPECT_EQ(FooBazVal, BarBazVal);
2338 });
2339}
2340
2341TEST(TransferTest, AssignmentOperatorFromBase) {
2342 std::string Code = R"(
2343 struct Base {
2344 int base;
2345 };
2346 struct Derived : public Base {
2347 using Base::operator=;
2348 int derived;
2349 };
2350 void target(Base B, Derived D) {
2351 D.base = 1;
2352 D.derived = 1;
2353 // [[before]]
2354 D = B;
2355 // [[after]]
2356 }
2357 )";
2358 runDataflow(
2359 Code,
2360 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2361 ASTContext &ASTCtx) {
2362 const Environment &EnvBefore =
2363 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "before");
2364 const Environment &EnvAfter =
2365 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "after");
2366
2367 auto &BLoc =
2368 getLocForDecl<RecordStorageLocation>(ASTCtx, Env: EnvBefore, Name: "B");
2369 auto &DLoc =
2370 getLocForDecl<RecordStorageLocation>(ASTCtx, Env: EnvBefore, Name: "D");
2371
2372 EXPECT_NE(getFieldValue(&BLoc, "base", ASTCtx, EnvBefore),
2373 getFieldValue(&DLoc, "base", ASTCtx, EnvBefore));
2374 EXPECT_EQ(getFieldValue(&BLoc, "base", ASTCtx, EnvAfter),
2375 getFieldValue(&DLoc, "base", ASTCtx, EnvAfter));
2376
2377 EXPECT_EQ(getFieldValue(&DLoc, "derived", ASTCtx, EnvBefore),
2378 getFieldValue(&DLoc, "derived", ASTCtx, EnvAfter));
2379 });
2380}
2381
2382TEST(TransferTest, AssignmentOperatorFromCallResult) {
2383 std::string Code = R"(
2384 struct A {};
2385 A ReturnA();
2386
2387 void target() {
2388 A MyA;
2389 MyA = ReturnA();
2390 }
2391 )";
2392 runDataflow(
2393 Code,
2394 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2395 ASTContext &ASTCtx) {
2396 // As of this writing, we don't produce a `Value` for the call
2397 // `ReturnA()`. The only condition we're testing for is that the
2398 // analysis should not crash in this case.
2399 });
2400}
2401
2402TEST(TransferTest, AssignmentOperatorWithInitAndInheritance) {
2403 // This is a crash repro.
2404 std::string Code = R"(
2405 struct B { int Foo; };
2406 struct S : public B {};
2407 void target() {
2408 S S1 = { 1 };
2409 S S2;
2410 S S3;
2411 S1 = S2; // Only Dst has InitListExpr.
2412 S3 = S1; // Only Src has InitListExpr.
2413 // [[p]]
2414 }
2415 )";
2416 runDataflow(
2417 Code,
2418 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2419 ASTContext &ASTCtx) {});
2420}
2421
2422TEST(TransferTest, AssignmentOperatorReturnsVoid) {
2423 // This is a crash repro.
2424 std::string Code = R"(
2425 struct S {
2426 void operator=(S&& other);
2427 };
2428 void target() {
2429 S s;
2430 s = S();
2431 // [[p]]
2432 }
2433 )";
2434 runDataflow(
2435 Code,
2436 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2437 ASTContext &ASTCtx) {});
2438}
2439
2440TEST(TransferTest, AssignmentOperatorReturnsByValue) {
2441 // This is a crash repro.
2442 std::string Code = R"(
2443 struct S {
2444 S operator=(S&& other);
2445 };
2446 void target() {
2447 S s;
2448 s = S();
2449 // [[p]]
2450 }
2451 )";
2452 runDataflow(
2453 Code,
2454 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2455 ASTContext &ASTCtx) {});
2456}
2457
2458TEST(TransferTest, InitListExprAsXValue) {
2459 // This is a crash repro.
2460 std::string Code = R"(
2461 void target() {
2462 bool&& Foo{false};
2463 // [[p]]
2464 }
2465 )";
2466 runDataflow(
2467 Code,
2468 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2469 ASTContext &ASTCtx) {
2470 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
2471 const auto &FooVal = getValueForDecl<BoolValue>(ASTCtx, Env, Name: "Foo");
2472 ASSERT_TRUE(FooVal.formula().isLiteral(false));
2473 });
2474}
2475
2476TEST(TransferTest, ArrayInitListExprOneRecordElement) {
2477 // This is a crash repro.
2478 std::string Code = R"cc(
2479 struct S {};
2480
2481 void target() { S foo[] = {S()}; }
2482 )cc";
2483 runDataflow(
2484 Code,
2485 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2486 ASTContext &ASTCtx) {
2487 // Just verify that it doesn't crash.
2488 });
2489}
2490
2491TEST(TransferTest, InitListExprAsUnion) {
2492 // This is a crash repro.
2493 std::string Code = R"cc(
2494 class target {
2495 union {
2496 int *a;
2497 bool *b;
2498 } F;
2499
2500 public:
2501 constexpr target() : F{nullptr} {
2502 int *null = nullptr;
2503 F.b; // Make sure we reference 'b' so it is modeled.
2504 // [[p]]
2505 }
2506 };
2507 )cc";
2508 runDataflow(
2509 Code,
2510 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2511 ASTContext &ASTCtx) {
2512 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
2513
2514 auto &FLoc = getFieldLoc<RecordStorageLocation>(
2515 Loc: *Env.getThisPointeeStorageLocation(), Name: "F", ASTCtx);
2516 auto *AVal = cast<PointerValue>(Val: getFieldValue(Loc: &FLoc, Name: "a", ASTCtx, Env));
2517 EXPECT_EQ(AVal, &getValueForDecl<PointerValue>(ASTCtx, Env, "null"));
2518 EXPECT_EQ(getFieldValue(&FLoc, "b", ASTCtx, Env), nullptr);
2519 });
2520}
2521
2522TEST(TransferTest, EmptyInitListExprForUnion) {
2523 // This is a crash repro.
2524 std::string Code = R"cc(
2525 class target {
2526 union {
2527 int *a;
2528 bool *b;
2529 } F;
2530
2531 public:
2532 // Empty initializer list means that `F` is aggregate-initialized.
2533 // For a union, this has the effect that the first member of the union
2534 // is copy-initialized from an empty initializer list; in this specific
2535 // case, this has the effect of initializing `a` with null.
2536 constexpr target() : F{} {
2537 int *null = nullptr;
2538 F.b; // Make sure we reference 'b' so it is modeled.
2539 // [[p]]
2540 }
2541 };
2542 )cc";
2543 runDataflow(
2544 Code,
2545 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2546 ASTContext &ASTCtx) {
2547 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
2548
2549 auto &FLoc = getFieldLoc<RecordStorageLocation>(
2550 Loc: *Env.getThisPointeeStorageLocation(), Name: "F", ASTCtx);
2551 auto *AVal = cast<PointerValue>(Val: getFieldValue(Loc: &FLoc, Name: "a", ASTCtx, Env));
2552 EXPECT_EQ(AVal, &getValueForDecl<PointerValue>(ASTCtx, Env, "null"));
2553 EXPECT_EQ(getFieldValue(&FLoc, "b", ASTCtx, Env), nullptr);
2554 });
2555}
2556
2557TEST(TransferTest, EmptyInitListExprForStruct) {
2558 std::string Code = R"cc(
2559 class target {
2560 struct {
2561 int *a;
2562 bool *b;
2563 } F;
2564
2565 public:
2566 constexpr target() : F{} {
2567 int *NullIntPtr = nullptr;
2568 bool *NullBoolPtr = nullptr;
2569 // [[p]]
2570 }
2571 };
2572 )cc";
2573 runDataflow(
2574 Code,
2575 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2576 ASTContext &ASTCtx) {
2577 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
2578
2579 auto &FLoc = getFieldLoc<RecordStorageLocation>(
2580 Loc: *Env.getThisPointeeStorageLocation(), Name: "F", ASTCtx);
2581 auto *AVal = cast<PointerValue>(Val: getFieldValue(Loc: &FLoc, Name: "a", ASTCtx, Env));
2582 EXPECT_EQ(AVal,
2583 &getValueForDecl<PointerValue>(ASTCtx, Env, "NullIntPtr"));
2584 auto *BVal = cast<PointerValue>(Val: getFieldValue(Loc: &FLoc, Name: "b", ASTCtx, Env));
2585 EXPECT_EQ(BVal,
2586 &getValueForDecl<PointerValue>(ASTCtx, Env, "NullBoolPtr"));
2587 });
2588}
2589
2590TEST(TransferTest, CopyConstructor) {
2591 std::string Code = R"(
2592 struct A {
2593 int Baz;
2594 };
2595
2596 void target() {
2597 A Foo = { 1 };
2598 A Bar = Foo;
2599 // [[after_copy]]
2600 Foo.Baz = 2;
2601 // [[after_update]]
2602 }
2603 )";
2604 runDataflow(
2605 Code,
2606 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2607 ASTContext &ASTCtx) {
2608 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
2609 ASSERT_THAT(FooDecl, NotNull());
2610
2611 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
2612 ASSERT_THAT(BarDecl, NotNull());
2613
2614 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
2615 ASSERT_THAT(BazDecl, NotNull());
2616
2617 // after_copy
2618 {
2619 const Environment &Env =
2620 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "after_copy");
2621
2622 const auto *FooLoc =
2623 cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
2624 const auto *BarLoc =
2625 cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *BarDecl));
2626
2627 // The records compare equal.
2628 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env));
2629
2630 // In particular, the value of `Baz` in both records is the same.
2631 const auto *FooBazVal =
2632 cast<IntegerValue>(Val: getFieldValue(Loc: FooLoc, Field: *BazDecl, Env));
2633 const auto *BarBazVal =
2634 cast<IntegerValue>(Val: getFieldValue(Loc: BarLoc, Field: *BazDecl, Env));
2635 EXPECT_EQ(FooBazVal, BarBazVal);
2636 }
2637
2638 // after_update
2639 {
2640 const Environment &Env =
2641 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "after_update");
2642
2643 const auto *FooLoc =
2644 cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
2645 const auto *BarLoc =
2646 cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *BarDecl));
2647
2648 EXPECT_FALSE(recordsEqual(*FooLoc, *BarLoc, Env));
2649
2650 const auto *FooBazVal =
2651 cast<IntegerValue>(Val: getFieldValue(Loc: FooLoc, Field: *BazDecl, Env));
2652 const auto *BarBazVal =
2653 cast<IntegerValue>(Val: getFieldValue(Loc: BarLoc, Field: *BazDecl, Env));
2654 EXPECT_NE(FooBazVal, BarBazVal);
2655 }
2656 });
2657}
2658
2659TEST(TransferTest, CopyConstructorWithDefaultArgument) {
2660 std::string Code = R"(
2661 struct A {
2662 int Baz;
2663 A() = default;
2664 A(const A& a, bool def = true) { Baz = a.Baz; }
2665 };
2666
2667 void target() {
2668 A Foo;
2669 (void)Foo.Baz;
2670 A Bar = Foo;
2671 // [[p]]
2672 }
2673 )";
2674 runDataflow(
2675 Code,
2676 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2677 ASTContext &ASTCtx) {
2678 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2679 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
2680
2681 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
2682 ASSERT_THAT(FooDecl, NotNull());
2683
2684 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
2685 ASSERT_THAT(BarDecl, NotNull());
2686
2687 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
2688 ASSERT_THAT(BazDecl, NotNull());
2689
2690 const auto *FooLoc =
2691 cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
2692 const auto *BarLoc =
2693 cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *BarDecl));
2694 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env));
2695
2696 const auto *FooBazVal =
2697 cast<IntegerValue>(Val: getFieldValue(Loc: FooLoc, Field: *BazDecl, Env));
2698 const auto *BarBazVal =
2699 cast<IntegerValue>(Val: getFieldValue(Loc: BarLoc, Field: *BazDecl, Env));
2700 EXPECT_EQ(FooBazVal, BarBazVal);
2701 });
2702}
2703
2704TEST(TransferTest, CopyConstructorWithParens) {
2705 std::string Code = R"(
2706 struct A {
2707 int Baz;
2708 };
2709
2710 void target() {
2711 A Foo;
2712 (void)Foo.Baz;
2713 A Bar((A(Foo)));
2714 // [[p]]
2715 }
2716 )";
2717 runDataflow(
2718 Code,
2719 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2720 ASTContext &ASTCtx) {
2721 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2722 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
2723
2724 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
2725 ASSERT_THAT(FooDecl, NotNull());
2726
2727 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
2728 ASSERT_THAT(BarDecl, NotNull());
2729
2730 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
2731 ASSERT_THAT(BazDecl, NotNull());
2732
2733 const auto *FooLoc =
2734 cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
2735 const auto *BarLoc =
2736 cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *BarDecl));
2737 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env));
2738
2739 const auto *FooBazVal =
2740 cast<IntegerValue>(Val: getFieldValue(Loc: FooLoc, Field: *BazDecl, Env));
2741 const auto *BarBazVal =
2742 cast<IntegerValue>(Val: getFieldValue(Loc: BarLoc, Field: *BazDecl, Env));
2743 EXPECT_EQ(FooBazVal, BarBazVal);
2744 });
2745}
2746
2747TEST(TransferTest, CopyConstructorWithInitializerListAsSyntacticSugar) {
2748 std::string Code = R"(
2749 struct A {
2750 int Baz;
2751 };
2752 void target() {
2753 A Foo = {3};
2754 (void)Foo.Baz;
2755 A Bar = {A(Foo)};
2756 // [[p]]
2757 }
2758 )";
2759 runDataflow(
2760 Code,
2761 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2762 ASTContext &ASTCtx) {
2763 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
2764
2765 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
2766
2767 const auto &FooLoc =
2768 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, Name: "Foo");
2769 const auto &BarLoc =
2770 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, Name: "Bar");
2771
2772 const auto *FooBazVal =
2773 cast<IntegerValue>(Val: getFieldValue(Loc: &FooLoc, Field: *BazDecl, Env));
2774 const auto *BarBazVal =
2775 cast<IntegerValue>(Val: getFieldValue(Loc: &BarLoc, Field: *BazDecl, Env));
2776 EXPECT_EQ(FooBazVal, BarBazVal);
2777 });
2778}
2779
2780TEST(TransferTest, CopyConstructorArgIsRefReturnedByFunction) {
2781 // This is a crash repro.
2782 std::string Code = R"(
2783 struct S {};
2784 const S &returnsSRef();
2785 void target() {
2786 S s(returnsSRef());
2787 }
2788 )";
2789 runDataflow(
2790 Code,
2791 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2792 ASTContext &ASTCtx) {});
2793}
2794
2795TEST(TransferTest, MoveConstructor) {
2796 std::string Code = R"(
2797 namespace std {
2798
2799 template <typename T> struct remove_reference { using type = T; };
2800 template <typename T> struct remove_reference<T&> { using type = T; };
2801 template <typename T> struct remove_reference<T&&> { using type = T; };
2802
2803 template <typename T>
2804 using remove_reference_t = typename remove_reference<T>::type;
2805
2806 template <typename T>
2807 std::remove_reference_t<T>&& move(T&& x);
2808
2809 } // namespace std
2810
2811 struct A {
2812 int Baz;
2813 };
2814
2815 void target() {
2816 A Foo;
2817 A Bar;
2818 (void)Foo.Baz;
2819 // [[p1]]
2820 Foo = std::move(Bar);
2821 // [[p2]]
2822 }
2823 )";
2824 runDataflow(
2825 Code,
2826 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2827 ASTContext &ASTCtx) {
2828 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
2829 const Environment &Env1 = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p1");
2830 const Environment &Env2 = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p2");
2831
2832 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
2833 ASSERT_THAT(FooDecl, NotNull());
2834
2835 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
2836 ASSERT_THAT(BarDecl, NotNull());
2837
2838 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
2839 ASSERT_THAT(BazDecl, NotNull());
2840
2841 const auto *FooLoc1 =
2842 cast<RecordStorageLocation>(Val: Env1.getStorageLocation(D: *FooDecl));
2843 const auto *BarLoc1 =
2844 cast<RecordStorageLocation>(Val: Env1.getStorageLocation(D: *BarDecl));
2845
2846 EXPECT_FALSE(recordsEqual(*FooLoc1, *BarLoc1, Env1));
2847
2848 const auto *FooBazVal1 =
2849 cast<IntegerValue>(Val: getFieldValue(Loc: FooLoc1, Field: *BazDecl, Env: Env1));
2850 const auto *BarBazVal1 =
2851 cast<IntegerValue>(Val: getFieldValue(Loc: BarLoc1, Field: *BazDecl, Env: Env1));
2852 EXPECT_NE(FooBazVal1, BarBazVal1);
2853
2854 const auto *FooLoc2 =
2855 cast<RecordStorageLocation>(Val: Env2.getStorageLocation(D: *FooDecl));
2856 EXPECT_TRUE(recordsEqual(*FooLoc2, Env2, *BarLoc1, Env1));
2857
2858 const auto *FooBazVal2 =
2859 cast<IntegerValue>(Val: getFieldValue(Loc: FooLoc1, Field: *BazDecl, Env: Env2));
2860 EXPECT_EQ(FooBazVal2, BarBazVal1);
2861 });
2862}
2863
2864TEST(TransferTest, BindTemporary) {
2865 std::string Code = R"(
2866 struct A {
2867 virtual ~A() = default;
2868
2869 int Baz;
2870 };
2871
2872 void target(A Foo) {
2873 int Bar = A(Foo).Baz;
2874 // [[p]]
2875 }
2876 )";
2877 runDataflow(
2878 Code,
2879 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2880 ASTContext &ASTCtx) {
2881 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2882 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
2883
2884 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
2885 ASSERT_THAT(FooDecl, NotNull());
2886
2887 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
2888 ASSERT_THAT(BarDecl, NotNull());
2889
2890 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
2891 ASSERT_THAT(BazDecl, NotNull());
2892
2893 const auto &FooLoc =
2894 *cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
2895 const auto *BarVal = cast<IntegerValue>(Val: Env.getValue(D: *BarDecl));
2896 EXPECT_EQ(BarVal, getFieldValue(&FooLoc, *BazDecl, Env));
2897 });
2898}
2899
2900TEST(TransferTest, ResultObjectLocation) {
2901 std::string Code = R"(
2902 struct A {
2903 virtual ~A() = default;
2904 };
2905
2906 void target() {
2907 0, A();
2908 (void)0; // [[p]]
2909 }
2910 )";
2911 using ast_matchers::binaryOperator;
2912 using ast_matchers::cxxBindTemporaryExpr;
2913 using ast_matchers::cxxTemporaryObjectExpr;
2914 using ast_matchers::exprWithCleanups;
2915 using ast_matchers::has;
2916 using ast_matchers::hasOperatorName;
2917 using ast_matchers::hasRHS;
2918 using ast_matchers::match;
2919 using ast_matchers::selectFirst;
2920 using ast_matchers::traverse;
2921 runDataflow(
2922 Code,
2923 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2924 ASTContext &ASTCtx) {
2925 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
2926
2927 // The expression `0, A()` in the code above produces the following
2928 // structure, consisting of four prvalues of record type.
2929 // `Env.getResultObjectLocation()` should return the same location for
2930 // all of these.
2931 auto MatchResult = match(
2932 Matcher: traverse(TK: TK_AsIs,
2933 InnerMatcher: exprWithCleanups(
2934 has(binaryOperator(
2935 hasOperatorName(Name: ","),
2936 hasRHS(InnerMatcher: cxxBindTemporaryExpr(
2937 has(cxxTemporaryObjectExpr().bind(
2938 ID: "toe")))
2939 .bind(ID: "bte")))
2940 .bind(ID: "comma")))
2941 .bind(ID: "ewc")),
2942 Context&: ASTCtx);
2943 auto *TOE = selectFirst<CXXTemporaryObjectExpr>(BoundTo: "toe", Results: MatchResult);
2944 ASSERT_NE(TOE, nullptr);
2945 auto *Comma = selectFirst<BinaryOperator>(BoundTo: "comma", Results: MatchResult);
2946 ASSERT_NE(Comma, nullptr);
2947 auto *EWC = selectFirst<ExprWithCleanups>(BoundTo: "ewc", Results: MatchResult);
2948 ASSERT_NE(EWC, nullptr);
2949 auto *BTE = selectFirst<CXXBindTemporaryExpr>(BoundTo: "bte", Results: MatchResult);
2950 ASSERT_NE(BTE, nullptr);
2951
2952 RecordStorageLocation &Loc = Env.getResultObjectLocation(*TOE);
2953 EXPECT_EQ(&Loc, &Env.getResultObjectLocation(*Comma));
2954 EXPECT_EQ(&Loc, &Env.getResultObjectLocation(*EWC));
2955 EXPECT_EQ(&Loc, &Env.getResultObjectLocation(*BTE));
2956 });
2957}
2958
2959TEST(TransferTest, ResultObjectLocationForDefaultArgExpr) {
2960 std::string Code = R"(
2961 struct Inner {};
2962 struct Outer {
2963 Inner I = {};
2964 };
2965
2966 void funcWithDefaultArg(Outer O = {});
2967 void target() {
2968 funcWithDefaultArg();
2969 // [[p]]
2970 }
2971 )";
2972
2973 using ast_matchers::cxxDefaultArgExpr;
2974 using ast_matchers::match;
2975 using ast_matchers::selectFirst;
2976 runDataflow(
2977 Code,
2978 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2979 ASTContext &ASTCtx) {
2980 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
2981
2982 auto *DefaultArg = selectFirst<CXXDefaultArgExpr>(
2983 BoundTo: "default_arg",
2984 Results: match(Matcher: cxxDefaultArgExpr().bind(ID: "default_arg"), Context&: ASTCtx));
2985 ASSERT_NE(DefaultArg, nullptr);
2986
2987 // The values for default arguments aren't modeled; we merely verify
2988 // that we can get a result object location for a default arg.
2989 Env.getResultObjectLocation(*DefaultArg);
2990 });
2991}
2992
2993TEST(TransferTest, ResultObjectLocationForDefaultInitExpr) {
2994 std::string Code = R"(
2995 struct S {};
2996 struct target {
2997 target () {
2998 (void)0;
2999 // [[p]]
3000 }
3001 S s = {};
3002 };
3003 )";
3004
3005 using ast_matchers::cxxCtorInitializer;
3006 using ast_matchers::match;
3007 using ast_matchers::selectFirst;
3008 runDataflow(
3009 Code,
3010 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3011 ASTContext &ASTCtx) {
3012 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3013
3014 const ValueDecl *SField = findValueDecl(ASTCtx, Name: "s");
3015
3016 auto *CtorInit = selectFirst<CXXCtorInitializer>(
3017 BoundTo: "ctor_initializer",
3018 Results: match(Matcher: cxxCtorInitializer().bind(ID: "ctor_initializer"), Context&: ASTCtx));
3019 ASSERT_NE(CtorInit, nullptr);
3020
3021 auto *DefaultInit = cast<CXXDefaultInitExpr>(Val: CtorInit->getInit());
3022
3023 RecordStorageLocation &Loc = Env.getResultObjectLocation(*DefaultInit);
3024
3025 EXPECT_EQ(&Loc, Env.getThisPointeeStorageLocation()->getChild(*SField));
3026 });
3027}
3028
3029// This test ensures that CXXOperatorCallExpr returning prvalues are correctly
3030// handled by the transfer functions, especially that `getResultObjectLocation`
3031// correctly returns a storage location for those.
3032TEST(TransferTest, ResultObjectLocationForCXXOperatorCallExpr) {
3033 std::string Code = R"(
3034 struct A {
3035 A operator+(int);
3036 };
3037
3038 void target() {
3039 A a;
3040 a + 3;
3041 (void)0; // [[p]]
3042 }
3043 )";
3044 using ast_matchers::cxxOperatorCallExpr;
3045 using ast_matchers::match;
3046 using ast_matchers::selectFirst;
3047 using ast_matchers::traverse;
3048 runDataflow(
3049 Code,
3050 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3051 ASTContext &ASTCtx) {
3052 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3053
3054 auto *CallExpr = selectFirst<CXXOperatorCallExpr>(
3055 BoundTo: "call_expr",
3056 Results: match(Matcher: cxxOperatorCallExpr().bind(ID: "call_expr"), Context&: ASTCtx));
3057
3058 EXPECT_NE(&Env.getResultObjectLocation(*CallExpr), nullptr);
3059 });
3060}
3061
3062TEST(TransferTest, ResultObjectLocationForInitListExpr) {
3063 std::string Code = R"cc(
3064 struct Inner {};
3065
3066 struct Outer { Inner I; };
3067
3068 void target() {
3069 Outer O = { Inner() };
3070 // [[p]]
3071 }
3072 )cc";
3073 using ast_matchers::asString;
3074 using ast_matchers::cxxConstructExpr;
3075 using ast_matchers::hasType;
3076 using ast_matchers::match;
3077 using ast_matchers::selectFirst;
3078 using ast_matchers::traverse;
3079 runDataflow(
3080 Code,
3081 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3082 ASTContext &ASTCtx) {
3083 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3084
3085 auto *Construct = selectFirst<CXXConstructExpr>(
3086 BoundTo: "construct",
3087 Results: match(
3088 Matcher: cxxConstructExpr(hasType(InnerMatcher: asString(Name: "Inner"))).bind(ID: "construct"),
3089 Context&: ASTCtx));
3090
3091 EXPECT_EQ(
3092 &Env.getResultObjectLocation(*Construct),
3093 &getFieldLoc(getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "O"),
3094 "I", ASTCtx));
3095 });
3096}
3097
3098TEST(TransferTest, ResultObjectLocationForParenInitListExpr) {
3099 std::string Code = R"cc(
3100 struct Inner {};
3101
3102 struct Outer { Inner I; };
3103
3104 void target() {
3105 Outer O((Inner()));
3106 // [[p]]
3107 }
3108 )cc";
3109 using ast_matchers::asString;
3110 using ast_matchers::cxxConstructExpr;
3111 using ast_matchers::hasType;
3112 using ast_matchers::match;
3113 using ast_matchers::selectFirst;
3114 using ast_matchers::traverse;
3115 runDataflow(
3116 Code,
3117 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3118 ASTContext &ASTCtx) {
3119 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3120
3121 auto *Construct = selectFirst<CXXConstructExpr>(
3122 BoundTo: "construct",
3123 Results: match(
3124 Matcher: cxxConstructExpr(hasType(InnerMatcher: asString(Name: "Inner"))).bind(ID: "construct"),
3125 Context&: ASTCtx));
3126
3127 EXPECT_EQ(
3128 &Env.getResultObjectLocation(*Construct),
3129 &getFieldLoc(getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "O"),
3130 "I", ASTCtx));
3131 },
3132 Std: LangStandard::lang_cxx20);
3133}
3134
3135// Check that the `std::strong_ordering` object returned by builtin `<=>` has a
3136// correctly modeled result object location.
3137TEST(TransferTest, ResultObjectLocationForBuiltinSpaceshipOperator) {
3138 std::string Code = R"(
3139 namespace std {
3140 // This is the minimal definition required to get
3141 // `Sema::CheckComparisonCategoryType()` to accept this fake.
3142 struct strong_ordering {
3143 enum class ordering { less, equal, greater };
3144 ordering o;
3145 static const strong_ordering less;
3146 static const strong_ordering equivalent;
3147 static const strong_ordering equal;
3148 static const strong_ordering greater;
3149 };
3150
3151 inline constexpr strong_ordering strong_ordering::less =
3152 { strong_ordering::ordering::less };
3153 inline constexpr strong_ordering strong_ordering::equal =
3154 { strong_ordering::ordering::equal };
3155 inline constexpr strong_ordering strong_ordering::equivalent =
3156 { strong_ordering::ordering::equal };
3157 inline constexpr strong_ordering strong_ordering::greater =
3158 { strong_ordering::ordering::greater };
3159 }
3160 void target(int i, int j) {
3161 auto ordering = i <=> j;
3162 // [[p]]
3163 }
3164 )";
3165 using ast_matchers::binaryOperator;
3166 using ast_matchers::hasOperatorName;
3167 using ast_matchers::match;
3168 using ast_matchers::selectFirst;
3169 using ast_matchers::traverse;
3170 runDataflow(
3171 Code,
3172 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3173 ASTContext &ASTCtx) {
3174 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3175
3176 auto *Spaceship = selectFirst<BinaryOperator>(
3177 BoundTo: "op",
3178 Results: match(Matcher: binaryOperator(hasOperatorName(Name: "<=>")).bind(ID: "op"), Context&: ASTCtx));
3179
3180 EXPECT_EQ(
3181 &Env.getResultObjectLocation(*Spaceship),
3182 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "ordering"));
3183 },
3184 Std: LangStandard::lang_cxx20);
3185}
3186
3187TEST(TransferTest, ResultObjectLocationForStdInitializerListExpr) {
3188 std::string Code = R"(
3189 namespace std {
3190 template <typename T>
3191 struct initializer_list {};
3192 } // namespace std
3193
3194 void target() {
3195 std::initializer_list<int> list = {1};
3196 // [[p]]
3197 }
3198 )";
3199
3200 using ast_matchers::cxxStdInitializerListExpr;
3201 using ast_matchers::match;
3202 using ast_matchers::selectFirst;
3203 runDataflow(
3204 Code,
3205 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3206 ASTContext &ASTCtx) {
3207 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3208
3209 auto *StdInitList = selectFirst<CXXStdInitializerListExpr>(
3210 BoundTo: "std_init_list",
3211 Results: match(Matcher: cxxStdInitializerListExpr().bind(ID: "std_init_list"), Context&: ASTCtx));
3212 ASSERT_NE(StdInitList, nullptr);
3213
3214 EXPECT_EQ(&Env.getResultObjectLocation(*StdInitList),
3215 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "list"));
3216 });
3217}
3218
3219TEST(TransferTest, ResultObjectLocationForStmtExpr) {
3220 std::string Code = R"(
3221 struct S {};
3222 void target() {
3223 S s = ({ S(); });
3224 // [[p]]
3225 }
3226 )";
3227 using ast_matchers::cxxConstructExpr;
3228 using ast_matchers::match;
3229 using ast_matchers::selectFirst;
3230 using ast_matchers::traverse;
3231 runDataflow(
3232 Code,
3233 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3234 ASTContext &ASTCtx) {
3235 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3236
3237 auto *Construct = selectFirst<CXXConstructExpr>(
3238 BoundTo: "construct", Results: match(Matcher: cxxConstructExpr().bind(ID: "construct"), Context&: ASTCtx));
3239
3240 EXPECT_EQ(&Env.getResultObjectLocation(*Construct),
3241 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"));
3242 });
3243}
3244
3245TEST(TransferTest, ResultObjectLocationForBuiltinBitCastExpr) {
3246 std::string Code = R"(
3247 struct S { int i; };
3248 void target(int i) {
3249 S s = __builtin_bit_cast(S, i);
3250 // [[p]]
3251 }
3252 )";
3253 using ast_matchers::explicitCastExpr;
3254 using ast_matchers::match;
3255 using ast_matchers::selectFirst;
3256 using ast_matchers::traverse;
3257 runDataflow(
3258 Code,
3259 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3260 ASTContext &ASTCtx) {
3261 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3262
3263 auto *BuiltinBitCast = selectFirst<BuiltinBitCastExpr>(
3264 BoundTo: "cast", Results: match(Matcher: explicitCastExpr().bind(ID: "cast"), Context&: ASTCtx));
3265
3266 EXPECT_EQ(&Env.getResultObjectLocation(*BuiltinBitCast),
3267 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"));
3268 });
3269}
3270
3271TEST(TransferTest, ResultObjectLocationPropagatesThroughConditionalOperator) {
3272 std::string Code = R"(
3273 struct A {
3274 A(int);
3275 };
3276
3277 void target(bool b) {
3278 A a = b ? A(0) : A(1);
3279 (void)0; // [[p]]
3280 }
3281 )";
3282 using ast_matchers::cxxConstructExpr;
3283 using ast_matchers::equals;
3284 using ast_matchers::hasArgument;
3285 using ast_matchers::integerLiteral;
3286 using ast_matchers::match;
3287 using ast_matchers::selectFirst;
3288 using ast_matchers::traverse;
3289 runDataflow(
3290 Code,
3291 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3292 ASTContext &ASTCtx) {
3293 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3294
3295 auto *ConstructExpr0 = selectFirst<CXXConstructExpr>(
3296 BoundTo: "construct",
3297 Results: match(Matcher: cxxConstructExpr(hasArgument(N: 0, InnerMatcher: integerLiteral(equals(Value: 0))))
3298 .bind(ID: "construct"),
3299 Context&: ASTCtx));
3300 auto *ConstructExpr1 = selectFirst<CXXConstructExpr>(
3301 BoundTo: "construct",
3302 Results: match(Matcher: cxxConstructExpr(hasArgument(N: 0, InnerMatcher: integerLiteral(equals(Value: 1))))
3303 .bind(ID: "construct"),
3304 Context&: ASTCtx));
3305
3306 auto &ALoc = getLocForDecl<StorageLocation>(ASTCtx, Env, Name: "a");
3307 EXPECT_EQ(&Env.getResultObjectLocation(*ConstructExpr0), &ALoc);
3308 EXPECT_EQ(&Env.getResultObjectLocation(*ConstructExpr1), &ALoc);
3309 });
3310}
3311
3312TEST(TransferTest, StaticCast) {
3313 std::string Code = R"(
3314 void target(int Foo) {
3315 int Bar = static_cast<int>(Foo);
3316 // [[p]]
3317 }
3318 )";
3319 runDataflow(
3320 Code,
3321 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3322 ASTContext &ASTCtx) {
3323 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3324 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3325
3326 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
3327 ASSERT_THAT(FooDecl, NotNull());
3328
3329 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
3330 ASSERT_THAT(BarDecl, NotNull());
3331
3332 const auto *FooVal = Env.getValue(D: *FooDecl);
3333 const auto *BarVal = Env.getValue(D: *BarDecl);
3334 EXPECT_TRUE(isa<IntegerValue>(FooVal));
3335 EXPECT_TRUE(isa<IntegerValue>(BarVal));
3336 EXPECT_EQ(FooVal, BarVal);
3337 });
3338}
3339
3340TEST(TransferTest, IntegralCast) {
3341 std::string Code = R"(
3342 void target(int Foo) {
3343 long Bar = Foo;
3344 // [[p]]
3345 }
3346 )";
3347 runDataflow(
3348 Code,
3349 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3350 ASTContext &ASTCtx) {
3351 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3352 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3353
3354 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
3355 ASSERT_THAT(FooDecl, NotNull());
3356
3357 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
3358 ASSERT_THAT(BarDecl, NotNull());
3359
3360 const auto *FooVal = Env.getValue(D: *FooDecl);
3361 const auto *BarVal = Env.getValue(D: *BarDecl);
3362 EXPECT_TRUE(isa<IntegerValue>(FooVal));
3363 EXPECT_TRUE(isa<IntegerValue>(BarVal));
3364 EXPECT_EQ(FooVal, BarVal);
3365 });
3366}
3367
3368TEST(TransferTest, IntegraltoBooleanCast) {
3369 std::string Code = R"(
3370 void target(int Foo) {
3371 bool Bar = Foo;
3372 // [[p]]
3373 }
3374 )";
3375 runDataflow(
3376 Code,
3377 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3378 ASTContext &ASTCtx) {
3379 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3380 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3381
3382 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
3383 ASSERT_THAT(FooDecl, NotNull());
3384
3385 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
3386 ASSERT_THAT(BarDecl, NotNull());
3387
3388 const auto *FooVal = Env.getValue(D: *FooDecl);
3389 const auto *BarVal = Env.getValue(D: *BarDecl);
3390 EXPECT_TRUE(isa<IntegerValue>(FooVal));
3391 EXPECT_TRUE(isa<BoolValue>(BarVal));
3392 });
3393}
3394
3395TEST(TransferTest, IntegralToBooleanCastFromBool) {
3396 std::string Code = R"(
3397 void target(bool Foo) {
3398 int Zab = Foo;
3399 bool Bar = Zab;
3400 // [[p]]
3401 }
3402 )";
3403 runDataflow(
3404 Code,
3405 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3406 ASTContext &ASTCtx) {
3407 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3408 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3409
3410 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
3411 ASSERT_THAT(FooDecl, NotNull());
3412
3413 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
3414 ASSERT_THAT(BarDecl, NotNull());
3415
3416 const auto *FooVal = Env.getValue(D: *FooDecl);
3417 const auto *BarVal = Env.getValue(D: *BarDecl);
3418 EXPECT_TRUE(isa<BoolValue>(FooVal));
3419 EXPECT_TRUE(isa<BoolValue>(BarVal));
3420 EXPECT_EQ(FooVal, BarVal);
3421 });
3422}
3423
3424TEST(TransferTest, NullToPointerCast) {
3425 std::string Code = R"(
3426 using my_nullptr_t = decltype(nullptr);
3427 struct Baz {};
3428 void target() {
3429 int *FooX = nullptr;
3430 int *FooY = nullptr;
3431 bool **Bar = nullptr;
3432 Baz *Baz = nullptr;
3433 my_nullptr_t Null = 0;
3434 // [[p]]
3435 }
3436 )";
3437 runDataflow(
3438 Code,
3439 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3440 ASTContext &ASTCtx) {
3441 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3442 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3443
3444 const ValueDecl *FooXDecl = findValueDecl(ASTCtx, Name: "FooX");
3445 ASSERT_THAT(FooXDecl, NotNull());
3446
3447 const ValueDecl *FooYDecl = findValueDecl(ASTCtx, Name: "FooY");
3448 ASSERT_THAT(FooYDecl, NotNull());
3449
3450 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
3451 ASSERT_THAT(BarDecl, NotNull());
3452
3453 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
3454 ASSERT_THAT(BazDecl, NotNull());
3455
3456 const ValueDecl *NullDecl = findValueDecl(ASTCtx, Name: "Null");
3457 ASSERT_THAT(NullDecl, NotNull());
3458
3459 const auto *FooXVal = cast<PointerValue>(Val: Env.getValue(D: *FooXDecl));
3460 const auto *FooYVal = cast<PointerValue>(Val: Env.getValue(D: *FooYDecl));
3461 const auto *BarVal = cast<PointerValue>(Val: Env.getValue(D: *BarDecl));
3462 const auto *BazVal = cast<PointerValue>(Val: Env.getValue(D: *BazDecl));
3463 const auto *NullVal = cast<PointerValue>(Val: Env.getValue(D: *NullDecl));
3464
3465 EXPECT_EQ(FooXVal, FooYVal);
3466 EXPECT_NE(FooXVal, BarVal);
3467 EXPECT_NE(FooXVal, BazVal);
3468 EXPECT_NE(BarVal, BazVal);
3469
3470 const StorageLocation &FooPointeeLoc = FooXVal->getPointeeLoc();
3471 EXPECT_TRUE(isa<ScalarStorageLocation>(FooPointeeLoc));
3472 EXPECT_THAT(Env.getValue(FooPointeeLoc), IsNull());
3473
3474 const StorageLocation &BarPointeeLoc = BarVal->getPointeeLoc();
3475 EXPECT_TRUE(isa<ScalarStorageLocation>(BarPointeeLoc));
3476 EXPECT_THAT(Env.getValue(BarPointeeLoc), IsNull());
3477
3478 const StorageLocation &BazPointeeLoc = BazVal->getPointeeLoc();
3479 EXPECT_TRUE(isa<RecordStorageLocation>(BazPointeeLoc));
3480 EXPECT_EQ(BazVal, &Env.fork().getOrCreateNullPointerValue(
3481 BazPointeeLoc.getType()));
3482
3483 const StorageLocation &NullPointeeLoc = NullVal->getPointeeLoc();
3484 EXPECT_TRUE(isa<ScalarStorageLocation>(NullPointeeLoc));
3485 EXPECT_THAT(Env.getValue(NullPointeeLoc), IsNull());
3486 });
3487}
3488
3489TEST(TransferTest, PointerToMemberVariable) {
3490 std::string Code = R"(
3491 struct S {
3492 int i;
3493 };
3494 void target() {
3495 int S::*MemberPointer = &S::i;
3496 // [[p]]
3497 }
3498 )";
3499 runDataflow(
3500 Code,
3501 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3502 ASTContext &ASTCtx) {
3503 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3504
3505 const ValueDecl *MemberPointerDecl =
3506 findValueDecl(ASTCtx, Name: "MemberPointer");
3507 ASSERT_THAT(MemberPointerDecl, NotNull());
3508 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull());
3509 });
3510}
3511
3512TEST(TransferTest, PointerToMemberFunction) {
3513 std::string Code = R"(
3514 struct S {
3515 void Method();
3516 };
3517 void target() {
3518 void (S::*MemberPointer)() = &S::Method;
3519 // [[p]]
3520 }
3521 )";
3522 runDataflow(
3523 Code,
3524 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3525 ASTContext &ASTCtx) {
3526 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3527
3528 const ValueDecl *MemberPointerDecl =
3529 findValueDecl(ASTCtx, Name: "MemberPointer");
3530 ASSERT_THAT(MemberPointerDecl, NotNull());
3531 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull());
3532 });
3533}
3534
3535TEST(TransferTest, NullToMemberPointerCast) {
3536 std::string Code = R"(
3537 struct Foo {};
3538 void target() {
3539 int Foo::*MemberPointer = nullptr;
3540 // [[p]]
3541 }
3542 )";
3543 runDataflow(
3544 Code,
3545 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3546 ASTContext &ASTCtx) {
3547 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3548 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3549
3550 const ValueDecl *MemberPointerDecl =
3551 findValueDecl(ASTCtx, Name: "MemberPointer");
3552 ASSERT_THAT(MemberPointerDecl, NotNull());
3553 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull());
3554 });
3555}
3556
3557TEST(TransferTest, AddrOfValue) {
3558 std::string Code = R"(
3559 void target() {
3560 int Foo;
3561 int *Bar = &Foo;
3562 // [[p]]
3563 }
3564 )";
3565 runDataflow(
3566 Code,
3567 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3568 ASTContext &ASTCtx) {
3569 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3570 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3571
3572 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
3573 ASSERT_THAT(FooDecl, NotNull());
3574
3575 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
3576 ASSERT_THAT(BarDecl, NotNull());
3577
3578 const auto *FooLoc =
3579 cast<ScalarStorageLocation>(Val: Env.getStorageLocation(D: *FooDecl));
3580 const auto *BarVal = cast<PointerValue>(Val: Env.getValue(D: *BarDecl));
3581 EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc);
3582 });
3583}
3584
3585TEST(TransferTest, AddrOfReference) {
3586 std::string Code = R"(
3587 void target(int *Foo) {
3588 int *Bar = &(*Foo);
3589 // [[p]]
3590 }
3591 )";
3592 runDataflow(
3593 Code,
3594 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3595 ASTContext &ASTCtx) {
3596 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3597 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3598
3599 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
3600 ASSERT_THAT(FooDecl, NotNull());
3601
3602 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
3603 ASSERT_THAT(BarDecl, NotNull());
3604
3605 const auto *FooVal = cast<PointerValue>(Val: Env.getValue(D: *FooDecl));
3606 const auto *BarVal = cast<PointerValue>(Val: Env.getValue(D: *BarDecl));
3607 EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc());
3608 });
3609}
3610
3611TEST(TransferTest, CannotAnalyzeFunctionTemplate) {
3612 std::string Code = R"(
3613 template <typename T>
3614 void target() {}
3615 )";
3616 ASSERT_THAT_ERROR(
3617 checkDataflowWithNoopAnalysis(Code),
3618 llvm::FailedWithMessage("Cannot analyze templated declarations"));
3619}
3620
3621TEST(TransferTest, CannotAnalyzeMethodOfClassTemplate) {
3622 std::string Code = R"(
3623 template <typename T>
3624 struct A {
3625 void target() {}
3626 };
3627 )";
3628 ASSERT_THAT_ERROR(
3629 checkDataflowWithNoopAnalysis(Code),
3630 llvm::FailedWithMessage("Cannot analyze templated declarations"));
3631}
3632
3633TEST(TransferTest, VarDeclInitAssignConditionalOperator) {
3634 std::string Code = R"(
3635 struct A {
3636 int i;
3637 };
3638
3639 void target(A Foo, A Bar, bool Cond) {
3640 A Baz = Cond ? A(Foo) : A(Bar);
3641 // Make sure A::i is modeled.
3642 Baz.i;
3643 /*[[p]]*/
3644 }
3645 )";
3646 runDataflow(
3647 Code,
3648 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3649 ASTContext &ASTCtx) {
3650 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3651
3652 auto *FooIVal = cast<IntegerValue>(Val: getFieldValue(
3653 Loc: &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, Name: "Foo"), Name: "i",
3654 ASTCtx, Env));
3655 auto *BarIVal = cast<IntegerValue>(Val: getFieldValue(
3656 Loc: &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, Name: "Bar"), Name: "i",
3657 ASTCtx, Env));
3658 auto *BazIVal = cast<IntegerValue>(Val: getFieldValue(
3659 Loc: &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, Name: "Baz"), Name: "i",
3660 ASTCtx, Env));
3661
3662 EXPECT_NE(BazIVal, FooIVal);
3663 EXPECT_NE(BazIVal, BarIVal);
3664 });
3665}
3666
3667TEST(TransferTest, VarDeclInDoWhile) {
3668 std::string Code = R"(
3669 void target(int *Foo) {
3670 do {
3671 int Bar = *Foo;
3672 // [[in_loop]]
3673 } while (false);
3674 (void)0;
3675 // [[after_loop]]
3676 }
3677 )";
3678 runDataflow(
3679 Code,
3680 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3681 ASTContext &ASTCtx) {
3682 const Environment &EnvInLoop =
3683 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "in_loop");
3684 const Environment &EnvAfterLoop =
3685 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "after_loop");
3686
3687 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
3688 ASSERT_THAT(FooDecl, NotNull());
3689
3690 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
3691 ASSERT_THAT(BarDecl, NotNull());
3692
3693 const auto *FooVal =
3694 cast<PointerValue>(Val: EnvAfterLoop.getValue(D: *FooDecl));
3695 const auto *FooPointeeVal =
3696 cast<IntegerValue>(Val: EnvAfterLoop.getValue(Loc: FooVal->getPointeeLoc()));
3697
3698 const auto *BarVal = cast<IntegerValue>(Val: EnvInLoop.getValue(D: *BarDecl));
3699 EXPECT_EQ(BarVal, FooPointeeVal);
3700
3701 ASSERT_THAT(EnvAfterLoop.getValue(*BarDecl), IsNull());
3702 });
3703}
3704
3705TEST(TransferTest, UnreachableAfterWhileTrue) {
3706 std::string Code = R"(
3707 void target() {
3708 while (true) {}
3709 (void)0;
3710 /*[[p]]*/
3711 }
3712 )";
3713 runDataflow(
3714 Code,
3715 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3716 ASTContext &ASTCtx) {
3717 // The node after the while-true is pruned because it is trivially
3718 // known to be unreachable.
3719 ASSERT_TRUE(Results.empty());
3720 });
3721}
3722
3723TEST(TransferTest, AggregateInitialization) {
3724 std::string BracesCode = R"(
3725 struct A {
3726 int Foo;
3727 };
3728
3729 struct B {
3730 int Bar;
3731 A Baz;
3732 int Qux;
3733 };
3734
3735 void target(int BarArg, int FooArg, int QuxArg) {
3736 B Quux{BarArg, {FooArg}, QuxArg};
3737 B OtherB;
3738 /*[[p]]*/
3739 }
3740 )";
3741 std::string BraceElisionCode = R"(
3742 struct A {
3743 int Foo;
3744 };
3745
3746 struct B {
3747 int Bar;
3748 A Baz;
3749 int Qux;
3750 };
3751
3752 void target(int BarArg, int FooArg, int QuxArg) {
3753 B Quux = {BarArg, FooArg, QuxArg};
3754 B OtherB;
3755 /*[[p]]*/
3756 }
3757 )";
3758 for (const std::string &Code : {BracesCode, BraceElisionCode}) {
3759 runDataflow(
3760 Code,
3761 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3762 ASTContext &ASTCtx) {
3763 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3764 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3765
3766 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
3767 ASSERT_THAT(FooDecl, NotNull());
3768
3769 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
3770 ASSERT_THAT(BarDecl, NotNull());
3771
3772 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
3773 ASSERT_THAT(BazDecl, NotNull());
3774
3775 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, Name: "Qux");
3776 ASSERT_THAT(QuxDecl, NotNull());
3777
3778 const ValueDecl *FooArgDecl = findValueDecl(ASTCtx, Name: "FooArg");
3779 ASSERT_THAT(FooArgDecl, NotNull());
3780
3781 const ValueDecl *BarArgDecl = findValueDecl(ASTCtx, Name: "BarArg");
3782 ASSERT_THAT(BarArgDecl, NotNull());
3783
3784 const ValueDecl *QuxArgDecl = findValueDecl(ASTCtx, Name: "QuxArg");
3785 ASSERT_THAT(QuxArgDecl, NotNull());
3786
3787 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, Name: "Quux");
3788 ASSERT_THAT(QuuxDecl, NotNull());
3789
3790 const auto *FooArgVal = cast<IntegerValue>(Val: Env.getValue(D: *FooArgDecl));
3791 const auto *BarArgVal = cast<IntegerValue>(Val: Env.getValue(D: *BarArgDecl));
3792 const auto *QuxArgVal = cast<IntegerValue>(Val: Env.getValue(D: *QuxArgDecl));
3793
3794 const auto &QuuxLoc =
3795 *cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *QuuxDecl));
3796 const auto &BazLoc =
3797 *cast<RecordStorageLocation>(Val: QuuxLoc.getChild(D: *BazDecl));
3798
3799 EXPECT_EQ(getFieldValue(&QuuxLoc, *BarDecl, Env), BarArgVal);
3800 EXPECT_EQ(getFieldValue(&BazLoc, *FooDecl, Env), FooArgVal);
3801 EXPECT_EQ(getFieldValue(&QuuxLoc, *QuxDecl, Env), QuxArgVal);
3802
3803 // Check that fields initialized in an initializer list are always
3804 // modeled in other instances of the same type.
3805 const auto &OtherBLoc =
3806 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, Name: "OtherB");
3807 EXPECT_THAT(OtherBLoc.getChild(*BarDecl), NotNull());
3808 EXPECT_THAT(OtherBLoc.getChild(*BazDecl), NotNull());
3809 EXPECT_THAT(OtherBLoc.getChild(*QuxDecl), NotNull());
3810 });
3811 }
3812}
3813
3814TEST(TransferTest, AggregateInitializationReferenceField) {
3815 std::string Code = R"(
3816 struct S {
3817 int &RefField;
3818 };
3819
3820 void target(int i) {
3821 S s = { i };
3822 /*[[p]]*/
3823 }
3824 )";
3825 runDataflow(
3826 Code,
3827 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3828 ASTContext &ASTCtx) {
3829 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3830
3831 const ValueDecl *RefFieldDecl = findValueDecl(ASTCtx, Name: "RefField");
3832
3833 auto &ILoc = getLocForDecl<StorageLocation>(ASTCtx, Env, Name: "i");
3834 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, Name: "s");
3835
3836 EXPECT_EQ(SLoc.getChild(*RefFieldDecl), &ILoc);
3837 });
3838}
3839
3840TEST(TransferTest, AggregateInitialization_NotExplicitlyInitializedField) {
3841 std::string Code = R"(
3842 struct S {
3843 int i1;
3844 int i2;
3845 };
3846
3847 void target(int i) {
3848 S s = { i };
3849 /*[[p]]*/
3850 }
3851 )";
3852 runDataflow(
3853 Code,
3854 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3855 ASTContext &ASTCtx) {
3856 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3857
3858 const ValueDecl *I1FieldDecl = findValueDecl(ASTCtx, Name: "i1");
3859 const ValueDecl *I2FieldDecl = findValueDecl(ASTCtx, Name: "i2");
3860
3861 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, Name: "s");
3862
3863 auto &IValue = getValueForDecl<IntegerValue>(ASTCtx, Env, Name: "i");
3864 auto &I1Value =
3865 *cast<IntegerValue>(Val: getFieldValue(Loc: &SLoc, Field: *I1FieldDecl, Env));
3866 EXPECT_EQ(&I1Value, &IValue);
3867 auto &I2Value =
3868 *cast<IntegerValue>(Val: getFieldValue(Loc: &SLoc, Field: *I2FieldDecl, Env));
3869 EXPECT_NE(&I2Value, &IValue);
3870 });
3871}
3872
3873TEST(TransferTest, AggregateInitializationFunctionPointer) {
3874 // This is a repro for an assertion failure.
3875 // nullptr takes on the type of a const function pointer, but its type was
3876 // asserted to be equal to the *unqualified* type of Field, which no longer
3877 // included the const.
3878 std::string Code = R"(
3879 struct S {
3880 void (*const Field)();
3881 };
3882
3883 void target() {
3884 S s{nullptr};
3885 }
3886 )";
3887 runDataflow(
3888 Code,
3889 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3890 ASTContext &ASTCtx) {});
3891}
3892
3893TEST(TransferTest, AssignToUnionMember) {
3894 std::string Code = R"(
3895 union A {
3896 int Foo;
3897 };
3898
3899 void target(int Bar) {
3900 A Baz;
3901 Baz.Foo = Bar;
3902 // [[p]]
3903 }
3904 )";
3905 runDataflow(
3906 Code,
3907 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3908 ASTContext &ASTCtx) {
3909 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3910 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3911
3912 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
3913 ASSERT_THAT(BazDecl, NotNull());
3914 ASSERT_TRUE(BazDecl->getType()->isUnionType());
3915
3916 auto BazFields = BazDecl->getType()->getAsRecordDecl()->fields();
3917 FieldDecl *FooDecl = nullptr;
3918 for (FieldDecl *Field : BazFields) {
3919 if (Field->getNameAsString() == "Foo") {
3920 FooDecl = Field;
3921 } else {
3922 FAIL() << "Unexpected field: " << Field->getNameAsString();
3923 }
3924 }
3925 ASSERT_THAT(FooDecl, NotNull());
3926
3927 const auto *BazLoc = dyn_cast_or_null<RecordStorageLocation>(
3928 Val: Env.getStorageLocation(D: *BazDecl));
3929 ASSERT_THAT(BazLoc, NotNull());
3930
3931 const auto *FooVal =
3932 cast<IntegerValue>(Val: getFieldValue(BazLoc, *FooDecl, Env));
3933
3934 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
3935 ASSERT_THAT(BarDecl, NotNull());
3936 const auto *BarLoc = Env.getStorageLocation(D: *BarDecl);
3937 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
3938
3939 EXPECT_EQ(Env.getValue(*BarLoc), FooVal);
3940 });
3941}
3942
3943TEST(TransferTest, AssignFromBoolLiteral) {
3944 std::string Code = R"(
3945 void target() {
3946 bool Foo = true;
3947 bool Bar = false;
3948 // [[p]]
3949 }
3950 )";
3951 runDataflow(
3952 Code,
3953 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3954 ASTContext &ASTCtx) {
3955 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3956 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3957
3958 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
3959 ASSERT_THAT(FooDecl, NotNull());
3960
3961 const auto *FooVal =
3962 dyn_cast_or_null<BoolValue>(Val: Env.getValue(D: *FooDecl));
3963 ASSERT_THAT(FooVal, NotNull());
3964
3965 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
3966 ASSERT_THAT(BarDecl, NotNull());
3967
3968 const auto *BarVal =
3969 dyn_cast_or_null<BoolValue>(Val: Env.getValue(D: *BarDecl));
3970 ASSERT_THAT(BarVal, NotNull());
3971
3972 EXPECT_EQ(FooVal, &Env.getBoolLiteralValue(true));
3973 EXPECT_EQ(BarVal, &Env.getBoolLiteralValue(false));
3974 });
3975}
3976
3977TEST(TransferTest, AssignFromCompositeBoolExpression) {
3978 {
3979 std::string Code = R"(
3980 void target(bool Foo, bool Bar, bool Qux) {
3981 bool Baz = (Foo) && (Bar || Qux);
3982 // [[p]]
3983 }
3984 )";
3985 runDataflow(
3986 Code,
3987 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3988 ASTContext &ASTCtx) {
3989 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3990 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
3991
3992 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
3993 ASSERT_THAT(FooDecl, NotNull());
3994
3995 const auto *FooVal =
3996 dyn_cast_or_null<BoolValue>(Val: Env.getValue(D: *FooDecl));
3997 ASSERT_THAT(FooVal, NotNull());
3998
3999 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
4000 ASSERT_THAT(BarDecl, NotNull());
4001
4002 const auto *BarVal =
4003 dyn_cast_or_null<BoolValue>(Val: Env.getValue(D: *BarDecl));
4004 ASSERT_THAT(BarVal, NotNull());
4005
4006 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, Name: "Qux");
4007 ASSERT_THAT(QuxDecl, NotNull());
4008
4009 const auto *QuxVal =
4010 dyn_cast_or_null<BoolValue>(Val: Env.getValue(D: *QuxDecl));
4011 ASSERT_THAT(QuxVal, NotNull());
4012
4013 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
4014 ASSERT_THAT(BazDecl, NotNull());
4015
4016 const auto *BazVal =
4017 dyn_cast_or_null<BoolValue>(Val: Env.getValue(D: *BazDecl));
4018 ASSERT_THAT(BazVal, NotNull());
4019 auto &A = Env.arena();
4020 EXPECT_EQ(&BazVal->formula(),
4021 &A.makeAnd(FooVal->formula(),
4022 A.makeOr(BarVal->formula(), QuxVal->formula())));
4023 });
4024 }
4025
4026 {
4027 std::string Code = R"(
4028 void target(bool Foo, bool Bar, bool Qux) {
4029 bool Baz = (Foo && Qux) || (Bar);
4030 // [[p]]
4031 }
4032 )";
4033 runDataflow(
4034 Code,
4035 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4036 ASTContext &ASTCtx) {
4037 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4038 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4039
4040 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
4041 ASSERT_THAT(FooDecl, NotNull());
4042
4043 const auto *FooVal =
4044 dyn_cast_or_null<BoolValue>(Val: Env.getValue(D: *FooDecl));
4045 ASSERT_THAT(FooVal, NotNull());
4046
4047 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
4048 ASSERT_THAT(BarDecl, NotNull());
4049
4050 const auto *BarVal =
4051 dyn_cast_or_null<BoolValue>(Val: Env.getValue(D: *BarDecl));
4052 ASSERT_THAT(BarVal, NotNull());
4053
4054 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, Name: "Qux");
4055 ASSERT_THAT(QuxDecl, NotNull());
4056
4057 const auto *QuxVal =
4058 dyn_cast_or_null<BoolValue>(Val: Env.getValue(D: *QuxDecl));
4059 ASSERT_THAT(QuxVal, NotNull());
4060
4061 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
4062 ASSERT_THAT(BazDecl, NotNull());
4063
4064 const auto *BazVal =
4065 dyn_cast_or_null<BoolValue>(Val: Env.getValue(D: *BazDecl));
4066 ASSERT_THAT(BazVal, NotNull());
4067 auto &A = Env.arena();
4068 EXPECT_EQ(&BazVal->formula(),
4069 &A.makeOr(A.makeAnd(FooVal->formula(), QuxVal->formula()),
4070 BarVal->formula()));
4071 });
4072 }
4073
4074 {
4075 std::string Code = R"(
4076 void target(bool A, bool B, bool C, bool D) {
4077 bool Foo = ((A && B) && C) && D;
4078 // [[p]]
4079 }
4080 )";
4081 runDataflow(
4082 Code,
4083 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4084 ASTContext &ASTCtx) {
4085 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4086 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4087
4088 const ValueDecl *ADecl = findValueDecl(ASTCtx, Name: "A");
4089 ASSERT_THAT(ADecl, NotNull());
4090
4091 const auto *AVal = dyn_cast_or_null<BoolValue>(Val: Env.getValue(D: *ADecl));
4092 ASSERT_THAT(AVal, NotNull());
4093
4094 const ValueDecl *BDecl = findValueDecl(ASTCtx, Name: "B");
4095 ASSERT_THAT(BDecl, NotNull());
4096
4097 const auto *BVal = dyn_cast_or_null<BoolValue>(Val: Env.getValue(D: *BDecl));
4098 ASSERT_THAT(BVal, NotNull());
4099
4100 const ValueDecl *CDecl = findValueDecl(ASTCtx, Name: "C");
4101 ASSERT_THAT(CDecl, NotNull());
4102
4103 const auto *CVal = dyn_cast_or_null<BoolValue>(Val: Env.getValue(D: *CDecl));
4104 ASSERT_THAT(CVal, NotNull());
4105
4106 const ValueDecl *DDecl = findValueDecl(ASTCtx, Name: "D");
4107 ASSERT_THAT(DDecl, NotNull());
4108
4109 const auto *DVal = dyn_cast_or_null<BoolValue>(Val: Env.getValue(D: *DDecl));
4110 ASSERT_THAT(DVal, NotNull());
4111
4112 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
4113 ASSERT_THAT(FooDecl, NotNull());
4114
4115 const auto *FooVal =
4116 dyn_cast_or_null<BoolValue>(Val: Env.getValue(D: *FooDecl));
4117 ASSERT_THAT(FooVal, NotNull());
4118 auto &A = Env.arena();
4119 EXPECT_EQ(
4120 &FooVal->formula(),
4121 &A.makeAnd(A.makeAnd(A.makeAnd(AVal->formula(), BVal->formula()),
4122 CVal->formula()),
4123 DVal->formula()));
4124 });
4125 }
4126}
4127
4128TEST(TransferTest, AssignFromBoolNegation) {
4129 std::string Code = R"(
4130 void target() {
4131 bool Foo = true;
4132 bool Bar = !(Foo);
4133 // [[p]]
4134 }
4135 )";
4136 runDataflow(
4137 Code,
4138 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4139 ASTContext &ASTCtx) {
4140 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4141 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4142
4143 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
4144 ASSERT_THAT(FooDecl, NotNull());
4145
4146 const auto *FooVal =
4147 dyn_cast_or_null<BoolValue>(Val: Env.getValue(D: *FooDecl));
4148 ASSERT_THAT(FooVal, NotNull());
4149
4150 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
4151 ASSERT_THAT(BarDecl, NotNull());
4152
4153 const auto *BarVal =
4154 dyn_cast_or_null<BoolValue>(Val: Env.getValue(D: *BarDecl));
4155 ASSERT_THAT(BarVal, NotNull());
4156 auto &A = Env.arena();
4157 EXPECT_EQ(&BarVal->formula(), &A.makeNot(FooVal->formula()));
4158 });
4159}
4160
4161TEST(TransferTest, BuiltinExpect) {
4162 std::string Code = R"(
4163 void target(long Foo) {
4164 long Bar = __builtin_expect(Foo, true);
4165 /*[[p]]*/
4166 }
4167 )";
4168 runDataflow(
4169 Code,
4170 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4171 ASTContext &ASTCtx) {
4172 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4173 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4174
4175 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
4176 ASSERT_THAT(FooDecl, NotNull());
4177
4178 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
4179 ASSERT_THAT(BarDecl, NotNull());
4180
4181 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
4182 });
4183}
4184
4185// `__builtin_expect` takes and returns a `long` argument, so other types
4186// involve casts. This verifies that we identify the input and output in that
4187// case.
4188TEST(TransferTest, BuiltinExpectBoolArg) {
4189 std::string Code = R"(
4190 void target(bool Foo) {
4191 bool Bar = __builtin_expect(Foo, true);
4192 /*[[p]]*/
4193 }
4194 )";
4195 runDataflow(
4196 Code,
4197 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4198 ASTContext &ASTCtx) {
4199 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4200 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4201
4202 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
4203 ASSERT_THAT(FooDecl, NotNull());
4204
4205 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
4206 ASSERT_THAT(BarDecl, NotNull());
4207
4208 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
4209 });
4210}
4211
4212TEST(TransferTest, BuiltinUnreachable) {
4213 std::string Code = R"(
4214 void target(bool Foo) {
4215 bool Bar = false;
4216 if (Foo)
4217 Bar = Foo;
4218 else
4219 __builtin_unreachable();
4220 (void)0;
4221 /*[[p]]*/
4222 }
4223 )";
4224 runDataflow(
4225 Code,
4226 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4227 ASTContext &ASTCtx) {
4228 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4229 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4230
4231 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
4232 ASSERT_THAT(FooDecl, NotNull());
4233
4234 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
4235 ASSERT_THAT(BarDecl, NotNull());
4236
4237 // `__builtin_unreachable` promises that the code is
4238 // unreachable, so the compiler treats the "then" branch as the
4239 // only possible predecessor of this statement.
4240 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
4241 });
4242}
4243
4244TEST(TransferTest, BuiltinTrap) {
4245 std::string Code = R"(
4246 void target(bool Foo) {
4247 bool Bar = false;
4248 if (Foo)
4249 Bar = Foo;
4250 else
4251 __builtin_trap();
4252 (void)0;
4253 /*[[p]]*/
4254 }
4255 )";
4256 runDataflow(
4257 Code,
4258 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4259 ASTContext &ASTCtx) {
4260 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4261 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4262
4263 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
4264 ASSERT_THAT(FooDecl, NotNull());
4265
4266 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
4267 ASSERT_THAT(BarDecl, NotNull());
4268
4269 // `__builtin_trap` ensures program termination, so only the
4270 // "then" branch is a predecessor of this statement.
4271 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
4272 });
4273}
4274
4275TEST(TransferTest, BuiltinDebugTrap) {
4276 std::string Code = R"(
4277 void target(bool Foo) {
4278 bool Bar = false;
4279 if (Foo)
4280 Bar = Foo;
4281 else
4282 __builtin_debugtrap();
4283 (void)0;
4284 /*[[p]]*/
4285 }
4286 )";
4287 runDataflow(
4288 Code,
4289 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4290 ASTContext &ASTCtx) {
4291 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4292 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4293
4294 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
4295 ASSERT_THAT(FooDecl, NotNull());
4296
4297 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
4298 ASSERT_THAT(BarDecl, NotNull());
4299
4300 // `__builtin_debugtrap` doesn't ensure program termination.
4301 EXPECT_NE(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
4302 });
4303}
4304
4305TEST(TransferTest, StaticIntSingleVarDecl) {
4306 std::string Code = R"(
4307 void target() {
4308 static int Foo;
4309 // [[p]]
4310 }
4311 )";
4312 runDataflow(
4313 Code,
4314 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4315 ASTContext &ASTCtx) {
4316 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4317 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4318
4319 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
4320 ASSERT_THAT(FooDecl, NotNull());
4321
4322 const StorageLocation *FooLoc = Env.getStorageLocation(D: *FooDecl);
4323 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
4324
4325 const Value *FooVal = Env.getValue(Loc: *FooLoc);
4326 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
4327 });
4328}
4329
4330TEST(TransferTest, StaticIntGroupVarDecl) {
4331 std::string Code = R"(
4332 void target() {
4333 static int Foo, Bar;
4334 (void)0;
4335 // [[p]]
4336 }
4337 )";
4338 runDataflow(
4339 Code,
4340 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4341 ASTContext &ASTCtx) {
4342 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4343 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4344
4345 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
4346 ASSERT_THAT(FooDecl, NotNull());
4347
4348 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
4349 ASSERT_THAT(BarDecl, NotNull());
4350
4351 const StorageLocation *FooLoc = Env.getStorageLocation(D: *FooDecl);
4352 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
4353
4354 const StorageLocation *BarLoc = Env.getStorageLocation(D: *BarDecl);
4355 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
4356
4357 const Value *FooVal = Env.getValue(Loc: *FooLoc);
4358 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
4359
4360 const Value *BarVal = Env.getValue(Loc: *BarLoc);
4361 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
4362
4363 EXPECT_NE(FooVal, BarVal);
4364 });
4365}
4366
4367TEST(TransferTest, GlobalIntVarDecl) {
4368 std::string Code = R"(
4369 static int Foo;
4370
4371 void target() {
4372 int Bar = Foo;
4373 int Baz = Foo;
4374 // [[p]]
4375 }
4376 )";
4377 runDataflow(
4378 Code,
4379 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4380 ASTContext &ASTCtx) {
4381 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4382 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4383
4384 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
4385 ASSERT_THAT(BarDecl, NotNull());
4386
4387 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
4388 ASSERT_THAT(BazDecl, NotNull());
4389
4390 const Value *BarVal = cast<IntegerValue>(Val: Env.getValue(D: *BarDecl));
4391 const Value *BazVal = cast<IntegerValue>(Val: Env.getValue(D: *BazDecl));
4392 EXPECT_EQ(BarVal, BazVal);
4393 });
4394}
4395
4396TEST(TransferTest, StaticMemberIntVarDecl) {
4397 std::string Code = R"(
4398 struct A {
4399 static int Foo;
4400 };
4401
4402 void target(A a) {
4403 int Bar = a.Foo;
4404 int Baz = a.Foo;
4405 // [[p]]
4406 }
4407 )";
4408 runDataflow(
4409 Code,
4410 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4411 ASTContext &ASTCtx) {
4412 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4413 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4414
4415 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
4416 ASSERT_THAT(BarDecl, NotNull());
4417
4418 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
4419 ASSERT_THAT(BazDecl, NotNull());
4420
4421 const Value *BarVal = cast<IntegerValue>(Val: Env.getValue(D: *BarDecl));
4422 const Value *BazVal = cast<IntegerValue>(Val: Env.getValue(D: *BazDecl));
4423 EXPECT_EQ(BarVal, BazVal);
4424 });
4425}
4426
4427TEST(TransferTest, StaticMemberRefVarDecl) {
4428 std::string Code = R"(
4429 struct A {
4430 static int &Foo;
4431 };
4432
4433 void target(A a) {
4434 int Bar = a.Foo;
4435 int Baz = a.Foo;
4436 // [[p]]
4437 }
4438 )";
4439 runDataflow(
4440 Code,
4441 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4442 ASTContext &ASTCtx) {
4443 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4444 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4445
4446 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
4447 ASSERT_THAT(BarDecl, NotNull());
4448
4449 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
4450 ASSERT_THAT(BazDecl, NotNull());
4451
4452 const Value *BarVal = cast<IntegerValue>(Val: Env.getValue(D: *BarDecl));
4453 const Value *BazVal = cast<IntegerValue>(Val: Env.getValue(D: *BazDecl));
4454 EXPECT_EQ(BarVal, BazVal);
4455 });
4456}
4457
4458TEST(TransferTest, AssignMemberBeforeCopy) {
4459 std::string Code = R"(
4460 struct A {
4461 int Foo;
4462 };
4463
4464 void target() {
4465 A A1;
4466 A A2;
4467 int Bar;
4468 A1.Foo = Bar;
4469 A2 = A1;
4470 // [[p]]
4471 }
4472 )";
4473 runDataflow(
4474 Code,
4475 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4476 ASTContext &ASTCtx) {
4477 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4478 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4479
4480 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
4481 ASSERT_THAT(FooDecl, NotNull());
4482
4483 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
4484 ASSERT_THAT(BarDecl, NotNull());
4485
4486 const ValueDecl *A1Decl = findValueDecl(ASTCtx, Name: "A1");
4487 ASSERT_THAT(A1Decl, NotNull());
4488
4489 const ValueDecl *A2Decl = findValueDecl(ASTCtx, Name: "A2");
4490 ASSERT_THAT(A2Decl, NotNull());
4491
4492 const auto *BarVal = cast<IntegerValue>(Val: Env.getValue(D: *BarDecl));
4493
4494 const auto &A2Loc =
4495 *cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *A2Decl));
4496 EXPECT_EQ(getFieldValue(&A2Loc, *FooDecl, Env), BarVal);
4497 });
4498}
4499
4500TEST(TransferTest, BooleanEquality) {
4501 std::string Code = R"(
4502 void target(bool Bar) {
4503 bool Foo = true;
4504 if (Bar == Foo) {
4505 (void)0;
4506 /*[[p-then]]*/
4507 } else {
4508 (void)0;
4509 /*[[p-else]]*/
4510 }
4511 }
4512 )";
4513 runDataflow(
4514 Code,
4515 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4516 ASTContext &ASTCtx) {
4517 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else"));
4518 const Environment &EnvThen =
4519 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p-then");
4520 const Environment &EnvElse =
4521 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p-else");
4522
4523 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
4524 ASSERT_THAT(BarDecl, NotNull());
4525
4526 auto &BarValThen = getFormula(D: *BarDecl, Env: EnvThen);
4527 EXPECT_TRUE(EnvThen.proves(BarValThen));
4528
4529 auto &BarValElse = getFormula(D: *BarDecl, Env: EnvElse);
4530 EXPECT_TRUE(EnvElse.proves(EnvElse.arena().makeNot(BarValElse)));
4531 });
4532}
4533
4534TEST(TransferTest, BooleanInequality) {
4535 std::string Code = R"(
4536 void target(bool Bar) {
4537 bool Foo = true;
4538 if (Bar != Foo) {
4539 (void)0;
4540 /*[[p-then]]*/
4541 } else {
4542 (void)0;
4543 /*[[p-else]]*/
4544 }
4545 }
4546 )";
4547 runDataflow(
4548 Code,
4549 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4550 ASTContext &ASTCtx) {
4551 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else"));
4552 const Environment &EnvThen =
4553 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p-then");
4554 const Environment &EnvElse =
4555 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p-else");
4556
4557 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
4558 ASSERT_THAT(BarDecl, NotNull());
4559
4560 auto &BarValThen = getFormula(D: *BarDecl, Env: EnvThen);
4561 EXPECT_TRUE(EnvThen.proves(EnvThen.arena().makeNot(BarValThen)));
4562
4563 auto &BarValElse = getFormula(D: *BarDecl, Env: EnvElse);
4564 EXPECT_TRUE(EnvElse.proves(BarValElse));
4565 });
4566}
4567
4568TEST(TransferTest, IntegerLiteralEquality) {
4569 std::string Code = R"(
4570 void target() {
4571 bool equal = (42 == 42);
4572 // [[p]]
4573 }
4574 )";
4575 runDataflow(
4576 Code,
4577 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4578 ASTContext &ASTCtx) {
4579 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4580
4581 auto &Equal =
4582 getValueForDecl<BoolValue>(ASTCtx, Env, Name: "equal").formula();
4583 EXPECT_TRUE(Env.proves(Equal));
4584 });
4585}
4586
4587TEST(TransferTest, CorrelatedBranches) {
4588 std::string Code = R"(
4589 void target(bool B, bool C) {
4590 if (B) {
4591 return;
4592 }
4593 (void)0;
4594 /*[[p0]]*/
4595 if (C) {
4596 B = true;
4597 /*[[p1]]*/
4598 }
4599 if (B) {
4600 (void)0;
4601 /*[[p2]]*/
4602 }
4603 }
4604 )";
4605 runDataflow(
4606 Code,
4607 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4608 ASTContext &ASTCtx) {
4609 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p0", "p1", "p2"));
4610
4611 const ValueDecl *CDecl = findValueDecl(ASTCtx, Name: "C");
4612 ASSERT_THAT(CDecl, NotNull());
4613
4614 {
4615 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p0");
4616 const ValueDecl *BDecl = findValueDecl(ASTCtx, Name: "B");
4617 ASSERT_THAT(BDecl, NotNull());
4618 auto &BVal = getFormula(D: *BDecl, Env);
4619
4620 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BVal)));
4621 }
4622
4623 {
4624 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p1");
4625 auto &CVal = getFormula(D: *CDecl, Env);
4626 EXPECT_TRUE(Env.proves(CVal));
4627 }
4628
4629 {
4630 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p2");
4631 auto &CVal = getFormula(D: *CDecl, Env);
4632 EXPECT_TRUE(Env.proves(CVal));
4633 }
4634 });
4635}
4636
4637TEST(TransferTest, LoopWithAssignmentConverges) {
4638 std::string Code = R"(
4639 bool foo();
4640
4641 void target() {
4642 do {
4643 bool Bar = foo();
4644 if (Bar) break;
4645 (void)Bar;
4646 /*[[p]]*/
4647 } while (true);
4648 }
4649 )";
4650 // The key property that we are verifying is implicit in `runDataflow` --
4651 // namely, that the analysis succeeds, rather than hitting the maximum number
4652 // of iterations.
4653 runDataflow(
4654 Code,
4655 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4656 ASTContext &ASTCtx) {
4657 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4658 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4659
4660 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
4661 ASSERT_THAT(BarDecl, NotNull());
4662
4663 auto &BarVal = getFormula(D: *BarDecl, Env);
4664 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal)));
4665 });
4666}
4667
4668TEST(TransferTest, LoopWithStagedAssignments) {
4669 std::string Code = R"(
4670 bool foo();
4671
4672 void target() {
4673 bool Bar = false;
4674 bool Err = false;
4675 while (foo()) {
4676 if (Bar)
4677 Err = true;
4678 Bar = true;
4679 /*[[p]]*/
4680 }
4681 }
4682 )";
4683 runDataflow(
4684 Code,
4685 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4686 ASTContext &ASTCtx) {
4687 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4688 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4689
4690 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
4691 ASSERT_THAT(BarDecl, NotNull());
4692 const ValueDecl *ErrDecl = findValueDecl(ASTCtx, Name: "Err");
4693 ASSERT_THAT(ErrDecl, NotNull());
4694
4695 auto &BarVal = getFormula(D: *BarDecl, Env);
4696 auto &ErrVal = getFormula(D: *ErrDecl, Env);
4697 EXPECT_TRUE(Env.proves(BarVal));
4698 // An unsound analysis, for example only evaluating the loop once, can
4699 // conclude that `Err` is false. So, we test that this conclusion is not
4700 // reached.
4701 EXPECT_FALSE(Env.proves(Env.arena().makeNot(ErrVal)));
4702 });
4703}
4704
4705TEST(TransferTest, LoopWithReferenceAssignmentConverges) {
4706 std::string Code = R"(
4707 bool &foo();
4708
4709 void target() {
4710 do {
4711 bool& Bar = foo();
4712 if (Bar) break;
4713 (void)Bar;
4714 /*[[p]]*/
4715 } while (true);
4716 }
4717 )";
4718 // The key property that we are verifying is that the analysis succeeds,
4719 // rather than hitting the maximum number of iterations.
4720 runDataflow(
4721 Code,
4722 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4723 ASTContext &ASTCtx) {
4724 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4725 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4726
4727 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
4728 ASSERT_THAT(BarDecl, NotNull());
4729
4730 auto &BarVal = getFormula(D: *BarDecl, Env);
4731 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal)));
4732 });
4733}
4734
4735TEST(TransferTest, LoopWithStructReferenceAssignmentConverges) {
4736 std::string Code = R"(
4737 struct Lookup {
4738 int x;
4739 };
4740
4741 void target(Lookup val, bool b) {
4742 const Lookup* l = nullptr;
4743 while (b) {
4744 l = &val;
4745 /*[[p-inner]]*/
4746 }
4747 (void)0;
4748 /*[[p-outer]]*/
4749 }
4750 )";
4751 // The key property that we are verifying is implicit in `runDataflow` --
4752 // namely, that the analysis succeeds, rather than hitting the maximum number
4753 // of iterations.
4754 runDataflow(
4755 Code,
4756 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4757 ASTContext &ASTCtx) {
4758 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-inner", "p-outer"));
4759 const Environment &InnerEnv =
4760 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p-inner");
4761 const Environment &OuterEnv =
4762 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p-outer");
4763
4764 const ValueDecl *ValDecl = findValueDecl(ASTCtx, Name: "val");
4765 ASSERT_THAT(ValDecl, NotNull());
4766
4767 const ValueDecl *LDecl = findValueDecl(ASTCtx, Name: "l");
4768 ASSERT_THAT(LDecl, NotNull());
4769
4770 // Inner.
4771 auto *LVal = dyn_cast<PointerValue>(Val: InnerEnv.getValue(D: *LDecl));
4772 ASSERT_THAT(LVal, NotNull());
4773
4774 EXPECT_EQ(&LVal->getPointeeLoc(),
4775 InnerEnv.getStorageLocation(*ValDecl));
4776
4777 // Outer.
4778 LVal = dyn_cast<PointerValue>(Val: OuterEnv.getValue(D: *LDecl));
4779 ASSERT_THAT(LVal, NotNull());
4780
4781 // The loop body may not have been executed, so we should not conclude
4782 // that `l` points to `val`.
4783 EXPECT_NE(&LVal->getPointeeLoc(),
4784 OuterEnv.getStorageLocation(*ValDecl));
4785 });
4786}
4787
4788TEST(TransferTest, LoopDereferencingChangingPointerConverges) {
4789 std::string Code = R"cc(
4790 bool some_condition();
4791
4792 void target(int i1, int i2) {
4793 int *p = &i1;
4794 while (true) {
4795 (void)*p;
4796 if (some_condition())
4797 p = &i1;
4798 else
4799 p = &i2;
4800 }
4801 }
4802 )cc";
4803 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded());
4804}
4805
4806TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) {
4807 std::string Code = R"cc(
4808 struct Lookup {
4809 int x;
4810 };
4811
4812 bool some_condition();
4813
4814 void target(Lookup l1, Lookup l2) {
4815 Lookup *l = &l1;
4816 while (true) {
4817 (void)l->x;
4818 if (some_condition())
4819 l = &l1;
4820 else
4821 l = &l2;
4822 }
4823 }
4824 )cc";
4825 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded());
4826}
4827
4828TEST(TransferTest, LoopWithShortCircuitedConditionConverges) {
4829 std::string Code = R"cc(
4830 bool foo();
4831
4832 void target() {
4833 bool c = false;
4834 while (foo() || foo()) {
4835 c = true;
4836 }
4837 }
4838 )cc";
4839 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded());
4840}
4841
4842TEST(TransferTest, LoopCanProveInvariantForBoolean) {
4843 // Check that we can prove `b` is always false in the loop.
4844 // This test exercises the logic in `widenDistinctValues()` that preserves
4845 // information if the boolean can be proved to be either true or false in both
4846 // the previous and current iteration.
4847 std::string Code = R"cc(
4848 int return_int();
4849 void target() {
4850 bool b = return_int() == 0;
4851 if (b) return;
4852 while (true) {
4853 b;
4854 // [[p]]
4855 b = return_int() == 0;
4856 if (b) return;
4857 }
4858 }
4859 )cc";
4860 runDataflow(
4861 Code,
4862 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4863 ASTContext &ASTCtx) {
4864 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4865 auto &BVal = getValueForDecl<BoolValue>(ASTCtx, Env, Name: "b");
4866 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BVal.formula())));
4867 });
4868}
4869
4870TEST(TransferTest, DoesNotCrashOnUnionThisExpr) {
4871 std::string Code = R"cc(
4872 union Union {
4873 int A;
4874 float B;
4875 };
4876
4877 void foo() {
4878 Union A;
4879 Union B;
4880 A = B;
4881 }
4882 )cc";
4883 // This is a crash regression test when calling the transfer function on a
4884 // `CXXThisExpr` that refers to a union.
4885 runDataflow(
4886 Code,
4887 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
4888 ASTContext &) {},
4889 Std: LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, TargetFun: "operator=");
4890}
4891
4892TEST(TransferTest, DoesNotCrashOnNullChildren) {
4893 std::string Code = (CoroutineLibrary + R"cc(
4894 task target() noexcept {
4895 co_return;
4896 }
4897 )cc")
4898 .str();
4899 // This is a crash regression test when calling `AdornedCFG::build` on a
4900 // statement (in this case, the `CoroutineBodyStmt`) with null children.
4901 runDataflow(
4902 Code,
4903 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
4904 ASTContext &) {},
4905 Std: LangStandard::lang_cxx20, /*ApplyBuiltinTransfer=*/true);
4906}
4907
4908TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToRefs) {
4909 std::string Code = R"(
4910 struct A {
4911 int Foo;
4912 int Bar;
4913 };
4914
4915 void target() {
4916 int Qux;
4917 A Baz;
4918 Baz.Foo = Qux;
4919 auto &FooRef = Baz.Foo;
4920 auto &BarRef = Baz.Bar;
4921 auto &[BoundFooRef, BoundBarRef] = Baz;
4922 // [[p]]
4923 }
4924 )";
4925 runDataflow(
4926 Code,
4927 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4928 ASTContext &ASTCtx) {
4929 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4930 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4931
4932 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, Name: "FooRef");
4933 ASSERT_THAT(FooRefDecl, NotNull());
4934
4935 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, Name: "BarRef");
4936 ASSERT_THAT(BarRefDecl, NotNull());
4937
4938 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, Name: "Qux");
4939 ASSERT_THAT(QuxDecl, NotNull());
4940
4941 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, Name: "BoundFooRef");
4942 ASSERT_THAT(BoundFooRefDecl, NotNull());
4943
4944 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, Name: "BoundBarRef");
4945 ASSERT_THAT(BoundBarRefDecl, NotNull());
4946
4947 const StorageLocation *FooRefLoc = Env.getStorageLocation(D: *FooRefDecl);
4948 ASSERT_THAT(FooRefLoc, NotNull());
4949
4950 const StorageLocation *BarRefLoc = Env.getStorageLocation(D: *BarRefDecl);
4951 ASSERT_THAT(BarRefLoc, NotNull());
4952
4953 const Value *QuxVal = Env.getValue(D: *QuxDecl);
4954 ASSERT_THAT(QuxVal, NotNull());
4955
4956 const StorageLocation *BoundFooRefLoc =
4957 Env.getStorageLocation(D: *BoundFooRefDecl);
4958 EXPECT_EQ(BoundFooRefLoc, FooRefLoc);
4959
4960 const StorageLocation *BoundBarRefLoc =
4961 Env.getStorageLocation(D: *BoundBarRefDecl);
4962 EXPECT_EQ(BoundBarRefLoc, BarRefLoc);
4963
4964 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal);
4965 });
4966}
4967
4968TEST(TransferTest, StructuredBindingAssignFromStructRefMembersToRefs) {
4969 std::string Code = R"(
4970 struct A {
4971 int &Foo;
4972 int &Bar;
4973 };
4974
4975 void target(A Baz) {
4976 int Qux;
4977 Baz.Foo = Qux;
4978 auto &FooRef = Baz.Foo;
4979 auto &BarRef = Baz.Bar;
4980 auto &[BoundFooRef, BoundBarRef] = Baz;
4981 // [[p]]
4982 }
4983 )";
4984 runDataflow(
4985 Code,
4986 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4987 ASTContext &ASTCtx) {
4988 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4989 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
4990
4991 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, Name: "FooRef");
4992 ASSERT_THAT(FooRefDecl, NotNull());
4993
4994 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, Name: "BarRef");
4995 ASSERT_THAT(BarRefDecl, NotNull());
4996
4997 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, Name: "Qux");
4998 ASSERT_THAT(QuxDecl, NotNull());
4999
5000 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, Name: "BoundFooRef");
5001 ASSERT_THAT(BoundFooRefDecl, NotNull());
5002
5003 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, Name: "BoundBarRef");
5004 ASSERT_THAT(BoundBarRefDecl, NotNull());
5005
5006 const StorageLocation *FooRefLoc = Env.getStorageLocation(D: *FooRefDecl);
5007 ASSERT_THAT(FooRefLoc, NotNull());
5008
5009 const StorageLocation *BarRefLoc = Env.getStorageLocation(D: *BarRefDecl);
5010 ASSERT_THAT(BarRefLoc, NotNull());
5011
5012 const Value *QuxVal = Env.getValue(D: *QuxDecl);
5013 ASSERT_THAT(QuxVal, NotNull());
5014
5015 const StorageLocation *BoundFooRefLoc =
5016 Env.getStorageLocation(D: *BoundFooRefDecl);
5017 EXPECT_EQ(BoundFooRefLoc, FooRefLoc);
5018
5019 const StorageLocation *BoundBarRefLoc =
5020 Env.getStorageLocation(D: *BoundBarRefDecl);
5021 EXPECT_EQ(BoundBarRefLoc, BarRefLoc);
5022
5023 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal);
5024 });
5025}
5026
5027TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToInts) {
5028 std::string Code = R"(
5029 struct A {
5030 int Foo;
5031 int Bar;
5032 };
5033
5034 void target() {
5035 int Qux;
5036 A Baz;
5037 Baz.Foo = Qux;
5038 auto &FooRef = Baz.Foo;
5039 auto &BarRef = Baz.Bar;
5040 auto [BoundFoo, BoundBar] = Baz;
5041 // [[p]]
5042 }
5043 )";
5044 runDataflow(
5045 Code,
5046 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5047 ASTContext &ASTCtx) {
5048 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5049 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
5050
5051 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, Name: "FooRef");
5052 ASSERT_THAT(FooRefDecl, NotNull());
5053
5054 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, Name: "BarRef");
5055 ASSERT_THAT(BarRefDecl, NotNull());
5056
5057 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, Name: "BoundFoo");
5058 ASSERT_THAT(BoundFooDecl, NotNull());
5059
5060 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, Name: "BoundBar");
5061 ASSERT_THAT(BoundBarDecl, NotNull());
5062
5063 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, Name: "Qux");
5064 ASSERT_THAT(QuxDecl, NotNull());
5065
5066 const StorageLocation *FooRefLoc = Env.getStorageLocation(D: *FooRefDecl);
5067 ASSERT_THAT(FooRefLoc, NotNull());
5068
5069 const StorageLocation *BarRefLoc = Env.getStorageLocation(D: *BarRefDecl);
5070 ASSERT_THAT(BarRefLoc, NotNull());
5071
5072 const Value *QuxVal = Env.getValue(D: *QuxDecl);
5073 ASSERT_THAT(QuxVal, NotNull());
5074
5075 const StorageLocation *BoundFooLoc =
5076 Env.getStorageLocation(D: *BoundFooDecl);
5077 EXPECT_NE(BoundFooLoc, FooRefLoc);
5078
5079 const StorageLocation *BoundBarLoc =
5080 Env.getStorageLocation(D: *BoundBarDecl);
5081 EXPECT_NE(BoundBarLoc, BarRefLoc);
5082
5083 EXPECT_EQ(Env.getValue(*BoundFooDecl), QuxVal);
5084 });
5085}
5086
5087TEST(TransferTest, StructuredBindingAssignFromTupleLikeType) {
5088 std::string Code = R"(
5089 namespace std {
5090 using size_t = int;
5091 template <class> struct tuple_size;
5092 template <std::size_t, class> struct tuple_element;
5093 template <class...> class tuple;
5094
5095 namespace {
5096 template <class T, T v>
5097 struct size_helper { static const T value = v; };
5098 } // namespace
5099
5100 template <class... T>
5101 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {};
5102
5103 template <std::size_t I, class... T>
5104 struct tuple_element<I, tuple<T...>> {
5105 using type = __type_pack_element<I, T...>;
5106 };
5107
5108 template <class...> class tuple {};
5109
5110 template <std::size_t I, class... T>
5111 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
5112 } // namespace std
5113
5114 std::tuple<bool, int> makeTuple();
5115
5116 void target(bool B) {
5117 auto [BoundFoo, BoundBar] = makeTuple();
5118 bool Baz;
5119 // Include if-then-else to test interaction of `BindingDecl` with join.
5120 if (B) {
5121 Baz = BoundFoo;
5122 (void)BoundBar;
5123 // [[p1]]
5124 } else {
5125 Baz = BoundFoo;
5126 }
5127 (void)0;
5128 // [[p2]]
5129 }
5130 )";
5131 runDataflow(
5132 Code,
5133 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5134 ASTContext &ASTCtx) {
5135 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
5136 const Environment &Env1 = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p1");
5137
5138 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, Name: "BoundFoo");
5139 ASSERT_THAT(BoundFooDecl, NotNull());
5140
5141 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, Name: "BoundBar");
5142 ASSERT_THAT(BoundBarDecl, NotNull());
5143
5144 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
5145 ASSERT_THAT(BazDecl, NotNull());
5146
5147 // BindingDecls always map to references -- either lvalue or rvalue, so
5148 // we still need to skip here.
5149 const Value *BoundFooValue = Env1.getValue(D: *BoundFooDecl);
5150 ASSERT_THAT(BoundFooValue, NotNull());
5151 EXPECT_TRUE(isa<BoolValue>(BoundFooValue));
5152
5153 const Value *BoundBarValue = Env1.getValue(D: *BoundBarDecl);
5154 ASSERT_THAT(BoundBarValue, NotNull());
5155 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue));
5156
5157 // Test that a `DeclRefExpr` to a `BindingDecl` works as expected.
5158 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue);
5159
5160 const Environment &Env2 = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p2");
5161
5162 // Test that `BoundFooDecl` retains the value we expect, after the join.
5163 BoundFooValue = Env2.getValue(D: *BoundFooDecl);
5164 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue);
5165 });
5166}
5167
5168TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) {
5169 std::string Code = R"(
5170 namespace std {
5171 using size_t = int;
5172 template <class> struct tuple_size;
5173 template <std::size_t, class> struct tuple_element;
5174 template <class...> class tuple;
5175
5176 namespace {
5177 template <class T, T v>
5178 struct size_helper { static const T value = v; };
5179 } // namespace
5180
5181 template <class... T>
5182 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {};
5183
5184 template <std::size_t I, class... T>
5185 struct tuple_element<I, tuple<T...>> {
5186 using type = __type_pack_element<I, T...>;
5187 };
5188
5189 template <class...> class tuple {};
5190
5191 template <std::size_t I, class... T>
5192 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
5193 } // namespace std
5194
5195 std::tuple<bool, int> &getTuple();
5196
5197 void target(bool B) {
5198 auto &[BoundFoo, BoundBar] = getTuple();
5199 bool Baz;
5200 // Include if-then-else to test interaction of `BindingDecl` with join.
5201 if (B) {
5202 Baz = BoundFoo;
5203 (void)BoundBar;
5204 // [[p1]]
5205 } else {
5206 Baz = BoundFoo;
5207 }
5208 (void)0;
5209 // [[p2]]
5210 }
5211 )";
5212 runDataflow(
5213 Code,
5214 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5215 ASTContext &ASTCtx) {
5216 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
5217 const Environment &Env1 = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p1");
5218
5219 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, Name: "BoundFoo");
5220 ASSERT_THAT(BoundFooDecl, NotNull());
5221
5222 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, Name: "BoundBar");
5223 ASSERT_THAT(BoundBarDecl, NotNull());
5224
5225 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
5226 ASSERT_THAT(BazDecl, NotNull());
5227
5228 const Value *BoundFooValue = Env1.getValue(D: *BoundFooDecl);
5229 ASSERT_THAT(BoundFooValue, NotNull());
5230 EXPECT_TRUE(isa<BoolValue>(BoundFooValue));
5231
5232 const Value *BoundBarValue = Env1.getValue(D: *BoundBarDecl);
5233 ASSERT_THAT(BoundBarValue, NotNull());
5234 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue));
5235
5236 // Test that a `DeclRefExpr` to a `BindingDecl` (with reference type)
5237 // works as expected. We don't test aliasing properties of the
5238 // reference, because we don't model `std::get` and so have no way to
5239 // equate separate references into the tuple.
5240 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue);
5241
5242 const Environment &Env2 = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p2");
5243
5244 // Test that `BoundFooDecl` retains the value we expect, after the join.
5245 BoundFooValue = Env2.getValue(D: *BoundFooDecl);
5246 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue);
5247 });
5248}
5249
5250TEST(TransferTest, BinaryOperatorComma) {
5251 std::string Code = R"(
5252 void target(int Foo, int Bar) {
5253 int &Baz = (Foo, Bar);
5254 // [[p]]
5255 }
5256 )";
5257 runDataflow(
5258 Code,
5259 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5260 ASTContext &ASTCtx) {
5261 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5262 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
5263
5264 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
5265 ASSERT_THAT(BarDecl, NotNull());
5266
5267 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
5268 ASSERT_THAT(BazDecl, NotNull());
5269
5270 const StorageLocation *BarLoc = Env.getStorageLocation(D: *BarDecl);
5271 ASSERT_THAT(BarLoc, NotNull());
5272
5273 const StorageLocation *BazLoc = Env.getStorageLocation(D: *BazDecl);
5274 EXPECT_EQ(BazLoc, BarLoc);
5275 });
5276}
5277
5278TEST(TransferTest, ConditionalOperatorValue) {
5279 std::string Code = R"(
5280 void target(bool Cond, bool B1, bool B2) {
5281 bool JoinSame = Cond ? B1 : B1;
5282 bool JoinDifferent = Cond ? B1 : B2;
5283 // [[p]]
5284 }
5285 )";
5286 runDataflow(
5287 Code,
5288 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5289 ASTContext &ASTCtx) {
5290 Environment Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p").fork();
5291
5292 auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, Name: "B1");
5293 auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, Name: "B2");
5294 auto &JoinSame = getValueForDecl<BoolValue>(ASTCtx, Env, Name: "JoinSame");
5295 auto &JoinDifferent =
5296 getValueForDecl<BoolValue>(ASTCtx, Env, Name: "JoinDifferent");
5297
5298 EXPECT_EQ(&JoinSame, &B1);
5299
5300 const Formula &JoinDifferentEqB1 =
5301 Env.arena().makeEquals(LHS: JoinDifferent.formula(), RHS: B1.formula());
5302 EXPECT_TRUE(Env.allows(JoinDifferentEqB1));
5303 EXPECT_FALSE(Env.proves(JoinDifferentEqB1));
5304
5305 const Formula &JoinDifferentEqB2 =
5306 Env.arena().makeEquals(LHS: JoinDifferent.formula(), RHS: B2.formula());
5307 EXPECT_TRUE(Env.allows(JoinDifferentEqB2));
5308 EXPECT_FALSE(Env.proves(JoinDifferentEqB1));
5309 });
5310}
5311
5312TEST(TransferTest, ConditionalOperatorLocation) {
5313 std::string Code = R"(
5314 void target(bool Cond, int I1, int I2) {
5315 int &JoinSame = Cond ? I1 : I1;
5316 int &JoinDifferent = Cond ? I1 : I2;
5317 // [[p]]
5318 }
5319 )";
5320 runDataflow(
5321 Code,
5322 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5323 ASTContext &ASTCtx) {
5324 Environment Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p").fork();
5325
5326 StorageLocation &I1 = getLocForDecl(ASTCtx, Env, Name: "I1");
5327 StorageLocation &I2 = getLocForDecl(ASTCtx, Env, Name: "I2");
5328 StorageLocation &JoinSame = getLocForDecl(ASTCtx, Env, Name: "JoinSame");
5329 StorageLocation &JoinDifferent =
5330 getLocForDecl(ASTCtx, Env, Name: "JoinDifferent");
5331
5332 EXPECT_EQ(&JoinSame, &I1);
5333
5334 EXPECT_NE(&JoinDifferent, &I1);
5335 EXPECT_NE(&JoinDifferent, &I2);
5336 });
5337}
5338
5339TEST(TransferTest, IfStmtBranchExtendsFlowCondition) {
5340 std::string Code = R"(
5341 void target(bool Foo) {
5342 if (Foo) {
5343 (void)0;
5344 // [[if_then]]
5345 } else {
5346 (void)0;
5347 // [[if_else]]
5348 }
5349 }
5350 )";
5351 runDataflow(
5352 Code,
5353 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5354 ASTContext &ASTCtx) {
5355 ASSERT_THAT(Results.keys(), UnorderedElementsAre("if_then", "if_else"));
5356 const Environment &ThenEnv =
5357 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "if_then");
5358 const Environment &ElseEnv =
5359 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "if_else");
5360
5361 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
5362 ASSERT_THAT(FooDecl, NotNull());
5363
5364 auto &ThenFooVal= getFormula(D: *FooDecl, Env: ThenEnv);
5365 EXPECT_TRUE(ThenEnv.proves(ThenFooVal));
5366
5367 auto &ElseFooVal = getFormula(D: *FooDecl, Env: ElseEnv);
5368 EXPECT_TRUE(ElseEnv.proves(ElseEnv.arena().makeNot(ElseFooVal)));
5369 });
5370}
5371
5372TEST(TransferTest, WhileStmtBranchExtendsFlowCondition) {
5373 std::string Code = R"(
5374 void target(bool Foo) {
5375 while (Foo) {
5376 (void)0;
5377 // [[loop_body]]
5378 }
5379 (void)0;
5380 // [[after_loop]]
5381 }
5382 )";
5383 runDataflow(
5384 Code,
5385 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5386 ASTContext &ASTCtx) {
5387 ASSERT_THAT(Results.keys(),
5388 UnorderedElementsAre("loop_body", "after_loop"));
5389 const Environment &LoopBodyEnv =
5390 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "loop_body");
5391 const Environment &AfterLoopEnv =
5392 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "after_loop");
5393
5394 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
5395 ASSERT_THAT(FooDecl, NotNull());
5396
5397 auto &LoopBodyFooVal = getFormula(D: *FooDecl, Env: LoopBodyEnv);
5398 EXPECT_TRUE(LoopBodyEnv.proves(LoopBodyFooVal));
5399
5400 auto &AfterLoopFooVal = getFormula(D: *FooDecl, Env: AfterLoopEnv);
5401 EXPECT_TRUE(
5402 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal)));
5403 });
5404}
5405
5406TEST(TransferTest, DoWhileStmtBranchExtendsFlowCondition) {
5407 std::string Code = R"(
5408 void target(bool Foo) {
5409 bool Bar = true;
5410 do {
5411 (void)0;
5412 // [[loop_body]]
5413 Bar = false;
5414 } while (Foo);
5415 (void)0;
5416 // [[after_loop]]
5417 }
5418 )";
5419 runDataflow(
5420 Code,
5421 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5422 ASTContext &ASTCtx) {
5423 ASSERT_THAT(Results.keys(),
5424 UnorderedElementsAre("loop_body", "after_loop"));
5425 const Environment &LoopBodyEnv =
5426 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "loop_body");
5427 const Environment &AfterLoopEnv =
5428 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "after_loop");
5429 auto &A = AfterLoopEnv.arena();
5430
5431 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
5432 ASSERT_THAT(FooDecl, NotNull());
5433
5434 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
5435 ASSERT_THAT(BarDecl, NotNull());
5436
5437 auto &LoopBodyFooVal= getFormula(D: *FooDecl, Env: LoopBodyEnv);
5438 auto &LoopBodyBarVal = getFormula(D: *BarDecl, Env: LoopBodyEnv);
5439 EXPECT_TRUE(
5440 LoopBodyEnv.proves(A.makeOr(LoopBodyBarVal, LoopBodyFooVal)));
5441
5442 auto &AfterLoopFooVal = getFormula(D: *FooDecl, Env: AfterLoopEnv);
5443 auto &AfterLoopBarVal = getFormula(D: *BarDecl, Env: AfterLoopEnv);
5444 EXPECT_TRUE(AfterLoopEnv.proves(A.makeNot(AfterLoopFooVal)));
5445 EXPECT_TRUE(AfterLoopEnv.proves(A.makeNot(AfterLoopBarVal)));
5446 });
5447}
5448
5449TEST(TransferTest, ForStmtBranchExtendsFlowCondition) {
5450 std::string Code = R"(
5451 void target(bool Foo) {
5452 for (; Foo;) {
5453 (void)0;
5454 // [[loop_body]]
5455 }
5456 (void)0;
5457 // [[after_loop]]
5458 }
5459 )";
5460 runDataflow(
5461 Code,
5462 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5463 ASTContext &ASTCtx) {
5464 ASSERT_THAT(Results.keys(),
5465 UnorderedElementsAre("loop_body", "after_loop"));
5466 const Environment &LoopBodyEnv =
5467 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "loop_body");
5468 const Environment &AfterLoopEnv =
5469 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "after_loop");
5470
5471 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
5472 ASSERT_THAT(FooDecl, NotNull());
5473
5474 auto &LoopBodyFooVal= getFormula(D: *FooDecl, Env: LoopBodyEnv);
5475 EXPECT_TRUE(LoopBodyEnv.proves(LoopBodyFooVal));
5476
5477 auto &AfterLoopFooVal = getFormula(D: *FooDecl, Env: AfterLoopEnv);
5478 EXPECT_TRUE(
5479 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal)));
5480 });
5481}
5482
5483TEST(TransferTest, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition) {
5484 std::string Code = R"(
5485 void target(bool Foo) {
5486 for (;;) {
5487 (void)0;
5488 // [[loop_body]]
5489 }
5490 }
5491 )";
5492 runDataflow(
5493 Code,
5494 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5495 ASTContext &ASTCtx) {
5496 ASSERT_THAT(Results.keys(), UnorderedElementsAre("loop_body"));
5497 const Environment &LoopBodyEnv =
5498 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "loop_body");
5499
5500 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
5501 ASSERT_THAT(FooDecl, NotNull());
5502
5503 auto &LoopBodyFooVal= getFormula(D: *FooDecl, Env: LoopBodyEnv);
5504 EXPECT_FALSE(LoopBodyEnv.proves(LoopBodyFooVal));
5505 });
5506}
5507
5508TEST(TransferTest, ContextSensitiveOptionDisabled) {
5509 std::string Code = R"(
5510 bool GiveBool();
5511 void SetBool(bool &Var) { Var = true; }
5512
5513 void target() {
5514 bool Foo = GiveBool();
5515 SetBool(Foo);
5516 // [[p]]
5517 }
5518 )";
5519 runDataflow(
5520 Code,
5521 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5522 ASTContext &ASTCtx) {
5523 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5524 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
5525
5526 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
5527 ASSERT_THAT(FooDecl, NotNull());
5528
5529 auto &FooVal = getFormula(D: *FooDecl, Env);
5530 EXPECT_FALSE(Env.proves(FooVal));
5531 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));
5532 },
5533 Options: {.BuiltinOpts: BuiltinOptions{/*.ContextSensitiveOpts=*/std::nullopt}});
5534}
5535
5536TEST(TransferTest, ContextSensitiveReturnReference) {
5537 std::string Code = R"(
5538 class S {};
5539 S& target(bool b, S &s) {
5540 return s;
5541 // [[p]]
5542 }
5543 )";
5544 runDataflow(
5545 Code,
5546 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5547 ASTContext &ASTCtx) {
5548 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
5549
5550 const ValueDecl *SDecl = findValueDecl(ASTCtx, Name: "s");
5551 ASSERT_THAT(SDecl, NotNull());
5552
5553 auto *SLoc = Env.getStorageLocation(D: *SDecl);
5554 ASSERT_THAT(SLoc, NotNull());
5555
5556 ASSERT_THAT(Env.getReturnStorageLocation(), Eq(SLoc));
5557 },
5558 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
5559}
5560
5561// This test is a regression test, based on a real crash.
5562TEST(TransferTest, ContextSensitiveReturnReferenceWithConditionalOperator) {
5563 std::string Code = R"(
5564 class S {};
5565 S& target(bool b, S &s) {
5566 return b ? s : s;
5567 // [[p]]
5568 }
5569 )";
5570 runDataflow(
5571 Code,
5572 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5573 ASTContext &ASTCtx) {
5574 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5575 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
5576
5577 const ValueDecl *SDecl = findValueDecl(ASTCtx, Name: "s");
5578 ASSERT_THAT(SDecl, NotNull());
5579
5580 auto *SLoc = Env.getStorageLocation(D: *SDecl);
5581 EXPECT_THAT(SLoc, NotNull());
5582
5583 auto *Loc = Env.getReturnStorageLocation();
5584 EXPECT_THAT(Loc, NotNull());
5585
5586 EXPECT_EQ(Loc, SLoc);
5587 },
5588 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
5589}
5590
5591TEST(TransferTest, ContextSensitiveReturnOneOfTwoReferences) {
5592 std::string Code = R"(
5593 class S {};
5594 S &callee(bool b, S &s1_parm, S &s2_parm) {
5595 if (b)
5596 return s1_parm;
5597 else
5598 return s2_parm;
5599 }
5600 void target(bool b) {
5601 S s1;
5602 S s2;
5603 S &return_s1 = s1;
5604 S &return_s2 = s2;
5605 S &return_dont_know = callee(b, s1, s2);
5606 // [[p]]
5607 }
5608 )";
5609 runDataflow(
5610 Code,
5611 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5612 ASTContext &ASTCtx) {
5613 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
5614
5615 const ValueDecl *S1 = findValueDecl(ASTCtx, Name: "s1");
5616 ASSERT_THAT(S1, NotNull());
5617 const ValueDecl *S2 = findValueDecl(ASTCtx, Name: "s2");
5618 ASSERT_THAT(S2, NotNull());
5619 const ValueDecl *ReturnS1 = findValueDecl(ASTCtx, Name: "return_s1");
5620 ASSERT_THAT(ReturnS1, NotNull());
5621 const ValueDecl *ReturnS2 = findValueDecl(ASTCtx, Name: "return_s2");
5622 ASSERT_THAT(ReturnS2, NotNull());
5623 const ValueDecl *ReturnDontKnow =
5624 findValueDecl(ASTCtx, Name: "return_dont_know");
5625 ASSERT_THAT(ReturnDontKnow, NotNull());
5626
5627 StorageLocation *S1Loc = Env.getStorageLocation(D: *S1);
5628 StorageLocation *S2Loc = Env.getStorageLocation(D: *S2);
5629
5630 EXPECT_THAT(Env.getStorageLocation(*ReturnS1), Eq(S1Loc));
5631 EXPECT_THAT(Env.getStorageLocation(*ReturnS2), Eq(S2Loc));
5632
5633 // In the case where we don't have a consistent storage location for
5634 // the return value, the framework creates a new storage location, which
5635 // should be different from the storage locations of `s1` and `s2`.
5636 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S1Loc));
5637 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S2Loc));
5638 },
5639 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
5640}
5641
5642TEST(TransferTest, ContextSensitiveDepthZero) {
5643 std::string Code = R"(
5644 bool GiveBool();
5645 void SetBool(bool &Var) { Var = true; }
5646
5647 void target() {
5648 bool Foo = GiveBool();
5649 SetBool(Foo);
5650 // [[p]]
5651 }
5652 )";
5653 runDataflow(
5654 Code,
5655 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5656 ASTContext &ASTCtx) {
5657 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5658 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
5659
5660 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
5661 ASSERT_THAT(FooDecl, NotNull());
5662
5663 auto &FooVal = getFormula(D: *FooDecl, Env);
5664 EXPECT_FALSE(Env.proves(FooVal));
5665 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));
5666 },
5667 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{/*.Depth=*/0}}});
5668}
5669
5670TEST(TransferTest, ContextSensitiveSetTrue) {
5671 std::string Code = R"(
5672 bool GiveBool();
5673 void SetBool(bool &Var) { Var = true; }
5674
5675 void target() {
5676 bool Foo = GiveBool();
5677 SetBool(Foo);
5678 // [[p]]
5679 }
5680 )";
5681 runDataflow(
5682 Code,
5683 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5684 ASTContext &ASTCtx) {
5685 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5686 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
5687
5688 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
5689 ASSERT_THAT(FooDecl, NotNull());
5690
5691 auto &FooVal = getFormula(D: *FooDecl, Env);
5692 EXPECT_TRUE(Env.proves(FooVal));
5693 },
5694 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
5695}
5696
5697TEST(TransferTest, ContextSensitiveSetFalse) {
5698 std::string Code = R"(
5699 bool GiveBool();
5700 void SetBool(bool &Var) { Var = false; }
5701
5702 void target() {
5703 bool Foo = GiveBool();
5704 SetBool(Foo);
5705 // [[p]]
5706 }
5707 )";
5708 runDataflow(
5709 Code,
5710 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5711 ASTContext &ASTCtx) {
5712 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5713 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
5714
5715 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
5716 ASSERT_THAT(FooDecl, NotNull());
5717
5718 auto &FooVal = getFormula(D: *FooDecl, Env);
5719 EXPECT_TRUE(Env.proves(Env.arena().makeNot(FooVal)));
5720 },
5721 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
5722}
5723
5724TEST(TransferTest, ContextSensitiveSetBothTrueAndFalse) {
5725 std::string Code = R"(
5726 bool GiveBool();
5727 void SetBool(bool &Var, bool Val) { Var = Val; }
5728
5729 void target() {
5730 bool Foo = GiveBool();
5731 bool Bar = GiveBool();
5732 SetBool(Foo, true);
5733 SetBool(Bar, false);
5734 // [[p]]
5735 }
5736 )";
5737 runDataflow(
5738 Code,
5739 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5740 ASTContext &ASTCtx) {
5741 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5742 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
5743 auto &A = Env.arena();
5744
5745 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
5746 ASSERT_THAT(FooDecl, NotNull());
5747
5748 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
5749 ASSERT_THAT(BarDecl, NotNull());
5750
5751 auto &FooVal = getFormula(D: *FooDecl, Env);
5752 EXPECT_TRUE(Env.proves(FooVal));
5753 EXPECT_FALSE(Env.proves(A.makeNot(FooVal)));
5754
5755 auto &BarVal = getFormula(D: *BarDecl, Env);
5756 EXPECT_FALSE(Env.proves(BarVal));
5757 EXPECT_TRUE(Env.proves(A.makeNot(BarVal)));
5758 },
5759 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
5760}
5761
5762TEST(TransferTest, ContextSensitiveSetTwoLayersDepthOne) {
5763 std::string Code = R"(
5764 bool GiveBool();
5765 void SetBool1(bool &Var) { Var = true; }
5766 void SetBool2(bool &Var) { SetBool1(Var); }
5767
5768 void target() {
5769 bool Foo = GiveBool();
5770 SetBool2(Foo);
5771 // [[p]]
5772 }
5773 )";
5774 runDataflow(
5775 Code,
5776 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5777 ASTContext &ASTCtx) {
5778 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5779 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
5780
5781 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
5782 ASSERT_THAT(FooDecl, NotNull());
5783
5784 auto &FooVal = getFormula(D: *FooDecl, Env);
5785 EXPECT_FALSE(Env.proves(FooVal));
5786 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));
5787 },
5788 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{/*.Depth=*/1}}});
5789}
5790
5791TEST(TransferTest, ContextSensitiveSetTwoLayersDepthTwo) {
5792 std::string Code = R"(
5793 bool GiveBool();
5794 void SetBool1(bool &Var) { Var = true; }
5795 void SetBool2(bool &Var) { SetBool1(Var); }
5796
5797 void target() {
5798 bool Foo = GiveBool();
5799 SetBool2(Foo);
5800 // [[p]]
5801 }
5802 )";
5803 runDataflow(
5804 Code,
5805 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5806 ASTContext &ASTCtx) {
5807 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5808 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
5809
5810 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
5811 ASSERT_THAT(FooDecl, NotNull());
5812
5813 auto &FooVal = getFormula(D: *FooDecl, Env);
5814 EXPECT_TRUE(Env.proves(FooVal));
5815 },
5816 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{/*.Depth=*/2}}});
5817}
5818
5819TEST(TransferTest, ContextSensitiveSetThreeLayersDepthTwo) {
5820 std::string Code = R"(
5821 bool GiveBool();
5822 void SetBool1(bool &Var) { Var = true; }
5823 void SetBool2(bool &Var) { SetBool1(Var); }
5824 void SetBool3(bool &Var) { SetBool2(Var); }
5825
5826 void target() {
5827 bool Foo = GiveBool();
5828 SetBool3(Foo);
5829 // [[p]]
5830 }
5831 )";
5832 runDataflow(
5833 Code,
5834 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5835 ASTContext &ASTCtx) {
5836 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5837 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
5838
5839 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
5840 ASSERT_THAT(FooDecl, NotNull());
5841
5842 auto &FooVal = getFormula(D: *FooDecl, Env);
5843 EXPECT_FALSE(Env.proves(FooVal));
5844 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));
5845 },
5846 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{/*.Depth=*/2}}});
5847}
5848
5849TEST(TransferTest, ContextSensitiveSetThreeLayersDepthThree) {
5850 std::string Code = R"(
5851 bool GiveBool();
5852 void SetBool1(bool &Var) { Var = true; }
5853 void SetBool2(bool &Var) { SetBool1(Var); }
5854 void SetBool3(bool &Var) { SetBool2(Var); }
5855
5856 void target() {
5857 bool Foo = GiveBool();
5858 SetBool3(Foo);
5859 // [[p]]
5860 }
5861 )";
5862 runDataflow(
5863 Code,
5864 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5865 ASTContext &ASTCtx) {
5866 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5867 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
5868
5869 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
5870 ASSERT_THAT(FooDecl, NotNull());
5871
5872 auto &FooVal = getFormula(D: *FooDecl, Env);
5873 EXPECT_TRUE(Env.proves(FooVal));
5874 },
5875 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{/*.Depth=*/3}}});
5876}
5877
5878TEST(TransferTest, ContextSensitiveMutualRecursion) {
5879 std::string Code = R"(
5880 bool Pong(bool X, bool Y);
5881
5882 bool Ping(bool X, bool Y) {
5883 if (X) {
5884 return Y;
5885 } else {
5886 return Pong(!X, Y);
5887 }
5888 }
5889
5890 bool Pong(bool X, bool Y) {
5891 if (Y) {
5892 return X;
5893 } else {
5894 return Ping(X, !Y);
5895 }
5896 }
5897
5898 void target() {
5899 bool Foo = Ping(false, false);
5900 // [[p]]
5901 }
5902 )";
5903 runDataflow(
5904 Code,
5905 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5906 ASTContext &ASTCtx) {
5907 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5908 // The analysis doesn't crash...
5909 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
5910
5911 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
5912 ASSERT_THAT(FooDecl, NotNull());
5913
5914 auto &FooVal = getFormula(D: *FooDecl, Env);
5915 // ... but it also can't prove anything here.
5916 EXPECT_FALSE(Env.proves(FooVal));
5917 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));
5918 },
5919 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{/*.Depth=*/4}}});
5920}
5921
5922TEST(TransferTest, ContextSensitiveSetMultipleLines) {
5923 std::string Code = R"(
5924 void SetBools(bool &Var1, bool &Var2) {
5925 Var1 = true;
5926 Var2 = false;
5927 }
5928
5929 void target() {
5930 bool Foo = false;
5931 bool Bar = true;
5932 SetBools(Foo, Bar);
5933 // [[p]]
5934 }
5935 )";
5936 runDataflow(
5937 Code,
5938 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5939 ASTContext &ASTCtx) {
5940 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5941 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
5942
5943 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
5944 ASSERT_THAT(FooDecl, NotNull());
5945
5946 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
5947 ASSERT_THAT(BarDecl, NotNull());
5948
5949 auto &FooVal = getFormula(D: *FooDecl, Env);
5950 EXPECT_TRUE(Env.proves(FooVal));
5951 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));
5952
5953 auto &BarVal = getFormula(D: *BarDecl, Env);
5954 EXPECT_FALSE(Env.proves(BarVal));
5955 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal)));
5956 },
5957 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
5958}
5959
5960TEST(TransferTest, ContextSensitiveSetMultipleBlocks) {
5961 std::string Code = R"(
5962 void IfCond(bool Cond, bool &Then, bool &Else) {
5963 if (Cond) {
5964 Then = true;
5965 } else {
5966 Else = true;
5967 }
5968 }
5969
5970 void target() {
5971 bool Foo = false;
5972 bool Bar = false;
5973 bool Baz = false;
5974 IfCond(Foo, Bar, Baz);
5975 // [[p]]
5976 }
5977 )";
5978 runDataflow(
5979 Code,
5980 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5981 ASTContext &ASTCtx) {
5982 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5983 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
5984
5985 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
5986 ASSERT_THAT(BarDecl, NotNull());
5987
5988 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
5989 ASSERT_THAT(BazDecl, NotNull());
5990
5991 auto &BarVal = getFormula(D: *BarDecl, Env);
5992 EXPECT_FALSE(Env.proves(BarVal));
5993 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal)));
5994
5995 auto &BazVal = getFormula(D: *BazDecl, Env);
5996 EXPECT_TRUE(Env.proves(BazVal));
5997 EXPECT_FALSE(Env.proves(Env.arena().makeNot(BazVal)));
5998 },
5999 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
6000}
6001
6002TEST(TransferTest, ContextSensitiveReturnVoid) {
6003 std::string Code = R"(
6004 void Noop() { return; }
6005
6006 void target() {
6007 Noop();
6008 // [[p]]
6009 }
6010 )";
6011 runDataflow(
6012 Code,
6013 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6014 ASTContext &ASTCtx) {
6015 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6016 // This just tests that the analysis doesn't crash.
6017 },
6018 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
6019}
6020
6021TEST(TransferTest, ContextSensitiveReturnTrue) {
6022 std::string Code = R"(
6023 bool GiveBool() { return true; }
6024
6025 void target() {
6026 bool Foo = GiveBool();
6027 // [[p]]
6028 }
6029 )";
6030 runDataflow(
6031 Code,
6032 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6033 ASTContext &ASTCtx) {
6034 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6035 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6036
6037 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
6038 ASSERT_THAT(FooDecl, NotNull());
6039
6040 auto &FooVal = getFormula(D: *FooDecl, Env);
6041 EXPECT_TRUE(Env.proves(FooVal));
6042 },
6043 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
6044}
6045
6046TEST(TransferTest, ContextSensitiveReturnFalse) {
6047 std::string Code = R"(
6048 bool GiveBool() { return false; }
6049
6050 void target() {
6051 bool Foo = GiveBool();
6052 // [[p]]
6053 }
6054 )";
6055 runDataflow(
6056 Code,
6057 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6058 ASTContext &ASTCtx) {
6059 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6060 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6061
6062 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
6063 ASSERT_THAT(FooDecl, NotNull());
6064
6065 auto &FooVal = getFormula(D: *FooDecl, Env);
6066 EXPECT_TRUE(Env.proves(Env.arena().makeNot(FooVal)));
6067 },
6068 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
6069}
6070
6071TEST(TransferTest, ContextSensitiveReturnArg) {
6072 std::string Code = R"(
6073 bool GiveBool();
6074 bool GiveBack(bool Arg) { return Arg; }
6075
6076 void target() {
6077 bool Foo = GiveBool();
6078 bool Bar = GiveBack(Foo);
6079 bool Baz = Foo == Bar;
6080 // [[p]]
6081 }
6082 )";
6083 runDataflow(
6084 Code,
6085 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6086 ASTContext &ASTCtx) {
6087 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6088 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6089
6090 const ValueDecl *BazDecl = findValueDecl(ASTCtx, Name: "Baz");
6091 ASSERT_THAT(BazDecl, NotNull());
6092
6093 auto &BazVal = getFormula(D: *BazDecl, Env);
6094 EXPECT_TRUE(Env.proves(BazVal));
6095 },
6096 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
6097}
6098
6099TEST(TransferTest, ContextSensitiveReturnInt) {
6100 std::string Code = R"(
6101 int identity(int x) { return x; }
6102
6103 void target() {
6104 int y = identity(42);
6105 // [[p]]
6106 }
6107 )";
6108 runDataflow(
6109 Code,
6110 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6111 ASTContext &ASTCtx) {
6112 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6113 // This just tests that the analysis doesn't crash.
6114 },
6115 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
6116}
6117
6118TEST(TransferTest, ContextSensitiveReturnRecord) {
6119 std::string Code = R"(
6120 struct S {
6121 bool B;
6122 };
6123
6124 S makeS(bool BVal) { return {BVal}; }
6125
6126 void target() {
6127 S FalseS = makeS(false);
6128 S TrueS = makeS(true);
6129 // [[p]]
6130 }
6131 )";
6132 runDataflow(
6133 Code,
6134 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6135 ASTContext &ASTCtx) {
6136 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6137
6138 auto &FalseSLoc =
6139 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, Name: "FalseS");
6140 auto &TrueSLoc =
6141 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, Name: "TrueS");
6142
6143 EXPECT_EQ(getFieldValue(&FalseSLoc, "B", ASTCtx, Env),
6144 &Env.getBoolLiteralValue(false));
6145 EXPECT_EQ(getFieldValue(&TrueSLoc, "B", ASTCtx, Env),
6146 &Env.getBoolLiteralValue(true));
6147 },
6148 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
6149}
6150
6151TEST(TransferTest, ContextSensitiveReturnSelfReferentialRecord) {
6152 std::string Code = R"(
6153 struct S {
6154 S() { self = this; }
6155 S *self;
6156 };
6157
6158 S makeS() {
6159 // RVO guarantees that this will be constructed directly into `MyS`.
6160 return S();
6161 }
6162
6163 void target() {
6164 S MyS = makeS();
6165 // [[p]]
6166 }
6167 )";
6168 runDataflow(
6169 Code,
6170 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6171 ASTContext &ASTCtx) {
6172 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6173
6174 auto &MySLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, Name: "MyS");
6175
6176 auto *SelfVal =
6177 cast<PointerValue>(Val: getFieldValue(Loc: &MySLoc, Name: "self", ASTCtx, Env));
6178 EXPECT_EQ(&SelfVal->getPointeeLoc(), &MySLoc);
6179 },
6180 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
6181}
6182
6183TEST(TransferTest, ContextSensitiveMethodLiteral) {
6184 std::string Code = R"(
6185 class MyClass {
6186 public:
6187 bool giveBool() { return true; }
6188 };
6189
6190 void target() {
6191 MyClass MyObj;
6192 bool Foo = MyObj.giveBool();
6193 // [[p]]
6194 }
6195 )";
6196 runDataflow(
6197 Code,
6198 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6199 ASTContext &ASTCtx) {
6200 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6201 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6202
6203 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
6204 ASSERT_THAT(FooDecl, NotNull());
6205
6206 auto &FooVal = getFormula(D: *FooDecl, Env);
6207 EXPECT_TRUE(Env.proves(FooVal));
6208 },
6209 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
6210}
6211
6212TEST(TransferTest, ContextSensitiveMethodGetter) {
6213 std::string Code = R"(
6214 class MyClass {
6215 public:
6216 bool getField() { return Field; }
6217
6218 bool Field;
6219 };
6220
6221 void target() {
6222 MyClass MyObj;
6223 MyObj.Field = true;
6224 bool Foo = MyObj.getField();
6225 // [[p]]
6226 }
6227 )";
6228 runDataflow(
6229 Code,
6230 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6231 ASTContext &ASTCtx) {
6232 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6233 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6234
6235 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
6236 ASSERT_THAT(FooDecl, NotNull());
6237
6238 auto &FooVal = getFormula(D: *FooDecl, Env);
6239 EXPECT_TRUE(Env.proves(FooVal));
6240 },
6241 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
6242}
6243
6244TEST(TransferTest, ContextSensitiveMethodSetter) {
6245 std::string Code = R"(
6246 class MyClass {
6247 public:
6248 void setField(bool Val) { Field = Val; }
6249
6250 bool Field;
6251 };
6252
6253 void target() {
6254 MyClass MyObj;
6255 MyObj.setField(true);
6256 bool Foo = MyObj.Field;
6257 // [[p]]
6258 }
6259 )";
6260 runDataflow(
6261 Code,
6262 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6263 ASTContext &ASTCtx) {
6264 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6265 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6266
6267 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
6268 ASSERT_THAT(FooDecl, NotNull());
6269
6270 auto &FooVal = getFormula(D: *FooDecl, Env);
6271 EXPECT_TRUE(Env.proves(FooVal));
6272 },
6273 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
6274}
6275
6276TEST(TransferTest, ContextSensitiveMethodGetterAndSetter) {
6277 std::string Code = R"(
6278 class MyClass {
6279 public:
6280 bool getField() { return Field; }
6281 void setField(bool Val) { Field = Val; }
6282
6283 private:
6284 bool Field;
6285 };
6286
6287 void target() {
6288 MyClass MyObj;
6289 MyObj.setField(true);
6290 bool Foo = MyObj.getField();
6291 // [[p]]
6292 }
6293 )";
6294 runDataflow(
6295 Code,
6296 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6297 ASTContext &ASTCtx) {
6298 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6299 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6300
6301 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
6302 ASSERT_THAT(FooDecl, NotNull());
6303
6304 auto &FooVal = getFormula(D: *FooDecl, Env);
6305 EXPECT_TRUE(Env.proves(FooVal));
6306 },
6307 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
6308}
6309
6310
6311TEST(TransferTest, ContextSensitiveMethodTwoLayersVoid) {
6312 std::string Code = R"(
6313 class MyClass {
6314 public:
6315 void Inner() { MyField = true; }
6316 void Outer() { Inner(); }
6317
6318 bool MyField;
6319 };
6320
6321 void target() {
6322 MyClass MyObj;
6323 MyObj.Outer();
6324 bool Foo = MyObj.MyField;
6325 // [[p]]
6326 }
6327 )";
6328 runDataflow(
6329 Code,
6330 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6331 ASTContext &ASTCtx) {
6332 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6333 ;
6334 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6335
6336 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
6337 ASSERT_THAT(FooDecl, NotNull());
6338
6339 auto &FooVal = getFormula(D: *FooDecl, Env);
6340 EXPECT_TRUE(Env.proves(FooVal));
6341 },
6342 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
6343}
6344
6345TEST(TransferTest, ContextSensitiveMethodTwoLayersReturn) {
6346 std::string Code = R"(
6347 class MyClass {
6348 public:
6349 bool Inner() { return MyField; }
6350 bool Outer() { return Inner(); }
6351
6352 bool MyField;
6353 };
6354
6355 void target() {
6356 MyClass MyObj;
6357 MyObj.MyField = true;
6358 bool Foo = MyObj.Outer();
6359 // [[p]]
6360 }
6361 )";
6362 runDataflow(
6363 Code,
6364 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6365 ASTContext &ASTCtx) {
6366 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6367 ;
6368 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6369
6370 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
6371 ASSERT_THAT(FooDecl, NotNull());
6372
6373 auto &FooVal = getFormula(D: *FooDecl, Env);
6374 EXPECT_TRUE(Env.proves(FooVal));
6375 },
6376 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
6377}
6378
6379TEST(TransferTest, ContextSensitiveConstructorBody) {
6380 std::string Code = R"(
6381 class MyClass {
6382 public:
6383 MyClass() { MyField = true; }
6384
6385 bool MyField;
6386 };
6387
6388 void target() {
6389 MyClass MyObj;
6390 bool Foo = MyObj.MyField;
6391 // [[p]]
6392 }
6393 )";
6394 runDataflow(
6395 Code,
6396 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6397 ASTContext &ASTCtx) {
6398 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6399 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6400
6401 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
6402 ASSERT_THAT(FooDecl, NotNull());
6403
6404 auto &FooVal = getFormula(D: *FooDecl, Env);
6405 EXPECT_TRUE(Env.proves(FooVal));
6406 },
6407 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
6408}
6409
6410TEST(TransferTest, ContextSensitiveConstructorInitializer) {
6411 std::string Code = R"(
6412 class MyClass {
6413 public:
6414 MyClass() : MyField(true) {}
6415
6416 bool MyField;
6417 };
6418
6419 void target() {
6420 MyClass MyObj;
6421 bool Foo = MyObj.MyField;
6422 // [[p]]
6423 }
6424 )";
6425 runDataflow(
6426 Code,
6427 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6428 ASTContext &ASTCtx) {
6429 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6430 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6431
6432 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
6433 ASSERT_THAT(FooDecl, NotNull());
6434
6435 auto &FooVal = getFormula(D: *FooDecl, Env);
6436 EXPECT_TRUE(Env.proves(FooVal));
6437 },
6438 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
6439}
6440
6441TEST(TransferTest, ContextSensitiveConstructorDefault) {
6442 std::string Code = R"(
6443 class MyClass {
6444 public:
6445 MyClass() = default;
6446
6447 bool MyField = true;
6448 };
6449
6450 void target() {
6451 MyClass MyObj;
6452 bool Foo = MyObj.MyField;
6453 // [[p]]
6454 }
6455 )";
6456 runDataflow(
6457 Code,
6458 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6459 ASTContext &ASTCtx) {
6460 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6461 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6462
6463 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
6464 ASSERT_THAT(FooDecl, NotNull());
6465
6466 auto &FooVal = getFormula(D: *FooDecl, Env);
6467 EXPECT_TRUE(Env.proves(FooVal));
6468 },
6469 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
6470}
6471
6472TEST(TransferTest, ContextSensitiveSelfReferentialClass) {
6473 // Test that the `this` pointer seen in the constructor has the same value
6474 // as the address of the variable the object is constructed into.
6475 std::string Code = R"(
6476 class MyClass {
6477 public:
6478 MyClass() : Self(this) {}
6479 MyClass *Self;
6480 };
6481
6482 void target() {
6483 MyClass MyObj;
6484 MyClass *SelfPtr = MyObj.Self;
6485 // [[p]]
6486 }
6487 )";
6488 runDataflow(
6489 Code,
6490 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6491 ASTContext &ASTCtx) {
6492 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6493
6494 const ValueDecl *MyObjDecl = findValueDecl(ASTCtx, Name: "MyObj");
6495 ASSERT_THAT(MyObjDecl, NotNull());
6496
6497 const ValueDecl *SelfDecl = findValueDecl(ASTCtx, Name: "SelfPtr");
6498 ASSERT_THAT(SelfDecl, NotNull());
6499
6500 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6501 auto &SelfVal = *cast<PointerValue>(Val: Env.getValue(D: *SelfDecl));
6502 EXPECT_EQ(Env.getStorageLocation(*MyObjDecl), &SelfVal.getPointeeLoc());
6503 },
6504 Options: {.BuiltinOpts: BuiltinOptions{.ContextSensitiveOpts: ContextSensitiveOptions{}}});
6505}
6506
6507TEST(TransferTest, UnnamedBitfieldInitializer) {
6508 std::string Code = R"(
6509 struct B {};
6510 struct A {
6511 unsigned a;
6512 unsigned : 4;
6513 unsigned c;
6514 B b;
6515 };
6516 void target() {
6517 A a = {};
6518 A test = a;
6519 (void)test.c;
6520 }
6521 )";
6522 runDataflow(
6523 Code,
6524 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6525 ASTContext &ASTCtx) {
6526 // This doesn't need a body because this test was crashing the framework
6527 // before handling correctly Unnamed bitfields in `InitListExpr`.
6528 });
6529}
6530
6531// Repro for a crash that used to occur with chained short-circuiting logical
6532// operators.
6533TEST(TransferTest, ChainedLogicalOps) {
6534 std::string Code = R"(
6535 bool target() {
6536 bool b = true || false || false || false;
6537 // [[p]]
6538 return b;
6539 }
6540 )";
6541 runDataflow(
6542 Code,
6543 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6544 ASTContext &ASTCtx) {
6545 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6546 auto &B = getValueForDecl<BoolValue>(ASTCtx, Env, Name: "b").formula();
6547 EXPECT_TRUE(Env.proves(B));
6548 });
6549}
6550
6551// Repro for a crash that used to occur when we call a `noreturn` function
6552// within one of the operands of a `&&` or `||` operator.
6553TEST(TransferTest, NoReturnFunctionInsideShortCircuitedBooleanOp) {
6554 std::string Code = R"(
6555 __attribute__((noreturn)) int doesnt_return();
6556 bool some_condition();
6557 void target(bool b1, bool b2) {
6558 // Neither of these should crash. In addition, if we don't terminate the
6559 // program, we know that the operators need to trigger the short-circuit
6560 // logic, so `NoreturnOnRhsOfAnd` will be false and `NoreturnOnRhsOfOr`
6561 // will be true.
6562 bool NoreturnOnRhsOfAnd = b1 && doesnt_return() > 0;
6563 bool NoreturnOnRhsOfOr = b2 || doesnt_return() > 0;
6564
6565 // Calling a `noreturn` function on the LHS of an `&&` or `||` makes the
6566 // entire expression unreachable. So we know that in both of the following
6567 // cases, if `target()` terminates, the `else` branch was taken.
6568 bool NoreturnOnLhsMakesAndUnreachable = false;
6569 if (some_condition())
6570 doesnt_return() > 0 && some_condition();
6571 else
6572 NoreturnOnLhsMakesAndUnreachable = true;
6573
6574 bool NoreturnOnLhsMakesOrUnreachable = false;
6575 if (some_condition())
6576 doesnt_return() > 0 || some_condition();
6577 else
6578 NoreturnOnLhsMakesOrUnreachable = true;
6579
6580 // [[p]]
6581 }
6582 )";
6583 runDataflow(
6584 Code,
6585 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6586 ASTContext &ASTCtx) {
6587 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6588 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6589 auto &A = Env.arena();
6590
6591 // Check that [[p]] is reachable with a non-false flow condition.
6592 EXPECT_FALSE(Env.proves(A.makeLiteral(false)));
6593
6594 auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, Name: "b1").formula();
6595 EXPECT_TRUE(Env.proves(A.makeNot(B1)));
6596
6597 auto &NoreturnOnRhsOfAnd =
6598 getValueForDecl<BoolValue>(ASTCtx, Env, Name: "NoreturnOnRhsOfAnd").formula();
6599 EXPECT_TRUE(Env.proves(A.makeNot(NoreturnOnRhsOfAnd)));
6600
6601 auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, Name: "b2").formula();
6602 EXPECT_TRUE(Env.proves(B2));
6603
6604 auto &NoreturnOnRhsOfOr =
6605 getValueForDecl<BoolValue>(ASTCtx, Env, Name: "NoreturnOnRhsOfOr")
6606 .formula();
6607 EXPECT_TRUE(Env.proves(NoreturnOnRhsOfOr));
6608
6609 auto &NoreturnOnLhsMakesAndUnreachable = getValueForDecl<BoolValue>(
6610 ASTCtx, Env, Name: "NoreturnOnLhsMakesAndUnreachable").formula();
6611 EXPECT_TRUE(Env.proves(NoreturnOnLhsMakesAndUnreachable));
6612
6613 auto &NoreturnOnLhsMakesOrUnreachable = getValueForDecl<BoolValue>(
6614 ASTCtx, Env, Name: "NoreturnOnLhsMakesOrUnreachable").formula();
6615 EXPECT_TRUE(Env.proves(NoreturnOnLhsMakesOrUnreachable));
6616 });
6617}
6618
6619TEST(TransferTest, NewExpressions) {
6620 std::string Code = R"(
6621 void target() {
6622 int *p = new int(42);
6623 // [[after_new]]
6624 }
6625 )";
6626 runDataflow(
6627 Code,
6628 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6629 ASTContext &ASTCtx) {
6630 const Environment &Env =
6631 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "after_new");
6632
6633 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, Name: "p");
6634
6635 EXPECT_THAT(Env.getValue(P.getPointeeLoc()), NotNull());
6636 });
6637}
6638
6639TEST(TransferTest, NewExpressions_Structs) {
6640 std::string Code = R"(
6641 struct Inner {
6642 int InnerField;
6643 };
6644
6645 struct Outer {
6646 Inner OuterField;
6647 };
6648
6649 void target() {
6650 Outer *p = new Outer;
6651 // Access the fields to make sure the analysis actually generates children
6652 // for them in the `RecordStorageLocation`.
6653 p->OuterField.InnerField;
6654 // [[after_new]]
6655 }
6656 )";
6657 runDataflow(
6658 Code,
6659 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6660 ASTContext &ASTCtx) {
6661 const Environment &Env =
6662 getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "after_new");
6663
6664 const ValueDecl *OuterField = findValueDecl(ASTCtx, Name: "OuterField");
6665 const ValueDecl *InnerField = findValueDecl(ASTCtx, Name: "InnerField");
6666
6667 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, Name: "p");
6668
6669 auto &OuterLoc = cast<RecordStorageLocation>(Val&: P.getPointeeLoc());
6670 auto &OuterFieldLoc =
6671 *cast<RecordStorageLocation>(Val: OuterLoc.getChild(D: *OuterField));
6672 auto &InnerFieldLoc = *OuterFieldLoc.getChild(D: *InnerField);
6673
6674 EXPECT_THAT(Env.getValue(InnerFieldLoc), NotNull());
6675 });
6676}
6677
6678TEST(TransferTest, FunctionToPointerDecayHasValue) {
6679 std::string Code = R"(
6680 struct A { static void static_member_func(); };
6681 void target() {
6682 // To check that we're treating function-to-pointer decay correctly,
6683 // create two pointers, then verify they refer to the same storage
6684 // location.
6685 // We need to do the test this way because even if an initializer (in this
6686 // case, the function-to-pointer decay) does not create a value, we still
6687 // create a value for the variable.
6688 void (*non_member_p1)() = target;
6689 void (*non_member_p2)() = target;
6690
6691 // Do the same thing but for a static member function.
6692 void (*member_p1)() = A::static_member_func;
6693 void (*member_p2)() = A::static_member_func;
6694 // [[p]]
6695 }
6696 )";
6697 runDataflow(
6698 Code,
6699 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6700 ASTContext &ASTCtx) {
6701 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6702
6703 auto &NonMemberP1 =
6704 getValueForDecl<PointerValue>(ASTCtx, Env, Name: "non_member_p1");
6705 auto &NonMemberP2 =
6706 getValueForDecl<PointerValue>(ASTCtx, Env, Name: "non_member_p2");
6707 EXPECT_EQ(&NonMemberP1.getPointeeLoc(), &NonMemberP2.getPointeeLoc());
6708
6709 auto &MemberP1 =
6710 getValueForDecl<PointerValue>(ASTCtx, Env, Name: "member_p1");
6711 auto &MemberP2 =
6712 getValueForDecl<PointerValue>(ASTCtx, Env, Name: "member_p2");
6713 EXPECT_EQ(&MemberP1.getPointeeLoc(), &MemberP2.getPointeeLoc());
6714 });
6715}
6716
6717// Check that a builtin function is not associated with a value. (It's only
6718// possible to call builtin functions directly, not take their address.)
6719TEST(TransferTest, BuiltinFunctionModeled) {
6720 std::string Code = R"(
6721 void target() {
6722 __builtin_expect(0, 0);
6723 // [[p]]
6724 }
6725 )";
6726 runDataflow(
6727 Code,
6728 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6729 ASTContext &ASTCtx) {
6730 using ast_matchers::selectFirst;
6731 using ast_matchers::match;
6732 using ast_matchers::traverse;
6733 using ast_matchers::implicitCastExpr;
6734 using ast_matchers::hasCastKind;
6735
6736 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6737
6738 auto *ImplicitCast = selectFirst<ImplicitCastExpr>(
6739 BoundTo: "implicit_cast",
6740 Results: match(Matcher: traverse(TK: TK_AsIs,
6741 InnerMatcher: implicitCastExpr(hasCastKind(Kind: CK_BuiltinFnToFnPtr))
6742 .bind(ID: "implicit_cast")),
6743 Context&: ASTCtx));
6744
6745 ASSERT_THAT(ImplicitCast, NotNull());
6746 EXPECT_THAT(Env.getValue(*ImplicitCast), IsNull());
6747 });
6748}
6749
6750// Check that a callee of a member operator call is modeled as a `PointerValue`.
6751// Member operator calls are unusual in that their callee is a pointer that
6752// stems from a `FunctionToPointerDecay`. In calls to non-operator non-static
6753// member functions, the callee is a `MemberExpr` (which does not have pointer
6754// type).
6755// We want to make sure that we produce a pointer value for the callee in this
6756// specific scenario and that its storage location is durable (for convergence).
6757TEST(TransferTest, MemberOperatorCallModelsPointerForCallee) {
6758 std::string Code = R"(
6759 struct S {
6760 bool operator!=(S s);
6761 };
6762 void target() {
6763 S s;
6764 (void)(s != s);
6765 (void)(s != s);
6766 // [[p]]
6767 }
6768 )";
6769 runDataflow(
6770 Code,
6771 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6772 ASTContext &ASTCtx) {
6773 using ast_matchers::selectFirst;
6774 using ast_matchers::match;
6775 using ast_matchers::traverse;
6776 using ast_matchers::cxxOperatorCallExpr;
6777
6778 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6779
6780 auto Matches = match(
6781 Matcher: traverse(TK: TK_AsIs, InnerMatcher: cxxOperatorCallExpr().bind(ID: "call")), Context&: ASTCtx);
6782
6783 ASSERT_EQ(Matches.size(), 2UL);
6784
6785 auto *Call1 = Matches[0].getNodeAs<CXXOperatorCallExpr>(ID: "call");
6786 auto *Call2 = Matches[1].getNodeAs<CXXOperatorCallExpr>(ID: "call");
6787
6788 ASSERT_THAT(Call1, NotNull());
6789 ASSERT_THAT(Call2, NotNull());
6790
6791 EXPECT_EQ(cast<ImplicitCastExpr>(Call1->getCallee())->getCastKind(),
6792 CK_FunctionToPointerDecay);
6793 EXPECT_EQ(cast<ImplicitCastExpr>(Call2->getCallee())->getCastKind(),
6794 CK_FunctionToPointerDecay);
6795
6796 auto *Ptr1 = cast<PointerValue>(Env.getValue(*Call1->getCallee()));
6797 auto *Ptr2 = cast<PointerValue>(Env.getValue(*Call2->getCallee()));
6798
6799 ASSERT_EQ(&Ptr1->getPointeeLoc(), &Ptr2->getPointeeLoc());
6800 });
6801}
6802
6803// Check that fields of anonymous records are modeled.
6804TEST(TransferTest, AnonymousStruct) {
6805 std::string Code = R"(
6806 struct S {
6807 struct {
6808 bool b;
6809 };
6810 };
6811 void target() {
6812 S s;
6813 s.b = true;
6814 // [[p]]
6815 }
6816 )";
6817 runDataflow(
6818 Code,
6819 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6820 ASTContext &ASTCtx) {
6821 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6822 const ValueDecl *SDecl = findValueDecl(ASTCtx, Name: "s");
6823 const ValueDecl *BDecl = findValueDecl(ASTCtx, Name: "b");
6824 const IndirectFieldDecl *IndirectField =
6825 findIndirectFieldDecl(ASTCtx, Name: "b");
6826
6827 auto *S = cast<RecordStorageLocation>(Val: Env.getStorageLocation(D: *SDecl));
6828 auto &AnonStruct = *cast<RecordStorageLocation>(
6829 Val: S->getChild(D: *cast<ValueDecl>(Val: IndirectField->chain().front())));
6830
6831 auto *B = cast<BoolValue>(Val: getFieldValue(Loc: &AnonStruct, Field: *BDecl, Env));
6832 ASSERT_TRUE(Env.proves(B->formula()));
6833 });
6834}
6835
6836TEST(TransferTest, AnonymousStructWithInitializer) {
6837 std::string Code = R"(
6838 struct target {
6839 target() {
6840 (void)0;
6841 // [[p]]
6842 }
6843 struct {
6844 bool b = true;
6845 };
6846 };
6847 )";
6848 runDataflow(
6849 Code,
6850 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6851 ASTContext &ASTCtx) {
6852 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6853 const ValueDecl *BDecl = findValueDecl(ASTCtx, Name: "b");
6854 const IndirectFieldDecl *IndirectField =
6855 findIndirectFieldDecl(ASTCtx, Name: "b");
6856
6857 auto *ThisLoc =
6858 cast<RecordStorageLocation>(Val: Env.getThisPointeeStorageLocation());
6859 auto &AnonStruct = *cast<RecordStorageLocation>(Val: ThisLoc->getChild(
6860 D: *cast<ValueDecl>(Val: IndirectField->chain().front())));
6861
6862 auto *B = cast<BoolValue>(Val: getFieldValue(Loc: &AnonStruct, Field: *BDecl, Env));
6863 ASSERT_TRUE(Env.proves(B->formula()));
6864 });
6865}
6866
6867TEST(TransferTest, AnonymousStructWithReferenceField) {
6868 std::string Code = R"(
6869 int global_i = 0;
6870 struct target {
6871 target() {
6872 (void)0;
6873 // [[p]]
6874 }
6875 struct {
6876 int &i = global_i;
6877 };
6878 };
6879 )";
6880 runDataflow(
6881 Code,
6882 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6883 ASTContext &ASTCtx) {
6884 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6885 const ValueDecl *GlobalIDecl = findValueDecl(ASTCtx, Name: "global_i");
6886 const ValueDecl *IDecl = findValueDecl(ASTCtx, Name: "i");
6887 const IndirectFieldDecl *IndirectField =
6888 findIndirectFieldDecl(ASTCtx, Name: "i");
6889
6890 auto *ThisLoc =
6891 cast<RecordStorageLocation>(Val: Env.getThisPointeeStorageLocation());
6892 auto &AnonStruct = *cast<RecordStorageLocation>(Val: ThisLoc->getChild(
6893 D: *cast<ValueDecl>(Val: IndirectField->chain().front())));
6894
6895 ASSERT_EQ(AnonStruct.getChild(*IDecl),
6896 Env.getStorageLocation(*GlobalIDecl));
6897 });
6898}
6899
6900TEST(TransferTest, EvaluateBlockWithUnreachablePreds) {
6901 // This is a crash repro.
6902 // `false` block may not have been processed when we try to evaluate the `||`
6903 // after visiting `true`, because it is not necessary (and therefore the edge
6904 // is marked unreachable). Trying to get the analysis state via
6905 // `getEnvironment` for the subexpression still should not crash.
6906 std::string Code = R"(
6907 int target(int i) {
6908 if ((i < 0 && true) || false) {
6909 return 0;
6910 }
6911 return 0;
6912 }
6913 )";
6914 runDataflow(
6915 Code,
6916 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6917 ASTContext &ASTCtx) {});
6918}
6919
6920TEST(TransferTest, LambdaCaptureByCopy) {
6921 std::string Code = R"(
6922 void target(int Foo, int Bar) {
6923 [Foo]() {
6924 (void)0;
6925 // [[p]]
6926 }();
6927 }
6928 )";
6929 runDataflowOnLambda(
6930 Code,
6931 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6932 ASTContext &ASTCtx) {
6933 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6934 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6935
6936 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
6937 ASSERT_THAT(FooDecl, NotNull());
6938
6939 const StorageLocation *FooLoc = Env.getStorageLocation(D: *FooDecl);
6940 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
6941
6942 const Value *FooVal = Env.getValue(Loc: *FooLoc);
6943 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
6944
6945 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
6946 ASSERT_THAT(BarDecl, NotNull());
6947
6948 const StorageLocation *BarLoc = Env.getStorageLocation(D: *BarDecl);
6949 EXPECT_THAT(BarLoc, IsNull());
6950 });
6951}
6952
6953TEST(TransferTest, LambdaCaptureByReference) {
6954 std::string Code = R"(
6955 void target(int Foo, int Bar) {
6956 [&Foo]() {
6957 (void)0;
6958 // [[p]]
6959 }();
6960 }
6961 )";
6962 runDataflowOnLambda(
6963 Code,
6964 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6965 ASTContext &ASTCtx) {
6966 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6967 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
6968
6969 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
6970 ASSERT_THAT(FooDecl, NotNull());
6971
6972 const StorageLocation *FooLoc = Env.getStorageLocation(D: *FooDecl);
6973 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
6974
6975 const Value *FooVal = Env.getValue(Loc: *FooLoc);
6976 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
6977
6978 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
6979 ASSERT_THAT(BarDecl, NotNull());
6980
6981 const StorageLocation *BarLoc = Env.getStorageLocation(D: *BarDecl);
6982 EXPECT_THAT(BarLoc, IsNull());
6983 });
6984}
6985
6986TEST(TransferTest, LambdaCaptureWithInitializer) {
6987 std::string Code = R"(
6988 void target(int Bar) {
6989 [Foo=Bar]() {
6990 (void)0;
6991 // [[p]]
6992 }();
6993 }
6994 )";
6995 runDataflowOnLambda(
6996 Code,
6997 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6998 ASTContext &ASTCtx) {
6999 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
7000 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
7001
7002 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
7003 ASSERT_THAT(FooDecl, NotNull());
7004
7005 const StorageLocation *FooLoc = Env.getStorageLocation(D: *FooDecl);
7006 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
7007
7008 const Value *FooVal = Env.getValue(Loc: *FooLoc);
7009 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
7010
7011 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
7012 ASSERT_THAT(BarDecl, NotNull());
7013
7014 const StorageLocation *BarLoc = Env.getStorageLocation(D: *BarDecl);
7015 EXPECT_THAT(BarLoc, IsNull());
7016 });
7017}
7018
7019TEST(TransferTest, LambdaCaptureByCopyImplicit) {
7020 std::string Code = R"(
7021 void target(int Foo, int Bar) {
7022 [=]() {
7023 Foo;
7024 // [[p]]
7025 }();
7026 }
7027 )";
7028 runDataflowOnLambda(
7029 Code,
7030 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
7031 ASTContext &ASTCtx) {
7032 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
7033 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
7034
7035 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
7036 ASSERT_THAT(FooDecl, NotNull());
7037
7038 const StorageLocation *FooLoc = Env.getStorageLocation(D: *FooDecl);
7039 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
7040
7041 const Value *FooVal = Env.getValue(Loc: *FooLoc);
7042 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
7043
7044 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
7045 ASSERT_THAT(BarDecl, NotNull());
7046
7047 // There is no storage location for `Bar` because it isn't used in the
7048 // body of the lambda.
7049 const StorageLocation *BarLoc = Env.getStorageLocation(D: *BarDecl);
7050 EXPECT_THAT(BarLoc, IsNull());
7051 });
7052}
7053
7054TEST(TransferTest, LambdaCaptureByReferenceImplicit) {
7055 std::string Code = R"(
7056 void target(int Foo, int Bar) {
7057 [&]() {
7058 Foo;
7059 // [[p]]
7060 }();
7061 }
7062 )";
7063 runDataflowOnLambda(
7064 Code,
7065 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
7066 ASTContext &ASTCtx) {
7067 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
7068 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
7069
7070 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
7071 ASSERT_THAT(FooDecl, NotNull());
7072
7073 const StorageLocation *FooLoc = Env.getStorageLocation(D: *FooDecl);
7074 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
7075
7076 const Value *FooVal = Env.getValue(Loc: *FooLoc);
7077 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
7078
7079 const ValueDecl *BarDecl = findValueDecl(ASTCtx, Name: "Bar");
7080 ASSERT_THAT(BarDecl, NotNull());
7081
7082 // There is no storage location for `Bar` because it isn't used in the
7083 // body of the lambda.
7084 const StorageLocation *BarLoc = Env.getStorageLocation(D: *BarDecl);
7085 EXPECT_THAT(BarLoc, IsNull());
7086 });
7087}
7088
7089TEST(TransferTest, LambdaCaptureThis) {
7090 std::string Code = R"(
7091 struct Bar {
7092 int Foo;
7093
7094 void target() {
7095 [this]() {
7096 Foo;
7097 // [[p]]
7098 }();
7099 }
7100 };
7101 )";
7102 runDataflowOnLambda(
7103 Code,
7104 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
7105 ASTContext &ASTCtx) {
7106 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
7107 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
7108
7109 const RecordStorageLocation *ThisPointeeLoc =
7110 Env.getThisPointeeStorageLocation();
7111 ASSERT_THAT(ThisPointeeLoc, NotNull());
7112
7113 const ValueDecl *FooDecl = findValueDecl(ASTCtx, Name: "Foo");
7114 ASSERT_THAT(FooDecl, NotNull());
7115
7116 const StorageLocation *FooLoc = ThisPointeeLoc->getChild(D: *FooDecl);
7117 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
7118
7119 const Value *FooVal = Env.getValue(Loc: *FooLoc);
7120 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
7121 });
7122}
7123
7124// This test verifies correct modeling of a relational dependency that goes
7125// through unmodeled functions (the simple `cond()` in this case).
7126TEST(TransferTest, ConditionalRelation) {
7127 std::string Code = R"(
7128 bool cond();
7129 void target() {
7130 bool a = true;
7131 bool b = true;
7132 if (cond()) {
7133 a = false;
7134 if (cond()) {
7135 b = false;
7136 }
7137 }
7138 (void)0;
7139 // [[p]]
7140 }
7141 )";
7142 runDataflow(
7143 Code,
7144 VerifyResults: [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
7145 ASTContext &ASTCtx) {
7146 const Environment &Env = getEnvironmentAtAnnotation(AnnotationStates: Results, Annotation: "p");
7147 auto &A = Env.arena();
7148 auto &VarA = getValueForDecl<BoolValue>(ASTCtx, Env, Name: "a").formula();
7149 auto &VarB = getValueForDecl<BoolValue>(ASTCtx, Env, Name: "b").formula();
7150
7151 EXPECT_FALSE(Env.allows(A.makeAnd(VarA, A.makeNot(VarB))));
7152 });
7153}
7154
7155} // namespace
7156

source code of clang/unittests/Analysis/FlowSensitive/TransferTest.cpp