Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / unittests / Analysis / FlowSensitive / TransferTest.cpp
blob0f9f13df817075ee5d5deb69f4ec092a1b469f55
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 //===----------------------------------------------------------------------===//
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/RecordOps.h"
16 #include "clang/Analysis/FlowSensitive/StorageLocation.h"
17 #include "clang/Analysis/FlowSensitive/Value.h"
18 #include "clang/Basic/LangStandard.h"
19 #include "llvm/ADT/ArrayRef.h"
20 #include "llvm/ADT/SmallVector.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/Support/Casting.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>
30 namespace {
32 using namespace clang;
33 using namespace dataflow;
34 using namespace test;
35 using ::testing::Eq;
36 using ::testing::IsNull;
37 using ::testing::Ne;
38 using ::testing::NotNull;
39 using ::testing::UnorderedElementsAre;
41 void runDataflow(
42 llvm::StringRef Code,
43 std::function<
44 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
45 ASTContext &)>
46 VerifyResults,
47 DataflowAnalysisOptions Options,
48 LangStandard::Kind Std = LangStandard::lang_cxx17,
49 llvm::StringRef TargetFun = "target") {
50 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code, VerifyResults, Options,
51 Std, TargetFun),
52 llvm::Succeeded());
55 void runDataflow(
56 llvm::StringRef Code,
57 std::function<
58 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
59 ASTContext &)>
60 VerifyResults,
61 LangStandard::Kind Std = LangStandard::lang_cxx17,
62 bool ApplyBuiltinTransfer = true, llvm::StringRef TargetFun = "target") {
63 runDataflow(Code, std::move(VerifyResults),
64 {ApplyBuiltinTransfer ? BuiltinOptions{}
65 : std::optional<BuiltinOptions>()},
66 Std, TargetFun);
69 void runDataflowOnLambda(
70 llvm::StringRef Code,
71 std::function<
72 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
73 ASTContext &)>
74 VerifyResults,
75 DataflowAnalysisOptions Options,
76 LangStandard::Kind Std = LangStandard::lang_cxx17) {
77 ASSERT_THAT_ERROR(
78 checkDataflowWithNoopAnalysis(
79 Code,
80 ast_matchers::hasDeclContext(
81 ast_matchers::cxxRecordDecl(ast_matchers::isLambda())),
82 VerifyResults, Options, Std),
83 llvm::Succeeded());
86 void runDataflowOnLambda(
87 llvm::StringRef Code,
88 std::function<
89 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
90 ASTContext &)>
91 VerifyResults,
92 LangStandard::Kind Std = LangStandard::lang_cxx17,
93 bool ApplyBuiltinTransfer = true) {
94 runDataflowOnLambda(Code, std::move(VerifyResults),
95 {ApplyBuiltinTransfer ? BuiltinOptions{}
96 : std::optional<BuiltinOptions>()},
97 Std);
100 const Formula &getFormula(const ValueDecl &D, const Environment &Env) {
101 return cast<BoolValue>(Env.getValue(D))->formula();
104 TEST(TransferTest, CNotSupported) {
105 std::string Code = R"(
106 void target() {}
108 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(
109 Code, [](const auto &, auto &) {}, {BuiltinOptions{}},
110 LangStandard::lang_c89),
111 llvm::FailedWithMessage("Can only analyze C++"));
114 TEST(TransferTest, IntVarDeclNotTrackedWhenTransferDisabled) {
115 std::string Code = R"(
116 void target() {
117 int Foo;
118 // [[p]]
121 runDataflow(
122 Code,
123 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
124 ASTContext &ASTCtx) {
125 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
126 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
128 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
129 ASSERT_THAT(FooDecl, NotNull());
131 EXPECT_EQ(Env.getStorageLocation(*FooDecl), nullptr);
133 LangStandard::lang_cxx17,
134 /*ApplyBuiltinTransfer=*/false);
137 TEST(TransferTest, BoolVarDecl) {
138 std::string Code = R"(
139 void target() {
140 bool Foo;
141 // [[p]]
144 runDataflow(
145 Code,
146 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
147 ASTContext &ASTCtx) {
148 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
149 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
151 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
152 ASSERT_THAT(FooDecl, NotNull());
154 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
155 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
157 const Value *FooVal = Env.getValue(*FooLoc);
158 EXPECT_TRUE(isa_and_nonnull<BoolValue>(FooVal));
162 TEST(TransferTest, IntVarDecl) {
163 std::string Code = R"(
164 void target() {
165 int Foo;
166 // [[p]]
169 runDataflow(
170 Code,
171 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
172 ASTContext &ASTCtx) {
173 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
174 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
176 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
177 ASSERT_THAT(FooDecl, NotNull());
179 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
180 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
182 const Value *FooVal = Env.getValue(*FooLoc);
183 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
187 TEST(TransferTest, StructIncomplete) {
188 std::string Code = R"(
189 struct A;
191 void target() {
192 A* Foo;
193 // [[p]]
196 runDataflow(
197 Code,
198 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
199 ASTContext &ASTCtx) {
200 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
201 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
203 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
204 ASSERT_THAT(FooDecl, NotNull());
205 auto *FooValue = dyn_cast_or_null<PointerValue>(Env.getValue(*FooDecl));
206 ASSERT_THAT(FooValue, NotNull());
208 EXPECT_TRUE(isa<RecordStorageLocation>(FooValue->getPointeeLoc()));
209 auto *FooPointeeValue = Env.getValue(FooValue->getPointeeLoc());
210 ASSERT_THAT(FooPointeeValue, NotNull());
211 EXPECT_TRUE(isa<RecordValue>(FooPointeeValue));
215 // As a memory optimization, we prevent modeling fields nested below a certain
216 // level (currently, depth 3). This test verifies this lack of modeling. We also
217 // include a regression test for the case that the unmodeled field is a
218 // reference to a struct; previously, we crashed when accessing such a field.
219 TEST(TransferTest, StructFieldUnmodeled) {
220 std::string Code = R"(
221 struct S { int X; };
222 S GlobalS;
223 struct A { S &Unmodeled = GlobalS; };
224 struct B { A F3; };
225 struct C { B F2; };
226 struct D { C F1; };
228 void target() {
229 D Bar;
230 A &Foo = Bar.F1.F2.F3;
231 int Zab = Foo.Unmodeled.X;
232 // [[p]]
235 runDataflow(
236 Code,
237 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
238 ASTContext &ASTCtx) {
239 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
240 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
242 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
243 ASSERT_THAT(FooDecl, NotNull());
244 QualType FooReferentType = FooDecl->getType()->getPointeeType();
245 ASSERT_TRUE(FooReferentType->isStructureType());
246 auto FooFields = FooReferentType->getAsRecordDecl()->fields();
248 FieldDecl *UnmodeledDecl = nullptr;
249 for (FieldDecl *Field : FooFields) {
250 if (Field->getNameAsString() == "Unmodeled") {
251 UnmodeledDecl = Field;
252 } else {
253 FAIL() << "Unexpected field: " << Field->getNameAsString();
256 ASSERT_THAT(UnmodeledDecl, NotNull());
258 const auto *FooLoc =
259 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
260 const auto *UnmodeledLoc = FooLoc->getChild(*UnmodeledDecl);
261 ASSERT_TRUE(isa<RecordStorageLocation>(UnmodeledLoc));
262 EXPECT_THAT(Env.getValue(*UnmodeledLoc), IsNull());
264 const ValueDecl *ZabDecl = findValueDecl(ASTCtx, "Zab");
265 ASSERT_THAT(ZabDecl, NotNull());
266 EXPECT_THAT(Env.getValue(*ZabDecl), NotNull());
270 TEST(TransferTest, StructVarDecl) {
271 std::string Code = R"(
272 struct A {
273 int Bar;
276 void target() {
277 A Foo;
278 (void)Foo.Bar;
279 // [[p]]
282 runDataflow(
283 Code,
284 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
285 ASTContext &ASTCtx) {
286 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
287 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
289 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
290 ASSERT_THAT(FooDecl, NotNull());
292 ASSERT_TRUE(FooDecl->getType()->isStructureType());
293 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
295 FieldDecl *BarDecl = nullptr;
296 for (FieldDecl *Field : FooFields) {
297 if (Field->getNameAsString() == "Bar") {
298 BarDecl = Field;
299 } else {
300 FAIL() << "Unexpected field: " << Field->getNameAsString();
303 ASSERT_THAT(BarDecl, NotNull());
305 const auto *FooLoc =
306 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
307 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
311 TEST(TransferTest, StructVarDeclWithInit) {
312 std::string Code = R"(
313 struct A {
314 int Bar;
317 A Gen();
319 void target() {
320 A Foo = Gen();
321 (void)Foo.Bar;
322 // [[p]]
325 runDataflow(
326 Code,
327 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
328 ASTContext &ASTCtx) {
329 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
330 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
332 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
333 ASSERT_THAT(FooDecl, NotNull());
335 ASSERT_TRUE(FooDecl->getType()->isStructureType());
336 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
338 FieldDecl *BarDecl = nullptr;
339 for (FieldDecl *Field : FooFields) {
340 if (Field->getNameAsString() == "Bar") {
341 BarDecl = Field;
342 } else {
343 FAIL() << "Unexpected field: " << Field->getNameAsString();
346 ASSERT_THAT(BarDecl, NotNull());
348 const auto *FooLoc =
349 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
350 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
354 TEST(TransferTest, StructArrayVarDecl) {
355 std::string Code = R"(
356 struct A {};
358 void target() {
359 A Array[2];
360 // [[p]]
363 runDataflow(
364 Code,
365 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
366 ASTContext &ASTCtx) {
367 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
369 const ValueDecl *ArrayDecl = findValueDecl(ASTCtx, "Array");
371 // We currently don't create values for arrays.
372 ASSERT_THAT(Env.getValue(*ArrayDecl), IsNull());
376 TEST(TransferTest, ClassVarDecl) {
377 std::string Code = R"(
378 class A {
379 public:
380 int Bar;
383 void target() {
384 A Foo;
385 (void)Foo.Bar;
386 // [[p]]
389 runDataflow(
390 Code,
391 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
392 ASTContext &ASTCtx) {
393 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
394 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
396 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
397 ASSERT_THAT(FooDecl, NotNull());
399 ASSERT_TRUE(FooDecl->getType()->isClassType());
400 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
402 FieldDecl *BarDecl = nullptr;
403 for (FieldDecl *Field : FooFields) {
404 if (Field->getNameAsString() == "Bar") {
405 BarDecl = Field;
406 } else {
407 FAIL() << "Unexpected field: " << Field->getNameAsString();
410 ASSERT_THAT(BarDecl, NotNull());
412 const auto *FooLoc =
413 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
414 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
418 TEST(TransferTest, ReferenceVarDecl) {
419 std::string Code = R"(
420 struct A {};
422 A &getA();
424 void target() {
425 A &Foo = getA();
426 // [[p]]
429 runDataflow(
430 Code,
431 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
432 ASTContext &ASTCtx) {
433 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
434 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
436 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
437 ASSERT_THAT(FooDecl, NotNull());
439 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
440 ASSERT_TRUE(isa_and_nonnull<RecordStorageLocation>(FooLoc));
442 const Value *FooReferentVal = Env.getValue(*FooLoc);
443 EXPECT_TRUE(isa_and_nonnull<RecordValue>(FooReferentVal));
447 TEST(TransferTest, SelfReferentialReferenceVarDecl) {
448 std::string Code = R"(
449 struct A;
451 struct B {};
453 struct C {
454 A &FooRef;
455 A *FooPtr;
456 B &BazRef;
457 B *BazPtr;
460 struct A {
461 C &Bar;
464 A &getA();
466 void target() {
467 A &Foo = getA();
468 (void)Foo.Bar.FooRef;
469 (void)Foo.Bar.FooPtr;
470 (void)Foo.Bar.BazRef;
471 (void)Foo.Bar.BazPtr;
472 // [[p]]
475 runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>>
476 &Results,
477 ASTContext &ASTCtx) {
478 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
479 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
481 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
482 ASSERT_THAT(FooDecl, NotNull());
484 ASSERT_TRUE(FooDecl->getType()->isReferenceType());
485 ASSERT_TRUE(FooDecl->getType().getNonReferenceType()->isStructureType());
486 const auto FooFields =
487 FooDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields();
489 FieldDecl *BarDecl = nullptr;
490 for (FieldDecl *Field : FooFields) {
491 if (Field->getNameAsString() == "Bar") {
492 BarDecl = Field;
493 } else {
494 FAIL() << "Unexpected field: " << Field->getNameAsString();
497 ASSERT_THAT(BarDecl, NotNull());
499 ASSERT_TRUE(BarDecl->getType()->isReferenceType());
500 ASSERT_TRUE(BarDecl->getType().getNonReferenceType()->isStructureType());
501 const auto BarFields =
502 BarDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields();
504 FieldDecl *FooRefDecl = nullptr;
505 FieldDecl *FooPtrDecl = nullptr;
506 FieldDecl *BazRefDecl = nullptr;
507 FieldDecl *BazPtrDecl = nullptr;
508 for (FieldDecl *Field : BarFields) {
509 if (Field->getNameAsString() == "FooRef") {
510 FooRefDecl = Field;
511 } else if (Field->getNameAsString() == "FooPtr") {
512 FooPtrDecl = Field;
513 } else if (Field->getNameAsString() == "BazRef") {
514 BazRefDecl = Field;
515 } else if (Field->getNameAsString() == "BazPtr") {
516 BazPtrDecl = Field;
517 } else {
518 FAIL() << "Unexpected field: " << Field->getNameAsString();
521 ASSERT_THAT(FooRefDecl, NotNull());
522 ASSERT_THAT(FooPtrDecl, NotNull());
523 ASSERT_THAT(BazRefDecl, NotNull());
524 ASSERT_THAT(BazPtrDecl, NotNull());
526 const auto &FooLoc =
527 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
529 const auto &BarLoc =
530 *cast<RecordStorageLocation>(FooLoc.getChild(*BarDecl));
532 const auto &FooReferentLoc =
533 *cast<RecordStorageLocation>(BarLoc.getChild(*FooRefDecl));
534 EXPECT_THAT(Env.getValue(FooReferentLoc), NotNull());
535 EXPECT_THAT(getFieldValue(&FooReferentLoc, *BarDecl, Env), IsNull());
537 const auto &FooPtrVal =
538 *cast<PointerValue>(getFieldValue(&BarLoc, *FooPtrDecl, Env));
539 const auto &FooPtrPointeeLoc =
540 cast<RecordStorageLocation>(FooPtrVal.getPointeeLoc());
541 EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), NotNull());
542 EXPECT_THAT(getFieldValue(&FooPtrPointeeLoc, *BarDecl, Env), IsNull());
544 EXPECT_THAT(getFieldValue(&BarLoc, *BazRefDecl, Env), NotNull());
546 const auto &BazPtrVal =
547 *cast<PointerValue>(getFieldValue(&BarLoc, *BazPtrDecl, Env));
548 const StorageLocation &BazPtrPointeeLoc = BazPtrVal.getPointeeLoc();
549 EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull());
553 TEST(TransferTest, PointerVarDecl) {
554 std::string Code = R"(
555 struct A {};
557 A *getA();
559 void target() {
560 A *Foo = getA();
561 // [[p]]
564 runDataflow(
565 Code,
566 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
567 ASTContext &ASTCtx) {
568 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
569 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
571 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
572 ASSERT_THAT(FooDecl, NotNull());
574 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
575 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
577 const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));
578 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
579 EXPECT_TRUE(isa<RecordStorageLocation>(&FooPointeeLoc));
581 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
582 EXPECT_TRUE(isa_and_nonnull<RecordValue>(FooPointeeVal));
586 TEST(TransferTest, SelfReferentialPointerVarDecl) {
587 std::string Code = R"(
588 struct A;
590 struct B {};
592 struct C {
593 A &FooRef;
594 A *FooPtr;
595 B &BazRef;
596 B *BazPtr;
599 struct A {
600 C *Bar;
603 A *getA();
605 void target() {
606 A *Foo = getA();
607 (void)Foo->Bar->FooRef;
608 (void)Foo->Bar->FooPtr;
609 (void)Foo->Bar->BazRef;
610 (void)Foo->Bar->BazPtr;
611 // [[p]]
614 runDataflow(
615 Code,
616 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
617 ASTContext &ASTCtx) {
618 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
619 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
621 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
622 ASSERT_THAT(FooDecl, NotNull());
624 ASSERT_TRUE(FooDecl->getType()->isPointerType());
625 ASSERT_TRUE(FooDecl->getType()
626 ->getAs<PointerType>()
627 ->getPointeeType()
628 ->isStructureType());
629 const auto FooFields = FooDecl->getType()
630 ->getAs<PointerType>()
631 ->getPointeeType()
632 ->getAsRecordDecl()
633 ->fields();
635 FieldDecl *BarDecl = nullptr;
636 for (FieldDecl *Field : FooFields) {
637 if (Field->getNameAsString() == "Bar") {
638 BarDecl = Field;
639 } else {
640 FAIL() << "Unexpected field: " << Field->getNameAsString();
643 ASSERT_THAT(BarDecl, NotNull());
645 ASSERT_TRUE(BarDecl->getType()->isPointerType());
646 ASSERT_TRUE(BarDecl->getType()
647 ->getAs<PointerType>()
648 ->getPointeeType()
649 ->isStructureType());
650 const auto BarFields = BarDecl->getType()
651 ->getAs<PointerType>()
652 ->getPointeeType()
653 ->getAsRecordDecl()
654 ->fields();
656 FieldDecl *FooRefDecl = nullptr;
657 FieldDecl *FooPtrDecl = nullptr;
658 FieldDecl *BazRefDecl = nullptr;
659 FieldDecl *BazPtrDecl = nullptr;
660 for (FieldDecl *Field : BarFields) {
661 if (Field->getNameAsString() == "FooRef") {
662 FooRefDecl = Field;
663 } else if (Field->getNameAsString() == "FooPtr") {
664 FooPtrDecl = Field;
665 } else if (Field->getNameAsString() == "BazRef") {
666 BazRefDecl = Field;
667 } else if (Field->getNameAsString() == "BazPtr") {
668 BazPtrDecl = Field;
669 } else {
670 FAIL() << "Unexpected field: " << Field->getNameAsString();
673 ASSERT_THAT(FooRefDecl, NotNull());
674 ASSERT_THAT(FooPtrDecl, NotNull());
675 ASSERT_THAT(BazRefDecl, NotNull());
676 ASSERT_THAT(BazPtrDecl, NotNull());
678 const auto &FooLoc =
679 *cast<ScalarStorageLocation>(Env.getStorageLocation(*FooDecl));
680 const auto &FooVal = *cast<PointerValue>(Env.getValue(FooLoc));
681 const auto &FooPointeeLoc =
682 cast<RecordStorageLocation>(FooVal.getPointeeLoc());
684 const auto &BarVal =
685 *cast<PointerValue>(getFieldValue(&FooPointeeLoc, *BarDecl, Env));
686 const auto &BarPointeeLoc =
687 cast<RecordStorageLocation>(BarVal.getPointeeLoc());
689 EXPECT_THAT(getFieldValue(&BarPointeeLoc, *FooRefDecl, Env), NotNull());
691 const auto &FooPtrVal = *cast<PointerValue>(
692 getFieldValue(&BarPointeeLoc, *FooPtrDecl, Env));
693 const auto &FooPtrPointeeLoc =
694 cast<RecordStorageLocation>(FooPtrVal.getPointeeLoc());
695 EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull());
697 EXPECT_THAT(getFieldValue(&BarPointeeLoc, *BazRefDecl, Env), NotNull());
699 const auto &BazPtrVal = *cast<PointerValue>(
700 getFieldValue(&BarPointeeLoc, *BazPtrDecl, Env));
701 const StorageLocation &BazPtrPointeeLoc = BazPtrVal.getPointeeLoc();
702 EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull());
706 TEST(TransferTest, DirectlySelfReferentialReference) {
707 std::string Code = R"(
708 struct target {
709 target() {
710 (void)0;
711 // [[p]]
713 target &self = *this;
716 runDataflow(
717 Code,
718 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
719 ASTContext &ASTCtx) {
720 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
721 const ValueDecl *SelfDecl = findValueDecl(ASTCtx, "self");
723 auto *ThisLoc = Env.getThisPointeeStorageLocation();
724 ASSERT_EQ(ThisLoc->getChild(*SelfDecl), ThisLoc);
728 TEST(TransferTest, MultipleVarsDecl) {
729 std::string Code = R"(
730 void target() {
731 int Foo, Bar;
732 (void)0;
733 // [[p]]
736 runDataflow(
737 Code,
738 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
739 ASTContext &ASTCtx) {
740 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
741 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
743 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
744 ASSERT_THAT(FooDecl, NotNull());
746 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
747 ASSERT_THAT(BarDecl, NotNull());
749 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
750 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
752 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
753 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
755 const Value *FooVal = Env.getValue(*FooLoc);
756 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
758 const Value *BarVal = Env.getValue(*BarLoc);
759 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
763 TEST(TransferTest, JoinVarDecl) {
764 std::string Code = R"(
765 void target(bool B) {
766 int Foo;
767 // [[p1]]
768 if (B) {
769 int Bar;
770 // [[p2]]
771 } else {
772 int Baz;
773 // [[p3]]
775 (void)0;
776 // [[p4]]
779 runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>>
780 &Results,
781 ASTContext &ASTCtx) {
782 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2", "p3", "p4"));
784 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
785 ASSERT_THAT(FooDecl, NotNull());
787 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
788 ASSERT_THAT(BarDecl, NotNull());
790 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
791 ASSERT_THAT(BazDecl, NotNull());
793 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
795 const StorageLocation *FooLoc = Env1.getStorageLocation(*FooDecl);
796 EXPECT_THAT(FooLoc, NotNull());
797 EXPECT_THAT(Env1.getStorageLocation(*BarDecl), IsNull());
798 EXPECT_THAT(Env1.getStorageLocation(*BazDecl), IsNull());
800 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
801 EXPECT_EQ(Env2.getStorageLocation(*FooDecl), FooLoc);
802 EXPECT_THAT(Env2.getStorageLocation(*BarDecl), NotNull());
803 EXPECT_THAT(Env2.getStorageLocation(*BazDecl), IsNull());
805 const Environment &Env3 = getEnvironmentAtAnnotation(Results, "p3");
806 EXPECT_EQ(Env3.getStorageLocation(*FooDecl), FooLoc);
807 EXPECT_THAT(Env3.getStorageLocation(*BarDecl), IsNull());
808 EXPECT_THAT(Env3.getStorageLocation(*BazDecl), NotNull());
810 const Environment &Env4 = getEnvironmentAtAnnotation(Results, "p4");
811 EXPECT_EQ(Env4.getStorageLocation(*FooDecl), FooLoc);
812 EXPECT_THAT(Env4.getStorageLocation(*BarDecl), IsNull());
813 EXPECT_THAT(Env4.getStorageLocation(*BazDecl), IsNull());
817 TEST(TransferTest, BinaryOperatorAssign) {
818 std::string Code = R"(
819 void target() {
820 int Foo;
821 int Bar;
822 (Bar) = (Foo);
823 // [[p]]
826 runDataflow(
827 Code,
828 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
829 ASTContext &ASTCtx) {
830 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
831 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
833 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
834 ASSERT_THAT(FooDecl, NotNull());
836 const Value *FooVal = Env.getValue(*FooDecl);
837 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
839 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
840 ASSERT_THAT(BarDecl, NotNull());
842 EXPECT_EQ(Env.getValue(*BarDecl), FooVal);
846 TEST(TransferTest, BinaryOperatorAssignIntegerLiteral) {
847 std::string Code = R"(
848 void target() {
849 int Foo = 1;
850 // [[before]]
851 Foo = 2;
852 // [[after]]
855 runDataflow(
856 Code,
857 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
858 ASTContext &ASTCtx) {
859 const Environment &Before =
860 getEnvironmentAtAnnotation(Results, "before");
861 const Environment &After = getEnvironmentAtAnnotation(Results, "after");
863 const auto &ValBefore =
864 getValueForDecl<IntegerValue>(ASTCtx, Before, "Foo");
865 const auto &ValAfter =
866 getValueForDecl<IntegerValue>(ASTCtx, After, "Foo");
867 EXPECT_NE(&ValBefore, &ValAfter);
871 TEST(TransferTest, VarDeclInitAssign) {
872 std::string Code = R"(
873 void target() {
874 int Foo;
875 int Bar = Foo;
876 // [[p]]
879 runDataflow(
880 Code,
881 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
882 ASTContext &ASTCtx) {
883 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
884 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
886 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
887 ASSERT_THAT(FooDecl, NotNull());
889 const Value *FooVal = Env.getValue(*FooDecl);
890 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
892 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
893 ASSERT_THAT(BarDecl, NotNull());
895 EXPECT_EQ(Env.getValue(*BarDecl), FooVal);
899 TEST(TransferTest, VarDeclInitAssignChained) {
900 std::string Code = R"(
901 void target() {
902 int Foo;
903 int Bar;
904 int Baz = (Bar = Foo);
905 // [[p]]
908 runDataflow(
909 Code,
910 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
911 ASTContext &ASTCtx) {
912 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
913 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
915 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
916 ASSERT_THAT(FooDecl, NotNull());
918 const Value *FooVal = Env.getValue(*FooDecl);
919 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
921 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
922 ASSERT_THAT(BarDecl, NotNull());
924 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
925 ASSERT_THAT(BazDecl, NotNull());
927 EXPECT_EQ(Env.getValue(*BarDecl), FooVal);
928 EXPECT_EQ(Env.getValue(*BazDecl), FooVal);
932 TEST(TransferTest, VarDeclInitAssignPtrDeref) {
933 std::string Code = R"(
934 void target() {
935 int Foo;
936 int *Bar;
937 *(Bar) = Foo;
938 int Baz = *(Bar);
939 // [[p]]
942 runDataflow(
943 Code,
944 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
945 ASTContext &ASTCtx) {
946 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
947 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
949 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
950 ASSERT_THAT(FooDecl, NotNull());
952 const Value *FooVal = Env.getValue(*FooDecl);
953 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
955 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
956 ASSERT_THAT(BarDecl, NotNull());
958 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl));
959 EXPECT_EQ(Env.getValue(BarVal->getPointeeLoc()), FooVal);
961 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
962 ASSERT_THAT(BazDecl, NotNull());
964 EXPECT_EQ(Env.getValue(*BazDecl), FooVal);
968 TEST(TransferTest, AssignToAndFromReference) {
969 std::string Code = R"(
970 void target() {
971 int Foo;
972 int Bar;
973 int &Baz = Foo;
974 // [[p1]]
975 Baz = Bar;
976 int Qux = Baz;
977 int &Quux = Baz;
978 // [[p2]]
981 runDataflow(
982 Code,
983 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
984 ASTContext &ASTCtx) {
985 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
986 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
987 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
989 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
990 ASSERT_THAT(FooDecl, NotNull());
992 const Value *FooVal = Env1.getValue(*FooDecl);
993 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
995 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
996 ASSERT_THAT(BarDecl, NotNull());
998 const Value *BarVal = Env1.getValue(*BarDecl);
999 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1001 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1002 ASSERT_THAT(BazDecl, NotNull());
1004 EXPECT_EQ(Env1.getValue(*BazDecl), FooVal);
1006 EXPECT_EQ(Env2.getValue(*BazDecl), BarVal);
1007 EXPECT_EQ(Env2.getValue(*FooDecl), BarVal);
1009 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1010 ASSERT_THAT(QuxDecl, NotNull());
1011 EXPECT_EQ(Env2.getValue(*QuxDecl), BarVal);
1013 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
1014 ASSERT_THAT(QuuxDecl, NotNull());
1015 EXPECT_EQ(Env2.getValue(*QuuxDecl), BarVal);
1019 TEST(TransferTest, MultipleParamDecls) {
1020 std::string Code = R"(
1021 void target(int Foo, int Bar) {
1022 (void)0;
1023 // [[p]]
1026 runDataflow(
1027 Code,
1028 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1029 ASTContext &ASTCtx) {
1030 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1031 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1033 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1034 ASSERT_THAT(FooDecl, NotNull());
1036 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
1037 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
1039 const Value *FooVal = Env.getValue(*FooLoc);
1040 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
1042 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1043 ASSERT_THAT(BarDecl, NotNull());
1045 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
1046 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1048 const Value *BarVal = Env.getValue(*BarLoc);
1049 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1053 TEST(TransferTest, StructParamDecl) {
1054 std::string Code = R"(
1055 struct A {
1056 int Bar;
1059 void target(A Foo) {
1060 (void)Foo.Bar;
1061 // [[p]]
1064 runDataflow(
1065 Code,
1066 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1067 ASTContext &ASTCtx) {
1068 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1069 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1071 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1072 ASSERT_THAT(FooDecl, NotNull());
1074 ASSERT_TRUE(FooDecl->getType()->isStructureType());
1075 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1077 FieldDecl *BarDecl = nullptr;
1078 for (FieldDecl *Field : FooFields) {
1079 if (Field->getNameAsString() == "Bar") {
1080 BarDecl = Field;
1081 } else {
1082 FAIL() << "Unexpected field: " << Field->getNameAsString();
1085 ASSERT_THAT(BarDecl, NotNull());
1087 const auto *FooLoc =
1088 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
1089 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
1093 TEST(TransferTest, ReferenceParamDecl) {
1094 std::string Code = R"(
1095 struct A {};
1097 void target(A &Foo) {
1098 (void)0;
1099 // [[p]]
1102 runDataflow(
1103 Code,
1104 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1105 ASTContext &ASTCtx) {
1106 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1107 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1109 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1110 ASSERT_THAT(FooDecl, NotNull());
1112 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
1113 ASSERT_TRUE(isa_and_nonnull<RecordStorageLocation>(FooLoc));
1115 const Value *FooReferentVal = Env.getValue(*FooLoc);
1116 EXPECT_TRUE(isa_and_nonnull<RecordValue>(FooReferentVal));
1120 TEST(TransferTest, PointerParamDecl) {
1121 std::string Code = R"(
1122 struct A {};
1124 void target(A *Foo) {
1125 (void)0;
1126 // [[p]]
1129 runDataflow(
1130 Code,
1131 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1132 ASTContext &ASTCtx) {
1133 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1134 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1136 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1137 ASSERT_THAT(FooDecl, NotNull());
1139 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
1140 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
1142 const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));
1143 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
1144 EXPECT_TRUE(isa<RecordStorageLocation>(&FooPointeeLoc));
1146 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
1147 EXPECT_TRUE(isa_and_nonnull<RecordValue>(FooPointeeVal));
1151 TEST(TransferTest, StructMember) {
1152 std::string Code = R"(
1153 struct A {
1154 int Bar;
1157 void target(A Foo) {
1158 int Baz = Foo.Bar;
1159 // [[p]]
1162 runDataflow(
1163 Code,
1164 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1165 ASTContext &ASTCtx) {
1166 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1167 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1169 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1170 ASSERT_THAT(FooDecl, NotNull());
1172 ASSERT_TRUE(FooDecl->getType()->isStructureType());
1173 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1175 FieldDecl *BarDecl = nullptr;
1176 for (FieldDecl *Field : FooFields) {
1177 if (Field->getNameAsString() == "Bar") {
1178 BarDecl = Field;
1179 } else {
1180 FAIL() << "Unexpected field: " << Field->getNameAsString();
1183 ASSERT_THAT(BarDecl, NotNull());
1185 const auto *FooLoc =
1186 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
1187 const auto *BarVal =
1188 cast<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env));
1190 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1191 ASSERT_THAT(BazDecl, NotNull());
1193 EXPECT_EQ(Env.getValue(*BazDecl), BarVal);
1197 TEST(TransferTest, StructMemberEnum) {
1198 std::string Code = R"(
1199 struct A {
1200 int Bar;
1201 enum E { ONE, TWO };
1204 void target(A Foo) {
1205 A::E Baz = Foo.ONE;
1206 // [[p]]
1209 // Minimal expectations -- we're just testing that it doesn't crash, since
1210 // enums aren't interpreted.
1211 runDataflow(
1212 Code,
1213 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1214 ASTContext &ASTCtx) {
1215 EXPECT_THAT(Results.keys(), UnorderedElementsAre("p"));
1219 TEST(TransferTest, DerivedBaseMemberClass) {
1220 std::string Code = R"(
1221 class A {
1222 int ADefault;
1223 protected:
1224 int AProtected;
1225 private:
1226 int APrivate;
1227 public:
1228 int APublic;
1230 private:
1231 friend void target();
1234 class B : public A {
1235 int BDefault;
1236 protected:
1237 int BProtected;
1238 private:
1239 int BPrivate;
1241 private:
1242 friend void target();
1245 void target() {
1246 B Foo;
1247 (void)Foo.ADefault;
1248 (void)Foo.AProtected;
1249 (void)Foo.APrivate;
1250 (void)Foo.APublic;
1251 (void)Foo.BDefault;
1252 (void)Foo.BProtected;
1253 (void)Foo.BPrivate;
1254 // [[p]]
1257 runDataflow(
1258 Code,
1259 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1260 ASTContext &ASTCtx) {
1261 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1262 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1264 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1265 ASSERT_THAT(FooDecl, NotNull());
1266 ASSERT_TRUE(FooDecl->getType()->isRecordType());
1268 // Derived-class fields.
1269 const FieldDecl *BDefaultDecl = nullptr;
1270 const FieldDecl *BProtectedDecl = nullptr;
1271 const FieldDecl *BPrivateDecl = nullptr;
1272 for (const FieldDecl *Field :
1273 FooDecl->getType()->getAsRecordDecl()->fields()) {
1274 if (Field->getNameAsString() == "BDefault") {
1275 BDefaultDecl = Field;
1276 } else if (Field->getNameAsString() == "BProtected") {
1277 BProtectedDecl = Field;
1278 } else if (Field->getNameAsString() == "BPrivate") {
1279 BPrivateDecl = Field;
1280 } else {
1281 FAIL() << "Unexpected field: " << Field->getNameAsString();
1284 ASSERT_THAT(BDefaultDecl, NotNull());
1285 ASSERT_THAT(BProtectedDecl, NotNull());
1286 ASSERT_THAT(BPrivateDecl, NotNull());
1288 // Base-class fields.
1289 const FieldDecl *ADefaultDecl = nullptr;
1290 const FieldDecl *APrivateDecl = nullptr;
1291 const FieldDecl *AProtectedDecl = nullptr;
1292 const FieldDecl *APublicDecl = nullptr;
1293 for (const clang::CXXBaseSpecifier &Base :
1294 FooDecl->getType()->getAsCXXRecordDecl()->bases()) {
1295 QualType BaseType = Base.getType();
1296 ASSERT_TRUE(BaseType->isRecordType());
1297 for (const FieldDecl *Field : BaseType->getAsRecordDecl()->fields()) {
1298 if (Field->getNameAsString() == "ADefault") {
1299 ADefaultDecl = Field;
1300 } else if (Field->getNameAsString() == "AProtected") {
1301 AProtectedDecl = Field;
1302 } else if (Field->getNameAsString() == "APrivate") {
1303 APrivateDecl = Field;
1304 } else if (Field->getNameAsString() == "APublic") {
1305 APublicDecl = Field;
1306 } else {
1307 FAIL() << "Unexpected field: " << Field->getNameAsString();
1311 ASSERT_THAT(ADefaultDecl, NotNull());
1312 ASSERT_THAT(AProtectedDecl, NotNull());
1313 ASSERT_THAT(APrivateDecl, NotNull());
1314 ASSERT_THAT(APublicDecl, NotNull());
1316 ASSERT_TRUE(
1317 isa<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)));
1321 static void derivedBaseMemberExpectations(
1322 const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1323 ASTContext &ASTCtx) {
1324 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1325 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1327 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1328 ASSERT_THAT(FooDecl, NotNull());
1330 ASSERT_TRUE(FooDecl->getType()->isRecordType());
1331 const FieldDecl *BarDecl = nullptr;
1332 for (const clang::CXXBaseSpecifier &Base :
1333 FooDecl->getType()->getAsCXXRecordDecl()->bases()) {
1334 QualType BaseType = Base.getType();
1335 ASSERT_TRUE(BaseType->isStructureType());
1337 for (const FieldDecl *Field : BaseType->getAsRecordDecl()->fields()) {
1338 if (Field->getNameAsString() == "Bar") {
1339 BarDecl = Field;
1340 } else {
1341 FAIL() << "Unexpected field: " << Field->getNameAsString();
1345 ASSERT_THAT(BarDecl, NotNull());
1347 const auto &FooLoc =
1348 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
1349 const auto &FooVal = *cast<RecordValue>(Env.getValue(FooLoc));
1350 EXPECT_EQ(&FooVal.getLoc(), &FooLoc);
1353 TEST(TransferTest, DerivedBaseMemberStructDefault) {
1354 std::string Code = R"(
1355 struct A {
1356 int Bar;
1358 struct B : public A {
1361 void target() {
1362 B Foo;
1363 (void)Foo.Bar;
1364 // [[p]]
1367 runDataflow(Code, derivedBaseMemberExpectations);
1370 TEST(TransferTest, DerivedBaseMemberPrivateFriend) {
1371 // Include an access to `Foo.Bar` to verify the analysis doesn't crash on that
1372 // access.
1373 std::string Code = R"(
1374 struct A {
1375 private:
1376 friend void target();
1377 int Bar;
1379 struct B : public A {
1382 void target() {
1383 B Foo;
1384 (void)Foo.Bar;
1385 // [[p]]
1388 runDataflow(Code, derivedBaseMemberExpectations);
1391 TEST(TransferTest, ClassMember) {
1392 std::string Code = R"(
1393 class A {
1394 public:
1395 int Bar;
1398 void target(A Foo) {
1399 int Baz = Foo.Bar;
1400 // [[p]]
1403 runDataflow(
1404 Code,
1405 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1406 ASTContext &ASTCtx) {
1407 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1408 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1410 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1411 ASSERT_THAT(FooDecl, NotNull());
1413 ASSERT_TRUE(FooDecl->getType()->isClassType());
1414 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1416 FieldDecl *BarDecl = nullptr;
1417 for (FieldDecl *Field : FooFields) {
1418 if (Field->getNameAsString() == "Bar") {
1419 BarDecl = Field;
1420 } else {
1421 FAIL() << "Unexpected field: " << Field->getNameAsString();
1424 ASSERT_THAT(BarDecl, NotNull());
1426 const auto *FooLoc =
1427 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
1428 const auto *BarVal =
1429 cast<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env));
1431 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1432 ASSERT_THAT(BazDecl, NotNull());
1434 EXPECT_EQ(Env.getValue(*BazDecl), BarVal);
1438 TEST(TransferTest, BaseClassInitializer) {
1439 using ast_matchers::cxxConstructorDecl;
1440 using ast_matchers::hasName;
1441 using ast_matchers::ofClass;
1443 std::string Code = R"(
1444 class A {
1445 public:
1446 A(int I) : Bar(I) {}
1447 int Bar;
1450 class B : public A {
1451 public:
1452 B(int I) : A(I) {
1453 (void)0;
1454 // [[p]]
1458 ASSERT_THAT_ERROR(
1459 checkDataflow<NoopAnalysis>(
1460 AnalysisInputs<NoopAnalysis>(
1461 Code, cxxConstructorDecl(ofClass(hasName("B"))),
1462 [](ASTContext &C, Environment &) { return NoopAnalysis(C); })
1463 .withASTBuildArgs(
1464 {"-fsyntax-only", "-fno-delayed-template-parsing",
1465 "-std=" + std::string(LangStandard::getLangStandardForKind(
1466 LangStandard::lang_cxx17)
1467 .getName())}),
1468 /*VerifyResults=*/
1469 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1470 const AnalysisOutputs &) {
1471 // Regression test to verify that base-class initializers do not
1472 // trigger an assertion. If we add support for such initializers in
1473 // the future, we can expand this test to check more specific
1474 // properties.
1475 EXPECT_THAT(Results.keys(), UnorderedElementsAre("p"));
1477 llvm::Succeeded());
1480 TEST(TransferTest, StructModeledFieldsWithAccessor) {
1481 std::string Code = R"(
1482 class S {
1483 int *Ptr;
1484 int *PtrNonConst;
1485 int Int;
1486 int IntWithInc;
1487 int IntNotAccessed;
1488 int IntRef;
1489 public:
1490 int *getPtr() const { return Ptr; }
1491 int *getPtrNonConst() { return PtrNonConst; }
1492 int getInt(int i) const { return Int; }
1493 int getWithInc(int i) { IntWithInc += i; return IntWithInc; }
1494 int getIntNotAccessed() const { return IntNotAccessed; }
1495 int getIntNoDefinition() const;
1496 int &getIntRef() { return IntRef; }
1497 void returnVoid() const { return; }
1500 void target() {
1501 S s;
1502 int *p1 = s.getPtr();
1503 int *p2 = s.getPtrNonConst();
1504 int i1 = s.getInt(1);
1505 int i2 = s.getWithInc(1);
1506 int i3 = s.getIntNoDefinition();
1507 int &iref = s.getIntRef();
1509 // Regression test: Don't crash on an indirect call (which doesn't have
1510 // an associated `CXXMethodDecl`).
1511 auto ptr_to_member_fn = &S::getPtr;
1512 p1 = (s.*ptr_to_member_fn)();
1514 // Regression test: Don't crash on a return statement without a value.
1515 s.returnVoid();
1516 // [[p]]
1519 runDataflow(
1520 Code,
1521 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1522 ASTContext &ASTCtx) {
1523 const Environment &Env =
1524 getEnvironmentAtAnnotation(Results, "p");
1525 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s");
1526 std::vector<const ValueDecl*> Fields;
1527 for (auto [Field, _] : SLoc.children())
1528 Fields.push_back(Field);
1529 // Only the fields that have simple accessor methods (that have a
1530 // single statement body that returns the member variable) should be
1531 // modeled.
1532 ASSERT_THAT(Fields, UnorderedElementsAre(
1533 findValueDecl(ASTCtx, "Ptr"), findValueDecl(ASTCtx, "PtrNonConst"),
1534 findValueDecl(ASTCtx, "Int"), findValueDecl(ASTCtx, "IntRef")));
1538 TEST(TransferTest, StructModeledFieldsWithComplicatedInheritance) {
1539 std::string Code = R"(
1540 struct Base1 {
1541 int base1_1;
1542 int base1_2;
1544 struct Intermediate : Base1 {
1545 int intermediate_1;
1546 int intermediate_2;
1548 struct Base2 {
1549 int base2_1;
1550 int base2_2;
1552 struct MostDerived : public Intermediate, Base2 {
1553 int most_derived_1;
1554 int most_derived_2;
1557 void target() {
1558 MostDerived MD;
1559 MD.base1_2 = 1;
1560 MD.intermediate_2 = 1;
1561 MD.base2_2 = 1;
1562 MD.most_derived_2 = 1;
1563 // [[p]]
1566 runDataflow(
1567 Code,
1568 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1569 ASTContext &ASTCtx) {
1570 const Environment &Env =
1571 getEnvironmentAtAnnotation(Results, "p");
1573 // Only the accessed fields should exist in the model.
1574 auto &MDLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "MD");
1575 std::vector<const ValueDecl*> Fields;
1576 for (auto [Field, _] : MDLoc.children())
1577 Fields.push_back(Field);
1578 ASSERT_THAT(Fields, UnorderedElementsAre(
1579 findValueDecl(ASTCtx, "base1_2"),
1580 findValueDecl(ASTCtx, "intermediate_2"),
1581 findValueDecl(ASTCtx, "base2_2"),
1582 findValueDecl(ASTCtx, "most_derived_2")));
1586 TEST(TransferTest, StructInitializerListWithComplicatedInheritance) {
1587 std::string Code = R"(
1588 struct Base1 {
1589 int base1;
1591 struct Intermediate : Base1 {
1592 int intermediate;
1594 struct Base2 {
1595 int base2;
1597 struct MostDerived : public Intermediate, Base2 {
1598 int most_derived;
1601 void target() {
1602 MostDerived MD = {};
1603 // [[p]]
1606 runDataflow(
1607 Code,
1608 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1609 ASTContext &ASTCtx) {
1610 const Environment &Env =
1611 getEnvironmentAtAnnotation(Results, "p");
1613 // When a struct is initialized with a initializer list, all the
1614 // fields are considered "accessed", and therefore do exist.
1615 auto &MD = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "MD");
1616 ASSERT_THAT(cast<IntegerValue>(
1617 getFieldValue(&MD, *findValueDecl(ASTCtx, "base1"), Env)),
1618 NotNull());
1619 ASSERT_THAT(cast<IntegerValue>(
1620 getFieldValue(&MD, *findValueDecl(ASTCtx, "intermediate"), Env)),
1621 NotNull());
1622 ASSERT_THAT(cast<IntegerValue>(
1623 getFieldValue(&MD, *findValueDecl(ASTCtx, "base2"), Env)),
1624 NotNull());
1625 ASSERT_THAT(cast<IntegerValue>(
1626 getFieldValue(&MD, *findValueDecl(ASTCtx, "most_derived"), Env)),
1627 NotNull());
1631 TEST(TransferTest, ReferenceMember) {
1632 std::string Code = R"(
1633 struct A {
1634 int &Bar;
1637 void target(A Foo) {
1638 int Baz = Foo.Bar;
1639 // [[p]]
1642 runDataflow(
1643 Code,
1644 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1645 ASTContext &ASTCtx) {
1646 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1647 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1649 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1650 ASSERT_THAT(FooDecl, NotNull());
1652 ASSERT_TRUE(FooDecl->getType()->isStructureType());
1653 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1655 FieldDecl *BarDecl = nullptr;
1656 for (FieldDecl *Field : FooFields) {
1657 if (Field->getNameAsString() == "Bar") {
1658 BarDecl = Field;
1659 } else {
1660 FAIL() << "Unexpected field: " << Field->getNameAsString();
1663 ASSERT_THAT(BarDecl, NotNull());
1665 const auto *FooLoc =
1666 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
1667 const auto *BarReferentVal =
1668 cast<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env));
1670 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1671 ASSERT_THAT(BazDecl, NotNull());
1673 EXPECT_EQ(Env.getValue(*BazDecl), BarReferentVal);
1677 TEST(TransferTest, StructThisMember) {
1678 std::string Code = R"(
1679 struct A {
1680 int Bar;
1682 struct B {
1683 int Baz;
1686 B Qux;
1688 void target() {
1689 int Foo = Bar;
1690 int Quux = Qux.Baz;
1691 // [[p]]
1695 runDataflow(
1696 Code,
1697 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1698 ASTContext &ASTCtx) {
1699 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1700 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1702 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
1703 ASSERT_THAT(ThisLoc, NotNull());
1705 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1706 ASSERT_THAT(BarDecl, NotNull());
1708 const auto *BarLoc =
1709 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl));
1710 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1712 const Value *BarVal = Env.getValue(*BarLoc);
1713 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1715 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1716 ASSERT_THAT(FooDecl, NotNull());
1717 EXPECT_EQ(Env.getValue(*FooDecl), BarVal);
1719 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1720 ASSERT_THAT(QuxDecl, NotNull());
1722 ASSERT_TRUE(QuxDecl->getType()->isStructureType());
1723 auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields();
1725 FieldDecl *BazDecl = nullptr;
1726 for (FieldDecl *Field : QuxFields) {
1727 if (Field->getNameAsString() == "Baz") {
1728 BazDecl = Field;
1729 } else {
1730 FAIL() << "Unexpected field: " << Field->getNameAsString();
1733 ASSERT_THAT(BazDecl, NotNull());
1735 const auto *QuxLoc =
1736 cast<RecordStorageLocation>(ThisLoc->getChild(*QuxDecl));
1737 EXPECT_THAT(dyn_cast<RecordValue>(Env.getValue(*QuxLoc)), NotNull());
1739 const auto *BazVal =
1740 cast<IntegerValue>(getFieldValue(QuxLoc, *BazDecl, Env));
1742 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
1743 ASSERT_THAT(QuuxDecl, NotNull());
1744 EXPECT_EQ(Env.getValue(*QuuxDecl), BazVal);
1748 TEST(TransferTest, ClassThisMember) {
1749 std::string Code = R"(
1750 class A {
1751 int Bar;
1753 class B {
1754 public:
1755 int Baz;
1758 B Qux;
1760 void target() {
1761 int Foo = Bar;
1762 int Quux = Qux.Baz;
1763 // [[p]]
1767 runDataflow(
1768 Code,
1769 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1770 ASTContext &ASTCtx) {
1771 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1772 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1774 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
1776 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1777 ASSERT_THAT(BarDecl, NotNull());
1779 const auto *BarLoc =
1780 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl));
1781 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1783 const Value *BarVal = Env.getValue(*BarLoc);
1784 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1786 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1787 ASSERT_THAT(FooDecl, NotNull());
1788 EXPECT_EQ(Env.getValue(*FooDecl), BarVal);
1790 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1791 ASSERT_THAT(QuxDecl, NotNull());
1793 ASSERT_TRUE(QuxDecl->getType()->isClassType());
1794 auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields();
1796 FieldDecl *BazDecl = nullptr;
1797 for (FieldDecl *Field : QuxFields) {
1798 if (Field->getNameAsString() == "Baz") {
1799 BazDecl = Field;
1800 } else {
1801 FAIL() << "Unexpected field: " << Field->getNameAsString();
1804 ASSERT_THAT(BazDecl, NotNull());
1806 const auto *QuxLoc =
1807 cast<RecordStorageLocation>(ThisLoc->getChild(*QuxDecl));
1808 EXPECT_THAT(dyn_cast<RecordValue>(Env.getValue(*QuxLoc)), NotNull());
1810 const auto *BazVal =
1811 cast<IntegerValue>(getFieldValue(QuxLoc, *BazDecl, Env));
1813 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
1814 ASSERT_THAT(QuuxDecl, NotNull());
1815 EXPECT_EQ(Env.getValue(*QuuxDecl), BazVal);
1819 TEST(TransferTest, UnionThisMember) {
1820 std::string Code = R"(
1821 union A {
1822 int Foo;
1823 int Bar;
1825 void target() {
1826 A a;
1827 // Mention the fields to ensure they're included in the analysis.
1828 (void)a.Foo;
1829 (void)a.Bar;
1830 // [[p]]
1834 runDataflow(
1835 Code,
1836 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1837 ASTContext &ASTCtx) {
1838 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1839 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1841 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
1842 ASSERT_THAT(ThisLoc, NotNull());
1844 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1845 ASSERT_THAT(FooDecl, NotNull());
1847 const auto *FooLoc =
1848 cast<ScalarStorageLocation>(ThisLoc->getChild(*FooDecl));
1849 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
1851 const Value *FooVal = Env.getValue(*FooLoc);
1852 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
1854 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1855 ASSERT_THAT(BarDecl, NotNull());
1857 const auto *BarLoc =
1858 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl));
1859 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1861 const Value *BarVal = Env.getValue(*BarLoc);
1862 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1866 TEST(TransferTest, StructThisInLambda) {
1867 std::string ThisCaptureCode = R"(
1868 struct A {
1869 void frob() {
1870 [this]() {
1871 int Foo = Bar;
1872 // [[p1]]
1873 }();
1876 int Bar;
1879 runDataflow(
1880 ThisCaptureCode,
1881 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1882 ASTContext &ASTCtx) {
1883 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1"));
1884 const Environment &Env = getEnvironmentAtAnnotation(Results, "p1");
1886 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
1887 ASSERT_THAT(ThisLoc, NotNull());
1889 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1890 ASSERT_THAT(BarDecl, NotNull());
1892 const auto *BarLoc =
1893 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl));
1894 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1896 const Value *BarVal = Env.getValue(*BarLoc);
1897 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1899 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1900 ASSERT_THAT(FooDecl, NotNull());
1901 EXPECT_EQ(Env.getValue(*FooDecl), BarVal);
1903 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()");
1905 std::string RefCaptureDefaultCode = R"(
1906 struct A {
1907 void frob() {
1908 [&]() {
1909 int Foo = Bar;
1910 // [[p2]]
1911 }();
1914 int Bar;
1917 runDataflow(
1918 RefCaptureDefaultCode,
1919 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1920 ASTContext &ASTCtx) {
1921 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p2"));
1922 const Environment &Env = getEnvironmentAtAnnotation(Results, "p2");
1924 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
1925 ASSERT_THAT(ThisLoc, NotNull());
1927 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1928 ASSERT_THAT(BarDecl, NotNull());
1930 const auto *BarLoc =
1931 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl));
1932 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1934 const Value *BarVal = Env.getValue(*BarLoc);
1935 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1937 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1938 ASSERT_THAT(FooDecl, NotNull());
1939 EXPECT_EQ(Env.getValue(*FooDecl), BarVal);
1941 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()");
1943 std::string FreeFunctionLambdaCode = R"(
1944 void foo() {
1945 int Bar;
1946 [&]() {
1947 int Foo = Bar;
1948 // [[p3]]
1949 }();
1952 runDataflow(
1953 FreeFunctionLambdaCode,
1954 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1955 ASTContext &ASTCtx) {
1956 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p3"));
1957 const Environment &Env = getEnvironmentAtAnnotation(Results, "p3");
1959 EXPECT_THAT(Env.getThisPointeeStorageLocation(), IsNull());
1961 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()");
1964 TEST(TransferTest, ConstructorInitializer) {
1965 std::string Code = R"(
1966 struct target {
1967 int Bar;
1969 target(int Foo) : Bar(Foo) {
1970 int Qux = Bar;
1971 // [[p]]
1975 runDataflow(
1976 Code,
1977 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1978 ASTContext &ASTCtx) {
1979 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1980 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1982 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
1983 ASSERT_THAT(ThisLoc, NotNull());
1985 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1986 ASSERT_THAT(FooDecl, NotNull());
1988 const auto *FooVal = cast<IntegerValue>(Env.getValue(*FooDecl));
1990 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1991 ASSERT_THAT(QuxDecl, NotNull());
1992 EXPECT_EQ(Env.getValue(*QuxDecl), FooVal);
1996 TEST(TransferTest, DefaultInitializer) {
1997 std::string Code = R"(
1998 struct target {
1999 int Bar;
2000 int Baz = Bar;
2002 target(int Foo) : Bar(Foo) {
2003 int Qux = Baz;
2004 // [[p]]
2008 runDataflow(
2009 Code,
2010 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2011 ASTContext &ASTCtx) {
2012 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2013 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2015 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
2016 ASSERT_THAT(ThisLoc, NotNull());
2018 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2019 ASSERT_THAT(FooDecl, NotNull());
2021 const auto *FooVal = cast<IntegerValue>(Env.getValue(*FooDecl));
2023 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
2024 ASSERT_THAT(QuxDecl, NotNull());
2025 EXPECT_EQ(Env.getValue(*QuxDecl), FooVal);
2029 TEST(TransferTest, DefaultInitializerReference) {
2030 std::string Code = R"(
2031 struct target {
2032 int &Bar;
2033 int &Baz = Bar;
2035 target(int &Foo) : Bar(Foo) {
2036 int &Qux = Baz;
2037 // [[p]]
2041 runDataflow(
2042 Code,
2043 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2044 ASTContext &ASTCtx) {
2045 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2046 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2048 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
2049 ASSERT_THAT(ThisLoc, NotNull());
2051 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2052 ASSERT_THAT(FooDecl, NotNull());
2054 const auto *FooLoc = Env.getStorageLocation(*FooDecl);
2056 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
2057 ASSERT_THAT(QuxDecl, NotNull());
2059 const auto *QuxLoc = Env.getStorageLocation(*QuxDecl);
2060 EXPECT_EQ(QuxLoc, FooLoc);
2064 TEST(TransferTest, TemporaryObject) {
2065 std::string Code = R"(
2066 struct A {
2067 int Bar;
2070 void target() {
2071 A Foo = A();
2072 (void)Foo.Bar;
2073 // [[p]]
2076 runDataflow(
2077 Code,
2078 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2079 ASTContext &ASTCtx) {
2080 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2081 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2083 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2084 ASSERT_THAT(FooDecl, NotNull());
2086 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2087 ASSERT_THAT(BarDecl, NotNull());
2089 const auto *FooLoc =
2090 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2091 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
2095 TEST(TransferTest, ElidableConstructor) {
2096 // This test is effectively the same as TransferTest.TemporaryObject, but
2097 // the code is compiled as C++ 14.
2098 std::string Code = R"(
2099 struct A {
2100 int Bar;
2103 void target() {
2104 A Foo = A();
2105 (void)Foo.Bar;
2106 // [[p]]
2109 runDataflow(
2110 Code,
2111 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2112 ASTContext &ASTCtx) {
2113 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2114 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2116 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2117 ASSERT_THAT(FooDecl, NotNull());
2119 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2120 ASSERT_THAT(BarDecl, NotNull());
2122 const auto *FooLoc =
2123 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2124 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
2126 LangStandard::lang_cxx14);
2129 TEST(TransferTest, AssignmentOperator) {
2130 std::string Code = R"(
2131 struct A {
2132 int Baz;
2135 void target() {
2136 A Foo = { 1 };
2137 A Bar = { 2 };
2138 // [[p1]]
2139 Foo = Bar;
2140 // [[p2]]
2141 Foo.Baz = 3;
2142 // [[p3]]
2145 runDataflow(
2146 Code,
2147 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2148 ASTContext &ASTCtx) {
2149 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2150 ASSERT_THAT(FooDecl, NotNull());
2152 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2153 ASSERT_THAT(BarDecl, NotNull());
2155 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2156 ASSERT_THAT(BazDecl, NotNull());
2158 // Before copy assignment.
2160 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
2162 const auto *FooLoc1 =
2163 cast<RecordStorageLocation>(Env1.getStorageLocation(*FooDecl));
2164 const auto *BarLoc1 =
2165 cast<RecordStorageLocation>(Env1.getStorageLocation(*BarDecl));
2166 EXPECT_FALSE(recordsEqual(*FooLoc1, *BarLoc1, Env1));
2168 const auto *FooBazVal1 =
2169 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env1));
2170 const auto *BarBazVal1 =
2171 cast<IntegerValue>(getFieldValue(BarLoc1, *BazDecl, Env1));
2172 EXPECT_NE(FooBazVal1, BarBazVal1);
2175 // After copy assignment.
2177 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
2179 const auto *FooLoc2 =
2180 cast<RecordStorageLocation>(Env2.getStorageLocation(*FooDecl));
2181 const auto *BarLoc2 =
2182 cast<RecordStorageLocation>(Env2.getStorageLocation(*BarDecl));
2184 const auto *FooVal2 = cast<RecordValue>(Env2.getValue(*FooLoc2));
2185 const auto *BarVal2 = cast<RecordValue>(Env2.getValue(*BarLoc2));
2186 EXPECT_NE(FooVal2, BarVal2);
2188 EXPECT_TRUE(recordsEqual(*FooLoc2, *BarLoc2, Env2));
2190 const auto *FooBazVal2 =
2191 cast<IntegerValue>(getFieldValue(FooLoc2, *BazDecl, Env2));
2192 const auto *BarBazVal2 =
2193 cast<IntegerValue>(getFieldValue(BarLoc2, *BazDecl, Env2));
2194 EXPECT_EQ(FooBazVal2, BarBazVal2);
2197 // After value update.
2199 const Environment &Env3 = getEnvironmentAtAnnotation(Results, "p3");
2201 const auto *FooLoc3 =
2202 cast<RecordStorageLocation>(Env3.getStorageLocation(*FooDecl));
2203 const auto *BarLoc3 =
2204 cast<RecordStorageLocation>(Env3.getStorageLocation(*BarDecl));
2205 EXPECT_FALSE(recordsEqual(*FooLoc3, *BarLoc3, Env3));
2207 const auto *FooBazVal3 =
2208 cast<IntegerValue>(getFieldValue(FooLoc3, *BazDecl, Env3));
2209 const auto *BarBazVal3 =
2210 cast<IntegerValue>(getFieldValue(BarLoc3, *BazDecl, Env3));
2211 EXPECT_NE(FooBazVal3, BarBazVal3);
2216 TEST(TransferTest, AssignmentOperatorFromBase) {
2217 // This is a crash repro. We don't model the copy this case, so no
2218 // expectations on the copied field of the base class are checked.
2219 std::string Code = R"(
2220 struct Base {
2221 int base;
2223 struct Derived : public Base {
2224 using Base::operator=;
2225 int derived;
2227 void target(Base B, Derived D) {
2228 D.base = 1;
2229 D.derived = 1;
2230 D = B;
2231 // [[p]]
2234 runDataflow(
2235 Code,
2236 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2237 ASTContext &ASTCtx) {});
2240 TEST(TransferTest, AssignmentOperatorFromCallResult) {
2241 std::string Code = R"(
2242 struct A {};
2243 A ReturnA();
2245 void target() {
2246 A MyA;
2247 MyA = ReturnA();
2250 runDataflow(
2251 Code,
2252 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2253 ASTContext &ASTCtx) {
2254 // As of this writing, we don't produce a `Value` for the call
2255 // `ReturnA()`. The only condition we're testing for is that the
2256 // analysis should not crash in this case.
2260 TEST(TransferTest, AssignmentOperatorWithInitAndInheritance) {
2261 // This is a crash repro.
2262 std::string Code = R"(
2263 struct B { int Foo; };
2264 struct S : public B {};
2265 void target() {
2266 S S1 = { 1 };
2267 S S2;
2268 S S3;
2269 S1 = S2; // Only Dst has InitListExpr.
2270 S3 = S1; // Only Src has InitListExpr.
2271 // [[p]]
2274 runDataflow(
2275 Code,
2276 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2277 ASTContext &ASTCtx) {});
2280 TEST(TransferTest, CopyConstructor) {
2281 std::string Code = R"(
2282 struct A {
2283 int Baz;
2286 void target() {
2287 A Foo = { 1 };
2288 A Bar = Foo;
2289 // [[after_copy]]
2290 Foo.Baz = 2;
2291 // [[after_update]]
2294 runDataflow(
2295 Code,
2296 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2297 ASTContext &ASTCtx) {
2298 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2299 ASSERT_THAT(FooDecl, NotNull());
2301 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2302 ASSERT_THAT(BarDecl, NotNull());
2304 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2305 ASSERT_THAT(BazDecl, NotNull());
2307 // after_copy
2309 const Environment &Env =
2310 getEnvironmentAtAnnotation(Results, "after_copy");
2312 const auto *FooLoc =
2313 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2314 const auto *BarLoc =
2315 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl));
2317 // `Foo` and `Bar` have different `RecordValue`s associated with them.
2318 const auto *FooVal = cast<RecordValue>(Env.getValue(*FooLoc));
2319 const auto *BarVal = cast<RecordValue>(Env.getValue(*BarLoc));
2320 EXPECT_NE(FooVal, BarVal);
2322 // But the records compare equal.
2323 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env));
2325 // In particular, the value of `Baz` in both records is the same.
2326 const auto *FooBazVal =
2327 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env));
2328 const auto *BarBazVal =
2329 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env));
2330 EXPECT_EQ(FooBazVal, BarBazVal);
2333 // after_update
2335 const Environment &Env =
2336 getEnvironmentAtAnnotation(Results, "after_update");
2338 const auto *FooLoc =
2339 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2340 const auto *BarLoc =
2341 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl));
2343 EXPECT_FALSE(recordsEqual(*FooLoc, *BarLoc, Env));
2345 const auto *FooBazVal =
2346 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env));
2347 const auto *BarBazVal =
2348 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env));
2349 EXPECT_NE(FooBazVal, BarBazVal);
2354 TEST(TransferTest, CopyConstructorWithDefaultArgument) {
2355 std::string Code = R"(
2356 struct A {
2357 int Baz;
2358 A() = default;
2359 A(const A& a, bool def = true) { Baz = a.Baz; }
2362 void target() {
2363 A Foo;
2364 (void)Foo.Baz;
2365 A Bar = Foo;
2366 // [[p]]
2369 runDataflow(
2370 Code,
2371 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2372 ASTContext &ASTCtx) {
2373 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2374 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2376 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2377 ASSERT_THAT(FooDecl, NotNull());
2379 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2380 ASSERT_THAT(BarDecl, NotNull());
2382 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2383 ASSERT_THAT(BazDecl, NotNull());
2385 const auto *FooLoc =
2386 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2387 const auto *BarLoc =
2388 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl));
2389 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env));
2391 const auto *FooBazVal =
2392 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env));
2393 const auto *BarBazVal =
2394 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env));
2395 EXPECT_EQ(FooBazVal, BarBazVal);
2399 TEST(TransferTest, CopyConstructorWithParens) {
2400 std::string Code = R"(
2401 struct A {
2402 int Baz;
2405 void target() {
2406 A Foo;
2407 (void)Foo.Baz;
2408 A Bar((A(Foo)));
2409 // [[p]]
2412 runDataflow(
2413 Code,
2414 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2415 ASTContext &ASTCtx) {
2416 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2417 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2419 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2420 ASSERT_THAT(FooDecl, NotNull());
2422 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2423 ASSERT_THAT(BarDecl, NotNull());
2425 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2426 ASSERT_THAT(BazDecl, NotNull());
2428 const auto *FooLoc =
2429 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2430 const auto *BarLoc =
2431 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl));
2432 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env));
2434 const auto *FooBazVal =
2435 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env));
2436 const auto *BarBazVal =
2437 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env));
2438 EXPECT_EQ(FooBazVal, BarBazVal);
2442 TEST(TransferTest, CopyConstructorWithInitializerListAsSyntacticSugar) {
2443 std::string Code = R"(
2444 struct A {
2445 int Baz;
2447 void target() {
2448 A Foo = {3};
2449 (void)Foo.Baz;
2450 A Bar = {A(Foo)};
2451 // [[p]]
2454 runDataflow(
2455 Code,
2456 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2457 ASTContext &ASTCtx) {
2458 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2460 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2462 const auto &FooLoc =
2463 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo");
2464 const auto &BarLoc =
2465 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar");
2467 const auto *FooBazVal =
2468 cast<IntegerValue>(getFieldValue(&FooLoc, *BazDecl, Env));
2469 const auto *BarBazVal =
2470 cast<IntegerValue>(getFieldValue(&BarLoc, *BazDecl, Env));
2471 EXPECT_EQ(FooBazVal, BarBazVal);
2475 TEST(TransferTest, CopyConstructorArgIsRefReturnedByFunction) {
2476 // This is a crash repro.
2477 std::string Code = R"(
2478 struct S {};
2479 const S &returnsSRef();
2480 void target() {
2481 S s(returnsSRef());
2484 runDataflow(
2485 Code,
2486 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2487 ASTContext &ASTCtx) {});
2490 TEST(TransferTest, MoveConstructor) {
2491 std::string Code = R"(
2492 namespace std {
2494 template <typename T> struct remove_reference { using type = T; };
2495 template <typename T> struct remove_reference<T&> { using type = T; };
2496 template <typename T> struct remove_reference<T&&> { using type = T; };
2498 template <typename T>
2499 using remove_reference_t = typename remove_reference<T>::type;
2501 template <typename T>
2502 std::remove_reference_t<T>&& move(T&& x);
2504 } // namespace std
2506 struct A {
2507 int Baz;
2510 void target() {
2511 A Foo;
2512 A Bar;
2513 (void)Foo.Baz;
2514 // [[p1]]
2515 Foo = std::move(Bar);
2516 // [[p2]]
2519 runDataflow(
2520 Code,
2521 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2522 ASTContext &ASTCtx) {
2523 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
2524 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
2525 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
2527 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2528 ASSERT_THAT(FooDecl, NotNull());
2530 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2531 ASSERT_THAT(BarDecl, NotNull());
2533 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2534 ASSERT_THAT(BazDecl, NotNull());
2536 const auto *FooLoc1 =
2537 cast<RecordStorageLocation>(Env1.getStorageLocation(*FooDecl));
2538 const auto *BarLoc1 =
2539 cast<RecordStorageLocation>(Env1.getStorageLocation(*BarDecl));
2541 EXPECT_FALSE(recordsEqual(*FooLoc1, *BarLoc1, Env1));
2543 const auto *FooVal1 = cast<RecordValue>(Env1.getValue(*FooLoc1));
2544 const auto *BarVal1 = cast<RecordValue>(Env1.getValue(*BarLoc1));
2545 EXPECT_NE(FooVal1, BarVal1);
2547 const auto *FooBazVal1 =
2548 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env1));
2549 const auto *BarBazVal1 =
2550 cast<IntegerValue>(getFieldValue(BarLoc1, *BazDecl, Env1));
2551 EXPECT_NE(FooBazVal1, BarBazVal1);
2553 const auto *FooLoc2 =
2554 cast<RecordStorageLocation>(Env2.getStorageLocation(*FooDecl));
2555 const auto *FooVal2 = cast<RecordValue>(Env2.getValue(*FooLoc2));
2556 EXPECT_NE(FooVal2, BarVal1);
2557 EXPECT_TRUE(recordsEqual(*FooLoc2, Env2, *BarLoc1, Env1));
2559 const auto *FooBazVal2 =
2560 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env2));
2561 EXPECT_EQ(FooBazVal2, BarBazVal1);
2565 TEST(TransferTest, BindTemporary) {
2566 std::string Code = R"(
2567 struct A {
2568 virtual ~A() = default;
2570 int Baz;
2573 void target(A Foo) {
2574 int Bar = A(Foo).Baz;
2575 // [[p]]
2578 runDataflow(
2579 Code,
2580 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2581 ASTContext &ASTCtx) {
2582 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2583 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2585 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2586 ASSERT_THAT(FooDecl, NotNull());
2588 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2589 ASSERT_THAT(BarDecl, NotNull());
2591 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2592 ASSERT_THAT(BazDecl, NotNull());
2594 const auto &FooLoc =
2595 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2596 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));
2597 EXPECT_EQ(BarVal, getFieldValue(&FooLoc, *BazDecl, Env));
2601 TEST(TransferTest, StaticCast) {
2602 std::string Code = R"(
2603 void target(int Foo) {
2604 int Bar = static_cast<int>(Foo);
2605 // [[p]]
2608 runDataflow(
2609 Code,
2610 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2611 ASTContext &ASTCtx) {
2612 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2613 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2615 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2616 ASSERT_THAT(FooDecl, NotNull());
2618 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2619 ASSERT_THAT(BarDecl, NotNull());
2621 const auto *FooVal = Env.getValue(*FooDecl);
2622 const auto *BarVal = Env.getValue(*BarDecl);
2623 EXPECT_TRUE(isa<IntegerValue>(FooVal));
2624 EXPECT_TRUE(isa<IntegerValue>(BarVal));
2625 EXPECT_EQ(FooVal, BarVal);
2629 TEST(TransferTest, IntegralCast) {
2630 std::string Code = R"(
2631 void target(int Foo) {
2632 long Bar = Foo;
2633 // [[p]]
2636 runDataflow(
2637 Code,
2638 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2639 ASTContext &ASTCtx) {
2640 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2641 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2643 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2644 ASSERT_THAT(FooDecl, NotNull());
2646 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2647 ASSERT_THAT(BarDecl, NotNull());
2649 const auto *FooVal = Env.getValue(*FooDecl);
2650 const auto *BarVal = Env.getValue(*BarDecl);
2651 EXPECT_TRUE(isa<IntegerValue>(FooVal));
2652 EXPECT_TRUE(isa<IntegerValue>(BarVal));
2653 EXPECT_EQ(FooVal, BarVal);
2657 TEST(TransferTest, IntegraltoBooleanCast) {
2658 std::string Code = R"(
2659 void target(int Foo) {
2660 bool Bar = Foo;
2661 // [[p]]
2664 runDataflow(
2665 Code,
2666 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2667 ASTContext &ASTCtx) {
2668 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2669 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2671 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2672 ASSERT_THAT(FooDecl, NotNull());
2674 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2675 ASSERT_THAT(BarDecl, NotNull());
2677 const auto *FooVal = Env.getValue(*FooDecl);
2678 const auto *BarVal = Env.getValue(*BarDecl);
2679 EXPECT_TRUE(isa<IntegerValue>(FooVal));
2680 EXPECT_TRUE(isa<BoolValue>(BarVal));
2684 TEST(TransferTest, IntegralToBooleanCastFromBool) {
2685 std::string Code = R"(
2686 void target(bool Foo) {
2687 int Zab = Foo;
2688 bool Bar = Zab;
2689 // [[p]]
2692 runDataflow(
2693 Code,
2694 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2695 ASTContext &ASTCtx) {
2696 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2697 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2699 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2700 ASSERT_THAT(FooDecl, NotNull());
2702 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2703 ASSERT_THAT(BarDecl, NotNull());
2705 const auto *FooVal = Env.getValue(*FooDecl);
2706 const auto *BarVal = Env.getValue(*BarDecl);
2707 EXPECT_TRUE(isa<BoolValue>(FooVal));
2708 EXPECT_TRUE(isa<BoolValue>(BarVal));
2709 EXPECT_EQ(FooVal, BarVal);
2713 TEST(TransferTest, NullToPointerCast) {
2714 std::string Code = R"(
2715 using my_nullptr_t = decltype(nullptr);
2716 struct Baz {};
2717 void target() {
2718 int *FooX = nullptr;
2719 int *FooY = nullptr;
2720 bool **Bar = nullptr;
2721 Baz *Baz = nullptr;
2722 my_nullptr_t Null = 0;
2723 // [[p]]
2726 runDataflow(
2727 Code,
2728 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2729 ASTContext &ASTCtx) {
2730 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2731 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2733 const ValueDecl *FooXDecl = findValueDecl(ASTCtx, "FooX");
2734 ASSERT_THAT(FooXDecl, NotNull());
2736 const ValueDecl *FooYDecl = findValueDecl(ASTCtx, "FooY");
2737 ASSERT_THAT(FooYDecl, NotNull());
2739 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2740 ASSERT_THAT(BarDecl, NotNull());
2742 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2743 ASSERT_THAT(BazDecl, NotNull());
2745 const ValueDecl *NullDecl = findValueDecl(ASTCtx, "Null");
2746 ASSERT_THAT(NullDecl, NotNull());
2748 const auto *FooXVal = cast<PointerValue>(Env.getValue(*FooXDecl));
2749 const auto *FooYVal = cast<PointerValue>(Env.getValue(*FooYDecl));
2750 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl));
2751 const auto *BazVal = cast<PointerValue>(Env.getValue(*BazDecl));
2752 const auto *NullVal = cast<PointerValue>(Env.getValue(*NullDecl));
2754 EXPECT_EQ(FooXVal, FooYVal);
2755 EXPECT_NE(FooXVal, BarVal);
2756 EXPECT_NE(FooXVal, BazVal);
2757 EXPECT_NE(BarVal, BazVal);
2759 const StorageLocation &FooPointeeLoc = FooXVal->getPointeeLoc();
2760 EXPECT_TRUE(isa<ScalarStorageLocation>(FooPointeeLoc));
2761 EXPECT_THAT(Env.getValue(FooPointeeLoc), IsNull());
2763 const StorageLocation &BarPointeeLoc = BarVal->getPointeeLoc();
2764 EXPECT_TRUE(isa<ScalarStorageLocation>(BarPointeeLoc));
2765 EXPECT_THAT(Env.getValue(BarPointeeLoc), IsNull());
2767 const StorageLocation &BazPointeeLoc = BazVal->getPointeeLoc();
2768 EXPECT_TRUE(isa<RecordStorageLocation>(BazPointeeLoc));
2769 EXPECT_THAT(Env.getValue(BazPointeeLoc), IsNull());
2771 const StorageLocation &NullPointeeLoc = NullVal->getPointeeLoc();
2772 EXPECT_TRUE(isa<ScalarStorageLocation>(NullPointeeLoc));
2773 EXPECT_THAT(Env.getValue(NullPointeeLoc), IsNull());
2777 TEST(TransferTest, PointerToMemberVariable) {
2778 std::string Code = R"(
2779 struct S {
2780 int i;
2782 void target() {
2783 int S::*MemberPointer = &S::i;
2784 // [[p]]
2787 runDataflow(
2788 Code,
2789 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2790 ASTContext &ASTCtx) {
2791 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2793 const ValueDecl *MemberPointerDecl =
2794 findValueDecl(ASTCtx, "MemberPointer");
2795 ASSERT_THAT(MemberPointerDecl, NotNull());
2796 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull());
2800 TEST(TransferTest, PointerToMemberFunction) {
2801 std::string Code = R"(
2802 struct S {
2803 void Method();
2805 void target() {
2806 void (S::*MemberPointer)() = &S::Method;
2807 // [[p]]
2810 runDataflow(
2811 Code,
2812 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2813 ASTContext &ASTCtx) {
2814 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2816 const ValueDecl *MemberPointerDecl =
2817 findValueDecl(ASTCtx, "MemberPointer");
2818 ASSERT_THAT(MemberPointerDecl, NotNull());
2819 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull());
2823 TEST(TransferTest, NullToMemberPointerCast) {
2824 std::string Code = R"(
2825 struct Foo {};
2826 void target() {
2827 int Foo::*MemberPointer = nullptr;
2828 // [[p]]
2831 runDataflow(
2832 Code,
2833 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2834 ASTContext &ASTCtx) {
2835 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2836 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2838 const ValueDecl *MemberPointerDecl =
2839 findValueDecl(ASTCtx, "MemberPointer");
2840 ASSERT_THAT(MemberPointerDecl, NotNull());
2841 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull());
2845 TEST(TransferTest, AddrOfValue) {
2846 std::string Code = R"(
2847 void target() {
2848 int Foo;
2849 int *Bar = &Foo;
2850 // [[p]]
2853 runDataflow(
2854 Code,
2855 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2856 ASTContext &ASTCtx) {
2857 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2858 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2860 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2861 ASSERT_THAT(FooDecl, NotNull());
2863 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2864 ASSERT_THAT(BarDecl, NotNull());
2866 const auto *FooLoc =
2867 cast<ScalarStorageLocation>(Env.getStorageLocation(*FooDecl));
2868 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl));
2869 EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc);
2873 TEST(TransferTest, AddrOfReference) {
2874 std::string Code = R"(
2875 void target(int *Foo) {
2876 int *Bar = &(*Foo);
2877 // [[p]]
2880 runDataflow(
2881 Code,
2882 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2883 ASTContext &ASTCtx) {
2884 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2885 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2887 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2888 ASSERT_THAT(FooDecl, NotNull());
2890 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2891 ASSERT_THAT(BarDecl, NotNull());
2893 const auto *FooVal = cast<PointerValue>(Env.getValue(*FooDecl));
2894 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl));
2895 EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc());
2899 TEST(TransferTest, CannotAnalyzeFunctionTemplate) {
2900 std::string Code = R"(
2901 template <typename T>
2902 void target() {}
2904 ASSERT_THAT_ERROR(
2905 checkDataflowWithNoopAnalysis(Code),
2906 llvm::FailedWithMessage("Cannot analyze templated declarations"));
2909 TEST(TransferTest, CannotAnalyzeMethodOfClassTemplate) {
2910 std::string Code = R"(
2911 template <typename T>
2912 struct A {
2913 void target() {}
2916 ASSERT_THAT_ERROR(
2917 checkDataflowWithNoopAnalysis(Code),
2918 llvm::FailedWithMessage("Cannot analyze templated declarations"));
2921 TEST(TransferTest, VarDeclInitAssignConditionalOperator) {
2922 std::string Code = R"(
2923 struct A {};
2925 void target(A Foo, A Bar, bool Cond) {
2926 A Baz = Cond ? Foo : Bar;
2927 /*[[p]]*/
2930 runDataflow(
2931 Code,
2932 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2933 ASTContext &ASTCtx) {
2934 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2935 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2937 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2938 ASSERT_THAT(FooDecl, NotNull());
2940 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2941 ASSERT_THAT(BarDecl, NotNull());
2943 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2944 ASSERT_THAT(BazDecl, NotNull());
2946 const auto *FooVal = cast<RecordValue>(Env.getValue(*FooDecl));
2947 const auto *BarVal = cast<RecordValue>(Env.getValue(*BarDecl));
2949 const auto *BazVal = dyn_cast<RecordValue>(Env.getValue(*BazDecl));
2950 ASSERT_THAT(BazVal, NotNull());
2952 EXPECT_NE(BazVal, FooVal);
2953 EXPECT_NE(BazVal, BarVal);
2957 TEST(TransferTest, VarDeclInDoWhile) {
2958 std::string Code = R"(
2959 void target(int *Foo) {
2960 do {
2961 int Bar = *Foo;
2962 // [[in_loop]]
2963 } while (false);
2964 (void)0;
2965 // [[after_loop]]
2968 runDataflow(
2969 Code,
2970 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2971 ASTContext &ASTCtx) {
2972 const Environment &EnvInLoop =
2973 getEnvironmentAtAnnotation(Results, "in_loop");
2974 const Environment &EnvAfterLoop =
2975 getEnvironmentAtAnnotation(Results, "after_loop");
2977 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2978 ASSERT_THAT(FooDecl, NotNull());
2980 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2981 ASSERT_THAT(BarDecl, NotNull());
2983 const auto *FooVal =
2984 cast<PointerValue>(EnvAfterLoop.getValue(*FooDecl));
2985 const auto *FooPointeeVal =
2986 cast<IntegerValue>(EnvAfterLoop.getValue(FooVal->getPointeeLoc()));
2988 const auto *BarVal = cast<IntegerValue>(EnvInLoop.getValue(*BarDecl));
2989 EXPECT_EQ(BarVal, FooPointeeVal);
2991 ASSERT_THAT(EnvAfterLoop.getValue(*BarDecl), IsNull());
2995 TEST(TransferTest, UnreachableAfterWhileTrue) {
2996 std::string Code = R"(
2997 void target() {
2998 while (true) {}
2999 (void)0;
3000 /*[[p]]*/
3003 runDataflow(
3004 Code,
3005 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3006 ASTContext &ASTCtx) {
3007 // The node after the while-true is pruned because it is trivially
3008 // known to be unreachable.
3009 ASSERT_TRUE(Results.empty());
3013 TEST(TransferTest, AggregateInitialization) {
3014 std::string BracesCode = R"(
3015 struct A {
3016 int Foo;
3019 struct B {
3020 int Bar;
3021 A Baz;
3022 int Qux;
3025 void target(int BarArg, int FooArg, int QuxArg) {
3026 B Quux{BarArg, {FooArg}, QuxArg};
3027 B OtherB;
3028 /*[[p]]*/
3031 std::string BraceElisionCode = R"(
3032 struct A {
3033 int Foo;
3036 struct B {
3037 int Bar;
3038 A Baz;
3039 int Qux;
3042 void target(int BarArg, int FooArg, int QuxArg) {
3043 B Quux = {BarArg, FooArg, QuxArg};
3044 B OtherB;
3045 /*[[p]]*/
3048 for (const std::string &Code : {BracesCode, BraceElisionCode}) {
3049 runDataflow(
3050 Code,
3051 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3052 ASTContext &ASTCtx) {
3053 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3054 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3056 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3057 ASSERT_THAT(FooDecl, NotNull());
3059 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3060 ASSERT_THAT(BarDecl, NotNull());
3062 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3063 ASSERT_THAT(BazDecl, NotNull());
3065 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
3066 ASSERT_THAT(QuxDecl, NotNull());
3068 const ValueDecl *FooArgDecl = findValueDecl(ASTCtx, "FooArg");
3069 ASSERT_THAT(FooArgDecl, NotNull());
3071 const ValueDecl *BarArgDecl = findValueDecl(ASTCtx, "BarArg");
3072 ASSERT_THAT(BarArgDecl, NotNull());
3074 const ValueDecl *QuxArgDecl = findValueDecl(ASTCtx, "QuxArg");
3075 ASSERT_THAT(QuxArgDecl, NotNull());
3077 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
3078 ASSERT_THAT(QuuxDecl, NotNull());
3080 const auto *FooArgVal = cast<IntegerValue>(Env.getValue(*FooArgDecl));
3081 const auto *BarArgVal = cast<IntegerValue>(Env.getValue(*BarArgDecl));
3082 const auto *QuxArgVal = cast<IntegerValue>(Env.getValue(*QuxArgDecl));
3084 const auto &QuuxLoc =
3085 *cast<RecordStorageLocation>(Env.getStorageLocation(*QuuxDecl));
3086 const auto &BazLoc =
3087 *cast<RecordStorageLocation>(QuuxLoc.getChild(*BazDecl));
3089 EXPECT_EQ(getFieldValue(&QuuxLoc, *BarDecl, Env), BarArgVal);
3090 EXPECT_EQ(getFieldValue(&BazLoc, *FooDecl, Env), FooArgVal);
3091 EXPECT_EQ(getFieldValue(&QuuxLoc, *QuxDecl, Env), QuxArgVal);
3093 // Check that fields initialized in an initializer list are always
3094 // modeled in other instances of the same type.
3095 const auto &OtherBLoc =
3096 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "OtherB");
3097 EXPECT_THAT(OtherBLoc.getChild(*BarDecl), NotNull());
3098 EXPECT_THAT(OtherBLoc.getChild(*BazDecl), NotNull());
3099 EXPECT_THAT(OtherBLoc.getChild(*QuxDecl), NotNull());
3104 TEST(TransferTest, AggregateInitializationReferenceField) {
3105 std::string Code = R"(
3106 struct S {
3107 int &RefField;
3110 void target(int i) {
3111 S s = { i };
3112 /*[[p]]*/
3115 runDataflow(
3116 Code,
3117 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3118 ASTContext &ASTCtx) {
3119 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3121 const ValueDecl *RefFieldDecl = findValueDecl(ASTCtx, "RefField");
3123 auto &ILoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "i");
3124 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s");
3126 EXPECT_EQ(SLoc.getChild(*RefFieldDecl), &ILoc);
3130 TEST(TransferTest, AggregateInitialization_NotExplicitlyInitializedField) {
3131 std::string Code = R"(
3132 struct S {
3133 int i1;
3134 int i2;
3137 void target(int i) {
3138 S s = { i };
3139 /*[[p]]*/
3142 runDataflow(
3143 Code,
3144 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3145 ASTContext &ASTCtx) {
3146 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3148 const ValueDecl *I1FieldDecl = findValueDecl(ASTCtx, "i1");
3149 const ValueDecl *I2FieldDecl = findValueDecl(ASTCtx, "i2");
3151 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s");
3153 auto &IValue = getValueForDecl<IntegerValue>(ASTCtx, Env, "i");
3154 auto &I1Value =
3155 *cast<IntegerValue>(getFieldValue(&SLoc, *I1FieldDecl, Env));
3156 EXPECT_EQ(&I1Value, &IValue);
3157 auto &I2Value =
3158 *cast<IntegerValue>(getFieldValue(&SLoc, *I2FieldDecl, Env));
3159 EXPECT_NE(&I2Value, &IValue);
3163 TEST(TransferTest, AssignToUnionMember) {
3164 std::string Code = R"(
3165 union A {
3166 int Foo;
3169 void target(int Bar) {
3170 A Baz;
3171 Baz.Foo = Bar;
3172 // [[p]]
3175 runDataflow(
3176 Code,
3177 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3178 ASTContext &ASTCtx) {
3179 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3180 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3182 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3183 ASSERT_THAT(BazDecl, NotNull());
3184 ASSERT_TRUE(BazDecl->getType()->isUnionType());
3186 auto BazFields = BazDecl->getType()->getAsRecordDecl()->fields();
3187 FieldDecl *FooDecl = nullptr;
3188 for (FieldDecl *Field : BazFields) {
3189 if (Field->getNameAsString() == "Foo") {
3190 FooDecl = Field;
3191 } else {
3192 FAIL() << "Unexpected field: " << Field->getNameAsString();
3195 ASSERT_THAT(FooDecl, NotNull());
3197 const auto *BazLoc = dyn_cast_or_null<RecordStorageLocation>(
3198 Env.getStorageLocation(*BazDecl));
3199 ASSERT_THAT(BazLoc, NotNull());
3200 ASSERT_THAT(Env.getValue(*BazLoc), NotNull());
3202 const auto *FooVal =
3203 cast<IntegerValue>(getFieldValue(BazLoc, *FooDecl, Env));
3205 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3206 ASSERT_THAT(BarDecl, NotNull());
3207 const auto *BarLoc = Env.getStorageLocation(*BarDecl);
3208 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
3210 EXPECT_EQ(Env.getValue(*BarLoc), FooVal);
3214 TEST(TransferTest, AssignFromBoolLiteral) {
3215 std::string Code = R"(
3216 void target() {
3217 bool Foo = true;
3218 bool Bar = false;
3219 // [[p]]
3222 runDataflow(
3223 Code,
3224 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3225 ASTContext &ASTCtx) {
3226 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3227 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3229 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3230 ASSERT_THAT(FooDecl, NotNull());
3232 const auto *FooVal =
3233 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));
3234 ASSERT_THAT(FooVal, NotNull());
3236 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3237 ASSERT_THAT(BarDecl, NotNull());
3239 const auto *BarVal =
3240 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl));
3241 ASSERT_THAT(BarVal, NotNull());
3243 EXPECT_EQ(FooVal, &Env.getBoolLiteralValue(true));
3244 EXPECT_EQ(BarVal, &Env.getBoolLiteralValue(false));
3248 TEST(TransferTest, AssignFromCompositeBoolExpression) {
3250 std::string Code = R"(
3251 void target(bool Foo, bool Bar, bool Qux) {
3252 bool Baz = (Foo) && (Bar || Qux);
3253 // [[p]]
3256 runDataflow(
3257 Code,
3258 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3259 ASTContext &ASTCtx) {
3260 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3261 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3263 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3264 ASSERT_THAT(FooDecl, NotNull());
3266 const auto *FooVal =
3267 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));
3268 ASSERT_THAT(FooVal, NotNull());
3270 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3271 ASSERT_THAT(BarDecl, NotNull());
3273 const auto *BarVal =
3274 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl));
3275 ASSERT_THAT(BarVal, NotNull());
3277 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
3278 ASSERT_THAT(QuxDecl, NotNull());
3280 const auto *QuxVal =
3281 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl));
3282 ASSERT_THAT(QuxVal, NotNull());
3284 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3285 ASSERT_THAT(BazDecl, NotNull());
3287 const auto *BazVal =
3288 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl));
3289 ASSERT_THAT(BazVal, NotNull());
3290 auto &A = Env.arena();
3291 EXPECT_EQ(&BazVal->formula(),
3292 &A.makeAnd(FooVal->formula(),
3293 A.makeOr(BarVal->formula(), QuxVal->formula())));
3298 std::string Code = R"(
3299 void target(bool Foo, bool Bar, bool Qux) {
3300 bool Baz = (Foo && Qux) || (Bar);
3301 // [[p]]
3304 runDataflow(
3305 Code,
3306 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3307 ASTContext &ASTCtx) {
3308 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3309 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3311 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3312 ASSERT_THAT(FooDecl, NotNull());
3314 const auto *FooVal =
3315 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));
3316 ASSERT_THAT(FooVal, NotNull());
3318 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3319 ASSERT_THAT(BarDecl, NotNull());
3321 const auto *BarVal =
3322 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl));
3323 ASSERT_THAT(BarVal, NotNull());
3325 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
3326 ASSERT_THAT(QuxDecl, NotNull());
3328 const auto *QuxVal =
3329 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl));
3330 ASSERT_THAT(QuxVal, NotNull());
3332 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3333 ASSERT_THAT(BazDecl, NotNull());
3335 const auto *BazVal =
3336 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl));
3337 ASSERT_THAT(BazVal, NotNull());
3338 auto &A = Env.arena();
3339 EXPECT_EQ(&BazVal->formula(),
3340 &A.makeOr(A.makeAnd(FooVal->formula(), QuxVal->formula()),
3341 BarVal->formula()));
3346 std::string Code = R"(
3347 void target(bool A, bool B, bool C, bool D) {
3348 bool Foo = ((A && B) && C) && D;
3349 // [[p]]
3352 runDataflow(
3353 Code,
3354 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3355 ASTContext &ASTCtx) {
3356 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3357 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3359 const ValueDecl *ADecl = findValueDecl(ASTCtx, "A");
3360 ASSERT_THAT(ADecl, NotNull());
3362 const auto *AVal = dyn_cast_or_null<BoolValue>(Env.getValue(*ADecl));
3363 ASSERT_THAT(AVal, NotNull());
3365 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B");
3366 ASSERT_THAT(BDecl, NotNull());
3368 const auto *BVal = dyn_cast_or_null<BoolValue>(Env.getValue(*BDecl));
3369 ASSERT_THAT(BVal, NotNull());
3371 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C");
3372 ASSERT_THAT(CDecl, NotNull());
3374 const auto *CVal = dyn_cast_or_null<BoolValue>(Env.getValue(*CDecl));
3375 ASSERT_THAT(CVal, NotNull());
3377 const ValueDecl *DDecl = findValueDecl(ASTCtx, "D");
3378 ASSERT_THAT(DDecl, NotNull());
3380 const auto *DVal = dyn_cast_or_null<BoolValue>(Env.getValue(*DDecl));
3381 ASSERT_THAT(DVal, NotNull());
3383 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3384 ASSERT_THAT(FooDecl, NotNull());
3386 const auto *FooVal =
3387 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));
3388 ASSERT_THAT(FooVal, NotNull());
3389 auto &A = Env.arena();
3390 EXPECT_EQ(
3391 &FooVal->formula(),
3392 &A.makeAnd(A.makeAnd(A.makeAnd(AVal->formula(), BVal->formula()),
3393 CVal->formula()),
3394 DVal->formula()));
3399 TEST(TransferTest, AssignFromBoolNegation) {
3400 std::string Code = R"(
3401 void target() {
3402 bool Foo = true;
3403 bool Bar = !(Foo);
3404 // [[p]]
3407 runDataflow(
3408 Code,
3409 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3410 ASTContext &ASTCtx) {
3411 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3412 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3414 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3415 ASSERT_THAT(FooDecl, NotNull());
3417 const auto *FooVal =
3418 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));
3419 ASSERT_THAT(FooVal, NotNull());
3421 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3422 ASSERT_THAT(BarDecl, NotNull());
3424 const auto *BarVal =
3425 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl));
3426 ASSERT_THAT(BarVal, NotNull());
3427 auto &A = Env.arena();
3428 EXPECT_EQ(&BarVal->formula(), &A.makeNot(FooVal->formula()));
3432 TEST(TransferTest, BuiltinExpect) {
3433 std::string Code = R"(
3434 void target(long Foo) {
3435 long Bar = __builtin_expect(Foo, true);
3436 /*[[p]]*/
3439 runDataflow(
3440 Code,
3441 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3442 ASTContext &ASTCtx) {
3443 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3444 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3446 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3447 ASSERT_THAT(FooDecl, NotNull());
3449 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3450 ASSERT_THAT(BarDecl, NotNull());
3452 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
3456 // `__builtin_expect` takes and returns a `long` argument, so other types
3457 // involve casts. This verifies that we identify the input and output in that
3458 // case.
3459 TEST(TransferTest, BuiltinExpectBoolArg) {
3460 std::string Code = R"(
3461 void target(bool Foo) {
3462 bool Bar = __builtin_expect(Foo, true);
3463 /*[[p]]*/
3466 runDataflow(
3467 Code,
3468 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3469 ASTContext &ASTCtx) {
3470 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3471 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3473 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3474 ASSERT_THAT(FooDecl, NotNull());
3476 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3477 ASSERT_THAT(BarDecl, NotNull());
3479 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
3483 TEST(TransferTest, BuiltinUnreachable) {
3484 std::string Code = R"(
3485 void target(bool Foo) {
3486 bool Bar = false;
3487 if (Foo)
3488 Bar = Foo;
3489 else
3490 __builtin_unreachable();
3491 (void)0;
3492 /*[[p]]*/
3495 runDataflow(
3496 Code,
3497 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3498 ASTContext &ASTCtx) {
3499 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3500 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3502 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3503 ASSERT_THAT(FooDecl, NotNull());
3505 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3506 ASSERT_THAT(BarDecl, NotNull());
3508 // `__builtin_unreachable` promises that the code is
3509 // unreachable, so the compiler treats the "then" branch as the
3510 // only possible predecessor of this statement.
3511 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
3515 TEST(TransferTest, BuiltinTrap) {
3516 std::string Code = R"(
3517 void target(bool Foo) {
3518 bool Bar = false;
3519 if (Foo)
3520 Bar = Foo;
3521 else
3522 __builtin_trap();
3523 (void)0;
3524 /*[[p]]*/
3527 runDataflow(
3528 Code,
3529 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3530 ASTContext &ASTCtx) {
3531 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3532 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3534 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3535 ASSERT_THAT(FooDecl, NotNull());
3537 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3538 ASSERT_THAT(BarDecl, NotNull());
3540 // `__builtin_trap` ensures program termination, so only the
3541 // "then" branch is a predecessor of this statement.
3542 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
3546 TEST(TransferTest, BuiltinDebugTrap) {
3547 std::string Code = R"(
3548 void target(bool Foo) {
3549 bool Bar = false;
3550 if (Foo)
3551 Bar = Foo;
3552 else
3553 __builtin_debugtrap();
3554 (void)0;
3555 /*[[p]]*/
3558 runDataflow(
3559 Code,
3560 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3561 ASTContext &ASTCtx) {
3562 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3563 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3565 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3566 ASSERT_THAT(FooDecl, NotNull());
3568 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3569 ASSERT_THAT(BarDecl, NotNull());
3571 // `__builtin_debugtrap` doesn't ensure program termination.
3572 EXPECT_NE(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
3576 TEST(TransferTest, StaticIntSingleVarDecl) {
3577 std::string Code = R"(
3578 void target() {
3579 static int Foo;
3580 // [[p]]
3583 runDataflow(
3584 Code,
3585 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3586 ASTContext &ASTCtx) {
3587 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3588 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3590 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3591 ASSERT_THAT(FooDecl, NotNull());
3593 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
3594 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
3596 const Value *FooVal = Env.getValue(*FooLoc);
3597 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
3601 TEST(TransferTest, StaticIntGroupVarDecl) {
3602 std::string Code = R"(
3603 void target() {
3604 static int Foo, Bar;
3605 (void)0;
3606 // [[p]]
3609 runDataflow(
3610 Code,
3611 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3612 ASTContext &ASTCtx) {
3613 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3614 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3616 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3617 ASSERT_THAT(FooDecl, NotNull());
3619 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3620 ASSERT_THAT(BarDecl, NotNull());
3622 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
3623 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
3625 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
3626 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
3628 const Value *FooVal = Env.getValue(*FooLoc);
3629 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
3631 const Value *BarVal = Env.getValue(*BarLoc);
3632 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
3634 EXPECT_NE(FooVal, BarVal);
3638 TEST(TransferTest, GlobalIntVarDecl) {
3639 std::string Code = R"(
3640 static int Foo;
3642 void target() {
3643 int Bar = Foo;
3644 int Baz = Foo;
3645 // [[p]]
3648 runDataflow(
3649 Code,
3650 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3651 ASTContext &ASTCtx) {
3652 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3653 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3655 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3656 ASSERT_THAT(BarDecl, NotNull());
3658 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3659 ASSERT_THAT(BazDecl, NotNull());
3661 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));
3662 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl));
3663 EXPECT_EQ(BarVal, BazVal);
3667 TEST(TransferTest, StaticMemberIntVarDecl) {
3668 std::string Code = R"(
3669 struct A {
3670 static int Foo;
3673 void target(A a) {
3674 int Bar = a.Foo;
3675 int Baz = a.Foo;
3676 // [[p]]
3679 runDataflow(
3680 Code,
3681 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3682 ASTContext &ASTCtx) {
3683 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3684 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3686 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3687 ASSERT_THAT(BarDecl, NotNull());
3689 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3690 ASSERT_THAT(BazDecl, NotNull());
3692 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));
3693 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl));
3694 EXPECT_EQ(BarVal, BazVal);
3698 TEST(TransferTest, StaticMemberRefVarDecl) {
3699 std::string Code = R"(
3700 struct A {
3701 static int &Foo;
3704 void target(A a) {
3705 int Bar = a.Foo;
3706 int Baz = a.Foo;
3707 // [[p]]
3710 runDataflow(
3711 Code,
3712 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3713 ASTContext &ASTCtx) {
3714 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3715 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3717 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3718 ASSERT_THAT(BarDecl, NotNull());
3720 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3721 ASSERT_THAT(BazDecl, NotNull());
3723 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));
3724 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl));
3725 EXPECT_EQ(BarVal, BazVal);
3729 TEST(TransferTest, AssignMemberBeforeCopy) {
3730 std::string Code = R"(
3731 struct A {
3732 int Foo;
3735 void target() {
3736 A A1;
3737 A A2;
3738 int Bar;
3739 A1.Foo = Bar;
3740 A2 = A1;
3741 // [[p]]
3744 runDataflow(
3745 Code,
3746 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3747 ASTContext &ASTCtx) {
3748 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3749 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3751 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3752 ASSERT_THAT(FooDecl, NotNull());
3754 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3755 ASSERT_THAT(BarDecl, NotNull());
3757 const ValueDecl *A1Decl = findValueDecl(ASTCtx, "A1");
3758 ASSERT_THAT(A1Decl, NotNull());
3760 const ValueDecl *A2Decl = findValueDecl(ASTCtx, "A2");
3761 ASSERT_THAT(A2Decl, NotNull());
3763 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));
3765 const auto &A2Loc =
3766 *cast<RecordStorageLocation>(Env.getStorageLocation(*A2Decl));
3767 EXPECT_EQ(getFieldValue(&A2Loc, *FooDecl, Env), BarVal);
3771 TEST(TransferTest, BooleanEquality) {
3772 std::string Code = R"(
3773 void target(bool Bar) {
3774 bool Foo = true;
3775 if (Bar == Foo) {
3776 (void)0;
3777 /*[[p-then]]*/
3778 } else {
3779 (void)0;
3780 /*[[p-else]]*/
3784 runDataflow(
3785 Code,
3786 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3787 ASTContext &ASTCtx) {
3788 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else"));
3789 const Environment &EnvThen =
3790 getEnvironmentAtAnnotation(Results, "p-then");
3791 const Environment &EnvElse =
3792 getEnvironmentAtAnnotation(Results, "p-else");
3794 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3795 ASSERT_THAT(BarDecl, NotNull());
3797 auto &BarValThen = getFormula(*BarDecl, EnvThen);
3798 EXPECT_TRUE(EnvThen.proves(BarValThen));
3800 auto &BarValElse = getFormula(*BarDecl, EnvElse);
3801 EXPECT_TRUE(EnvElse.proves(EnvElse.arena().makeNot(BarValElse)));
3805 TEST(TransferTest, BooleanInequality) {
3806 std::string Code = R"(
3807 void target(bool Bar) {
3808 bool Foo = true;
3809 if (Bar != Foo) {
3810 (void)0;
3811 /*[[p-then]]*/
3812 } else {
3813 (void)0;
3814 /*[[p-else]]*/
3818 runDataflow(
3819 Code,
3820 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3821 ASTContext &ASTCtx) {
3822 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else"));
3823 const Environment &EnvThen =
3824 getEnvironmentAtAnnotation(Results, "p-then");
3825 const Environment &EnvElse =
3826 getEnvironmentAtAnnotation(Results, "p-else");
3828 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3829 ASSERT_THAT(BarDecl, NotNull());
3831 auto &BarValThen = getFormula(*BarDecl, EnvThen);
3832 EXPECT_TRUE(EnvThen.proves(EnvThen.arena().makeNot(BarValThen)));
3834 auto &BarValElse = getFormula(*BarDecl, EnvElse);
3835 EXPECT_TRUE(EnvElse.proves(BarValElse));
3839 TEST(TransferTest, IntegerLiteralEquality) {
3840 std::string Code = R"(
3841 void target() {
3842 bool equal = (42 == 42);
3843 // [[p]]
3846 runDataflow(
3847 Code,
3848 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3849 ASTContext &ASTCtx) {
3850 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3852 auto &Equal =
3853 getValueForDecl<BoolValue>(ASTCtx, Env, "equal").formula();
3854 EXPECT_TRUE(Env.proves(Equal));
3858 TEST(TransferTest, CorrelatedBranches) {
3859 std::string Code = R"(
3860 void target(bool B, bool C) {
3861 if (B) {
3862 return;
3864 (void)0;
3865 /*[[p0]]*/
3866 if (C) {
3867 B = true;
3868 /*[[p1]]*/
3870 if (B) {
3871 (void)0;
3872 /*[[p2]]*/
3876 runDataflow(
3877 Code,
3878 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3879 ASTContext &ASTCtx) {
3880 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p0", "p1", "p2"));
3882 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C");
3883 ASSERT_THAT(CDecl, NotNull());
3886 const Environment &Env = getEnvironmentAtAnnotation(Results, "p0");
3887 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B");
3888 ASSERT_THAT(BDecl, NotNull());
3889 auto &BVal = getFormula(*BDecl, Env);
3891 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BVal)));
3895 const Environment &Env = getEnvironmentAtAnnotation(Results, "p1");
3896 auto &CVal = getFormula(*CDecl, Env);
3897 EXPECT_TRUE(Env.proves(CVal));
3901 const Environment &Env = getEnvironmentAtAnnotation(Results, "p2");
3902 auto &CVal = getFormula(*CDecl, Env);
3903 EXPECT_TRUE(Env.proves(CVal));
3908 TEST(TransferTest, LoopWithAssignmentConverges) {
3909 std::string Code = R"(
3910 bool foo();
3912 void target() {
3913 do {
3914 bool Bar = foo();
3915 if (Bar) break;
3916 (void)Bar;
3917 /*[[p]]*/
3918 } while (true);
3921 // The key property that we are verifying is implicit in `runDataflow` --
3922 // namely, that the analysis succeeds, rather than hitting the maximum number
3923 // of iterations.
3924 runDataflow(
3925 Code,
3926 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3927 ASTContext &ASTCtx) {
3928 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3929 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3931 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3932 ASSERT_THAT(BarDecl, NotNull());
3934 auto &BarVal = getFormula(*BarDecl, Env);
3935 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal)));
3939 TEST(TransferTest, LoopWithStagedAssignments) {
3940 std::string Code = R"(
3941 bool foo();
3943 void target() {
3944 bool Bar = false;
3945 bool Err = false;
3946 while (foo()) {
3947 if (Bar)
3948 Err = true;
3949 Bar = true;
3950 /*[[p]]*/
3954 runDataflow(
3955 Code,
3956 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3957 ASTContext &ASTCtx) {
3958 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3959 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3961 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3962 ASSERT_THAT(BarDecl, NotNull());
3963 const ValueDecl *ErrDecl = findValueDecl(ASTCtx, "Err");
3964 ASSERT_THAT(ErrDecl, NotNull());
3966 auto &BarVal = getFormula(*BarDecl, Env);
3967 auto &ErrVal = getFormula(*ErrDecl, Env);
3968 EXPECT_TRUE(Env.proves(BarVal));
3969 // An unsound analysis, for example only evaluating the loop once, can
3970 // conclude that `Err` is false. So, we test that this conclusion is not
3971 // reached.
3972 EXPECT_FALSE(Env.proves(Env.arena().makeNot(ErrVal)));
3976 TEST(TransferTest, LoopWithReferenceAssignmentConverges) {
3977 std::string Code = R"(
3978 bool &foo();
3980 void target() {
3981 do {
3982 bool& Bar = foo();
3983 if (Bar) break;
3984 (void)Bar;
3985 /*[[p]]*/
3986 } while (true);
3989 // The key property that we are verifying is that the analysis succeeds,
3990 // rather than hitting the maximum number of iterations.
3991 runDataflow(
3992 Code,
3993 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3994 ASTContext &ASTCtx) {
3995 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3996 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3998 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3999 ASSERT_THAT(BarDecl, NotNull());
4001 auto &BarVal = getFormula(*BarDecl, Env);
4002 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal)));
4006 TEST(TransferTest, LoopWithStructReferenceAssignmentConverges) {
4007 std::string Code = R"(
4008 struct Lookup {
4009 int x;
4012 void target(Lookup val, bool b) {
4013 const Lookup* l = nullptr;
4014 while (b) {
4015 l = &val;
4016 /*[[p-inner]]*/
4018 (void)0;
4019 /*[[p-outer]]*/
4022 // The key property that we are verifying is implicit in `runDataflow` --
4023 // namely, that the analysis succeeds, rather than hitting the maximum number
4024 // of iterations.
4025 runDataflow(
4026 Code,
4027 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4028 ASTContext &ASTCtx) {
4029 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-inner", "p-outer"));
4030 const Environment &InnerEnv =
4031 getEnvironmentAtAnnotation(Results, "p-inner");
4032 const Environment &OuterEnv =
4033 getEnvironmentAtAnnotation(Results, "p-outer");
4035 const ValueDecl *ValDecl = findValueDecl(ASTCtx, "val");
4036 ASSERT_THAT(ValDecl, NotNull());
4038 const ValueDecl *LDecl = findValueDecl(ASTCtx, "l");
4039 ASSERT_THAT(LDecl, NotNull());
4041 // Inner.
4042 auto *LVal = dyn_cast<PointerValue>(InnerEnv.getValue(*LDecl));
4043 ASSERT_THAT(LVal, NotNull());
4045 EXPECT_EQ(&LVal->getPointeeLoc(),
4046 InnerEnv.getStorageLocation(*ValDecl));
4048 // Outer.
4049 LVal = dyn_cast<PointerValue>(OuterEnv.getValue(*LDecl));
4050 ASSERT_THAT(LVal, NotNull());
4052 // The loop body may not have been executed, so we should not conclude
4053 // that `l` points to `val`.
4054 EXPECT_NE(&LVal->getPointeeLoc(),
4055 OuterEnv.getStorageLocation(*ValDecl));
4059 TEST(TransferTest, LoopDereferencingChangingPointerConverges) {
4060 std::string Code = R"cc(
4061 bool some_condition();
4063 void target(int i1, int i2) {
4064 int *p = &i1;
4065 while (true) {
4066 (void)*p;
4067 if (some_condition())
4068 p = &i1;
4069 else
4070 p = &i2;
4073 )cc";
4074 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded());
4077 TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) {
4078 std::string Code = R"cc(
4079 struct Lookup {
4080 int x;
4083 bool some_condition();
4085 void target(Lookup l1, Lookup l2) {
4086 Lookup *l = &l1;
4087 while (true) {
4088 (void)l->x;
4089 if (some_condition())
4090 l = &l1;
4091 else
4092 l = &l2;
4095 )cc";
4096 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded());
4099 TEST(TransferTest, LoopWithShortCircuitedConditionConverges) {
4100 std::string Code = R"cc(
4101 bool foo();
4103 void target() {
4104 bool c = false;
4105 while (foo() || foo()) {
4106 c = true;
4109 )cc";
4110 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded());
4113 TEST(TransferTest, DoesNotCrashOnUnionThisExpr) {
4114 std::string Code = R"(
4115 union Union {
4116 int A;
4117 float B;
4120 void foo() {
4121 Union A;
4122 Union B;
4123 A = B;
4126 // This is a crash regression test when calling the transfer function on a
4127 // `CXXThisExpr` that refers to a union.
4128 runDataflow(
4129 Code,
4130 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
4131 ASTContext &) {},
4132 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator=");
4135 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToRefs) {
4136 std::string Code = R"(
4137 struct A {
4138 int Foo;
4139 int Bar;
4142 void target() {
4143 int Qux;
4144 A Baz;
4145 Baz.Foo = Qux;
4146 auto &FooRef = Baz.Foo;
4147 auto &BarRef = Baz.Bar;
4148 auto &[BoundFooRef, BoundBarRef] = Baz;
4149 // [[p]]
4152 runDataflow(
4153 Code,
4154 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4155 ASTContext &ASTCtx) {
4156 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4157 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4159 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef");
4160 ASSERT_THAT(FooRefDecl, NotNull());
4162 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef");
4163 ASSERT_THAT(BarRefDecl, NotNull());
4165 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
4166 ASSERT_THAT(QuxDecl, NotNull());
4168 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef");
4169 ASSERT_THAT(BoundFooRefDecl, NotNull());
4171 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef");
4172 ASSERT_THAT(BoundBarRefDecl, NotNull());
4174 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl);
4175 ASSERT_THAT(FooRefLoc, NotNull());
4177 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl);
4178 ASSERT_THAT(BarRefLoc, NotNull());
4180 const Value *QuxVal = Env.getValue(*QuxDecl);
4181 ASSERT_THAT(QuxVal, NotNull());
4183 const StorageLocation *BoundFooRefLoc =
4184 Env.getStorageLocation(*BoundFooRefDecl);
4185 EXPECT_EQ(BoundFooRefLoc, FooRefLoc);
4187 const StorageLocation *BoundBarRefLoc =
4188 Env.getStorageLocation(*BoundBarRefDecl);
4189 EXPECT_EQ(BoundBarRefLoc, BarRefLoc);
4191 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal);
4195 TEST(TransferTest, StructuredBindingAssignFromStructRefMembersToRefs) {
4196 std::string Code = R"(
4197 struct A {
4198 int &Foo;
4199 int &Bar;
4202 void target(A Baz) {
4203 int Qux;
4204 Baz.Foo = Qux;
4205 auto &FooRef = Baz.Foo;
4206 auto &BarRef = Baz.Bar;
4207 auto &[BoundFooRef, BoundBarRef] = Baz;
4208 // [[p]]
4211 runDataflow(
4212 Code,
4213 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4214 ASTContext &ASTCtx) {
4215 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4216 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4218 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef");
4219 ASSERT_THAT(FooRefDecl, NotNull());
4221 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef");
4222 ASSERT_THAT(BarRefDecl, NotNull());
4224 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
4225 ASSERT_THAT(QuxDecl, NotNull());
4227 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef");
4228 ASSERT_THAT(BoundFooRefDecl, NotNull());
4230 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef");
4231 ASSERT_THAT(BoundBarRefDecl, NotNull());
4233 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl);
4234 ASSERT_THAT(FooRefLoc, NotNull());
4236 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl);
4237 ASSERT_THAT(BarRefLoc, NotNull());
4239 const Value *QuxVal = Env.getValue(*QuxDecl);
4240 ASSERT_THAT(QuxVal, NotNull());
4242 const StorageLocation *BoundFooRefLoc =
4243 Env.getStorageLocation(*BoundFooRefDecl);
4244 EXPECT_EQ(BoundFooRefLoc, FooRefLoc);
4246 const StorageLocation *BoundBarRefLoc =
4247 Env.getStorageLocation(*BoundBarRefDecl);
4248 EXPECT_EQ(BoundBarRefLoc, BarRefLoc);
4250 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal);
4254 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToInts) {
4255 std::string Code = R"(
4256 struct A {
4257 int Foo;
4258 int Bar;
4261 void target() {
4262 int Qux;
4263 A Baz;
4264 Baz.Foo = Qux;
4265 auto &FooRef = Baz.Foo;
4266 auto &BarRef = Baz.Bar;
4267 auto [BoundFoo, BoundBar] = Baz;
4268 // [[p]]
4271 runDataflow(
4272 Code,
4273 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4274 ASTContext &ASTCtx) {
4275 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4276 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4278 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef");
4279 ASSERT_THAT(FooRefDecl, NotNull());
4281 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef");
4282 ASSERT_THAT(BarRefDecl, NotNull());
4284 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo");
4285 ASSERT_THAT(BoundFooDecl, NotNull());
4287 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");
4288 ASSERT_THAT(BoundBarDecl, NotNull());
4290 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
4291 ASSERT_THAT(QuxDecl, NotNull());
4293 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl);
4294 ASSERT_THAT(FooRefLoc, NotNull());
4296 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl);
4297 ASSERT_THAT(BarRefLoc, NotNull());
4299 const Value *QuxVal = Env.getValue(*QuxDecl);
4300 ASSERT_THAT(QuxVal, NotNull());
4302 const StorageLocation *BoundFooLoc =
4303 Env.getStorageLocation(*BoundFooDecl);
4304 EXPECT_NE(BoundFooLoc, FooRefLoc);
4306 const StorageLocation *BoundBarLoc =
4307 Env.getStorageLocation(*BoundBarDecl);
4308 EXPECT_NE(BoundBarLoc, BarRefLoc);
4310 EXPECT_EQ(Env.getValue(*BoundFooDecl), QuxVal);
4314 TEST(TransferTest, StructuredBindingAssignFromTupleLikeType) {
4315 std::string Code = R"(
4316 namespace std {
4317 using size_t = int;
4318 template <class> struct tuple_size;
4319 template <std::size_t, class> struct tuple_element;
4320 template <class...> class tuple;
4322 namespace {
4323 template <class T, T v>
4324 struct size_helper { static const T value = v; };
4325 } // namespace
4327 template <class... T>
4328 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {};
4330 template <std::size_t I, class... T>
4331 struct tuple_element<I, tuple<T...>> {
4332 using type = __type_pack_element<I, T...>;
4335 template <class...> class tuple {};
4337 template <std::size_t I, class... T>
4338 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
4339 } // namespace std
4341 std::tuple<bool, int> makeTuple();
4343 void target(bool B) {
4344 auto [BoundFoo, BoundBar] = makeTuple();
4345 bool Baz;
4346 // Include if-then-else to test interaction of `BindingDecl` with join.
4347 if (B) {
4348 Baz = BoundFoo;
4349 (void)BoundBar;
4350 // [[p1]]
4351 } else {
4352 Baz = BoundFoo;
4354 (void)0;
4355 // [[p2]]
4358 runDataflow(
4359 Code,
4360 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4361 ASTContext &ASTCtx) {
4362 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
4363 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
4365 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo");
4366 ASSERT_THAT(BoundFooDecl, NotNull());
4368 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");
4369 ASSERT_THAT(BoundBarDecl, NotNull());
4371 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
4372 ASSERT_THAT(BazDecl, NotNull());
4374 // BindingDecls always map to references -- either lvalue or rvalue, so
4375 // we still need to skip here.
4376 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl);
4377 ASSERT_THAT(BoundFooValue, NotNull());
4378 EXPECT_TRUE(isa<BoolValue>(BoundFooValue));
4380 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl);
4381 ASSERT_THAT(BoundBarValue, NotNull());
4382 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue));
4384 // Test that a `DeclRefExpr` to a `BindingDecl` works as expected.
4385 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue);
4387 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
4389 // Test that `BoundFooDecl` retains the value we expect, after the join.
4390 BoundFooValue = Env2.getValue(*BoundFooDecl);
4391 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue);
4395 TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) {
4396 std::string Code = R"(
4397 namespace std {
4398 using size_t = int;
4399 template <class> struct tuple_size;
4400 template <std::size_t, class> struct tuple_element;
4401 template <class...> class tuple;
4403 namespace {
4404 template <class T, T v>
4405 struct size_helper { static const T value = v; };
4406 } // namespace
4408 template <class... T>
4409 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {};
4411 template <std::size_t I, class... T>
4412 struct tuple_element<I, tuple<T...>> {
4413 using type = __type_pack_element<I, T...>;
4416 template <class...> class tuple {};
4418 template <std::size_t I, class... T>
4419 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
4420 } // namespace std
4422 std::tuple<bool, int> &getTuple();
4424 void target(bool B) {
4425 auto &[BoundFoo, BoundBar] = getTuple();
4426 bool Baz;
4427 // Include if-then-else to test interaction of `BindingDecl` with join.
4428 if (B) {
4429 Baz = BoundFoo;
4430 (void)BoundBar;
4431 // [[p1]]
4432 } else {
4433 Baz = BoundFoo;
4435 (void)0;
4436 // [[p2]]
4439 runDataflow(
4440 Code,
4441 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4442 ASTContext &ASTCtx) {
4443 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
4444 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
4446 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo");
4447 ASSERT_THAT(BoundFooDecl, NotNull());
4449 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");
4450 ASSERT_THAT(BoundBarDecl, NotNull());
4452 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
4453 ASSERT_THAT(BazDecl, NotNull());
4455 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl);
4456 ASSERT_THAT(BoundFooValue, NotNull());
4457 EXPECT_TRUE(isa<BoolValue>(BoundFooValue));
4459 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl);
4460 ASSERT_THAT(BoundBarValue, NotNull());
4461 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue));
4463 // Test that a `DeclRefExpr` to a `BindingDecl` (with reference type)
4464 // works as expected. We don't test aliasing properties of the
4465 // reference, because we don't model `std::get` and so have no way to
4466 // equate separate references into the tuple.
4467 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue);
4469 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
4471 // Test that `BoundFooDecl` retains the value we expect, after the join.
4472 BoundFooValue = Env2.getValue(*BoundFooDecl);
4473 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue);
4477 TEST(TransferTest, BinaryOperatorComma) {
4478 std::string Code = R"(
4479 void target(int Foo, int Bar) {
4480 int &Baz = (Foo, Bar);
4481 // [[p]]
4484 runDataflow(
4485 Code,
4486 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4487 ASTContext &ASTCtx) {
4488 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4489 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4491 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
4492 ASSERT_THAT(BarDecl, NotNull());
4494 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
4495 ASSERT_THAT(BazDecl, NotNull());
4497 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
4498 ASSERT_THAT(BarLoc, NotNull());
4500 const StorageLocation *BazLoc = Env.getStorageLocation(*BazDecl);
4501 EXPECT_EQ(BazLoc, BarLoc);
4505 TEST(TransferTest, IfStmtBranchExtendsFlowCondition) {
4506 std::string Code = R"(
4507 void target(bool Foo) {
4508 if (Foo) {
4509 (void)0;
4510 // [[if_then]]
4511 } else {
4512 (void)0;
4513 // [[if_else]]
4517 runDataflow(
4518 Code,
4519 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4520 ASTContext &ASTCtx) {
4521 ASSERT_THAT(Results.keys(), UnorderedElementsAre("if_then", "if_else"));
4522 const Environment &ThenEnv =
4523 getEnvironmentAtAnnotation(Results, "if_then");
4524 const Environment &ElseEnv =
4525 getEnvironmentAtAnnotation(Results, "if_else");
4527 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4528 ASSERT_THAT(FooDecl, NotNull());
4530 auto &ThenFooVal= getFormula(*FooDecl, ThenEnv);
4531 EXPECT_TRUE(ThenEnv.proves(ThenFooVal));
4533 auto &ElseFooVal = getFormula(*FooDecl, ElseEnv);
4534 EXPECT_TRUE(ElseEnv.proves(ElseEnv.arena().makeNot(ElseFooVal)));
4538 TEST(TransferTest, WhileStmtBranchExtendsFlowCondition) {
4539 std::string Code = R"(
4540 void target(bool Foo) {
4541 while (Foo) {
4542 (void)0;
4543 // [[loop_body]]
4545 (void)0;
4546 // [[after_loop]]
4549 runDataflow(
4550 Code,
4551 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4552 ASTContext &ASTCtx) {
4553 ASSERT_THAT(Results.keys(),
4554 UnorderedElementsAre("loop_body", "after_loop"));
4555 const Environment &LoopBodyEnv =
4556 getEnvironmentAtAnnotation(Results, "loop_body");
4557 const Environment &AfterLoopEnv =
4558 getEnvironmentAtAnnotation(Results, "after_loop");
4560 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4561 ASSERT_THAT(FooDecl, NotNull());
4563 auto &LoopBodyFooVal = getFormula(*FooDecl, LoopBodyEnv);
4564 EXPECT_TRUE(LoopBodyEnv.proves(LoopBodyFooVal));
4566 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv);
4567 EXPECT_TRUE(
4568 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal)));
4572 TEST(TransferTest, DoWhileStmtBranchExtendsFlowCondition) {
4573 std::string Code = R"(
4574 void target(bool Foo) {
4575 bool Bar = true;
4576 do {
4577 (void)0;
4578 // [[loop_body]]
4579 Bar = false;
4580 } while (Foo);
4581 (void)0;
4582 // [[after_loop]]
4585 runDataflow(
4586 Code,
4587 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4588 ASTContext &ASTCtx) {
4589 ASSERT_THAT(Results.keys(),
4590 UnorderedElementsAre("loop_body", "after_loop"));
4591 const Environment &LoopBodyEnv =
4592 getEnvironmentAtAnnotation(Results, "loop_body");
4593 const Environment &AfterLoopEnv =
4594 getEnvironmentAtAnnotation(Results, "after_loop");
4595 auto &A = AfterLoopEnv.arena();
4597 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4598 ASSERT_THAT(FooDecl, NotNull());
4600 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
4601 ASSERT_THAT(BarDecl, NotNull());
4603 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv);
4604 auto &LoopBodyBarVal = getFormula(*BarDecl, LoopBodyEnv);
4605 EXPECT_TRUE(
4606 LoopBodyEnv.proves(A.makeOr(LoopBodyBarVal, LoopBodyFooVal)));
4608 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv);
4609 auto &AfterLoopBarVal = getFormula(*BarDecl, AfterLoopEnv);
4610 EXPECT_TRUE(AfterLoopEnv.proves(A.makeNot(AfterLoopFooVal)));
4611 EXPECT_TRUE(AfterLoopEnv.proves(A.makeNot(AfterLoopBarVal)));
4615 TEST(TransferTest, ForStmtBranchExtendsFlowCondition) {
4616 std::string Code = R"(
4617 void target(bool Foo) {
4618 for (; Foo;) {
4619 (void)0;
4620 // [[loop_body]]
4622 (void)0;
4623 // [[after_loop]]
4626 runDataflow(
4627 Code,
4628 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4629 ASTContext &ASTCtx) {
4630 ASSERT_THAT(Results.keys(),
4631 UnorderedElementsAre("loop_body", "after_loop"));
4632 const Environment &LoopBodyEnv =
4633 getEnvironmentAtAnnotation(Results, "loop_body");
4634 const Environment &AfterLoopEnv =
4635 getEnvironmentAtAnnotation(Results, "after_loop");
4637 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4638 ASSERT_THAT(FooDecl, NotNull());
4640 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv);
4641 EXPECT_TRUE(LoopBodyEnv.proves(LoopBodyFooVal));
4643 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv);
4644 EXPECT_TRUE(
4645 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal)));
4649 TEST(TransferTest, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition) {
4650 std::string Code = R"(
4651 void target(bool Foo) {
4652 for (;;) {
4653 (void)0;
4654 // [[loop_body]]
4658 runDataflow(
4659 Code,
4660 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4661 ASTContext &ASTCtx) {
4662 ASSERT_THAT(Results.keys(), UnorderedElementsAre("loop_body"));
4663 const Environment &LoopBodyEnv =
4664 getEnvironmentAtAnnotation(Results, "loop_body");
4666 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4667 ASSERT_THAT(FooDecl, NotNull());
4669 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv);
4670 EXPECT_FALSE(LoopBodyEnv.proves(LoopBodyFooVal));
4674 TEST(TransferTest, ContextSensitiveOptionDisabled) {
4675 std::string Code = R"(
4676 bool GiveBool();
4677 void SetBool(bool &Var) { Var = true; }
4679 void target() {
4680 bool Foo = GiveBool();
4681 SetBool(Foo);
4682 // [[p]]
4685 runDataflow(
4686 Code,
4687 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4688 ASTContext &ASTCtx) {
4689 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4690 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4692 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4693 ASSERT_THAT(FooDecl, NotNull());
4695 auto &FooVal = getFormula(*FooDecl, Env);
4696 EXPECT_FALSE(Env.proves(FooVal));
4697 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));
4699 {BuiltinOptions{/*.ContextSensitiveOpts=*/std::nullopt}});
4702 TEST(TransferTest, ContextSensitiveReturnReference) {
4703 std::string Code = R"(
4704 class S {};
4705 S& target(bool b, S &s) {
4706 return s;
4707 // [[p]]
4710 runDataflow(
4711 Code,
4712 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4713 ASTContext &ASTCtx) {
4714 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4716 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s");
4717 ASSERT_THAT(SDecl, NotNull());
4719 auto *SLoc = Env.getStorageLocation(*SDecl);
4720 ASSERT_THAT(SLoc, NotNull());
4722 ASSERT_THAT(Env.getReturnStorageLocation(), Eq(SLoc));
4724 {BuiltinOptions{ContextSensitiveOptions{}}});
4727 // This test is a regression test, based on a real crash.
4728 TEST(TransferTest, ContextSensitiveReturnReferenceWithConditionalOperator) {
4729 std::string Code = R"(
4730 class S {};
4731 S& target(bool b, S &s) {
4732 return b ? s : s;
4733 // [[p]]
4736 runDataflow(
4737 Code,
4738 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4739 ASTContext &ASTCtx) {
4740 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4741 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4743 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s");
4744 ASSERT_THAT(SDecl, NotNull());
4746 auto *SLoc = Env.getStorageLocation(*SDecl);
4747 ASSERT_THAT(SLoc, NotNull());
4748 EXPECT_THAT(Env.getValue(*SLoc), NotNull());
4750 auto *Loc = Env.getReturnStorageLocation();
4751 ASSERT_THAT(Loc, NotNull());
4752 EXPECT_THAT(Env.getValue(*Loc), NotNull());
4754 // TODO: We would really like to make this stronger assertion, but that
4755 // doesn't work because we don't propagate values correctly through
4756 // the conditional operator yet.
4757 // ASSERT_THAT(Loc, Eq(SLoc));
4759 {BuiltinOptions{ContextSensitiveOptions{}}});
4762 TEST(TransferTest, ContextSensitiveReturnOneOfTwoReferences) {
4763 std::string Code = R"(
4764 class S {};
4765 S &callee(bool b, S &s1_parm, S &s2_parm) {
4766 if (b)
4767 return s1_parm;
4768 else
4769 return s2_parm;
4771 void target(bool b) {
4772 S s1;
4773 S s2;
4774 S &return_s1 = s1;
4775 S &return_s2 = s2;
4776 S &return_dont_know = callee(b, s1, s2);
4777 // [[p]]
4780 runDataflow(
4781 Code,
4782 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4783 ASTContext &ASTCtx) {
4784 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4786 const ValueDecl *S1 = findValueDecl(ASTCtx, "s1");
4787 ASSERT_THAT(S1, NotNull());
4788 const ValueDecl *S2 = findValueDecl(ASTCtx, "s2");
4789 ASSERT_THAT(S2, NotNull());
4790 const ValueDecl *ReturnS1 = findValueDecl(ASTCtx, "return_s1");
4791 ASSERT_THAT(ReturnS1, NotNull());
4792 const ValueDecl *ReturnS2 = findValueDecl(ASTCtx, "return_s2");
4793 ASSERT_THAT(ReturnS2, NotNull());
4794 const ValueDecl *ReturnDontKnow =
4795 findValueDecl(ASTCtx, "return_dont_know");
4796 ASSERT_THAT(ReturnDontKnow, NotNull());
4798 StorageLocation *S1Loc = Env.getStorageLocation(*S1);
4799 StorageLocation *S2Loc = Env.getStorageLocation(*S2);
4801 EXPECT_THAT(Env.getStorageLocation(*ReturnS1), Eq(S1Loc));
4802 EXPECT_THAT(Env.getStorageLocation(*ReturnS2), Eq(S2Loc));
4804 // In the case where we don't have a consistent storage location for
4805 // the return value, the framework creates a new storage location, which
4806 // should be different from the storage locations of `s1` and `s2`.
4807 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S1Loc));
4808 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S2Loc));
4810 {BuiltinOptions{ContextSensitiveOptions{}}});
4813 TEST(TransferTest, ContextSensitiveDepthZero) {
4814 std::string Code = R"(
4815 bool GiveBool();
4816 void SetBool(bool &Var) { Var = true; }
4818 void target() {
4819 bool Foo = GiveBool();
4820 SetBool(Foo);
4821 // [[p]]
4824 runDataflow(
4825 Code,
4826 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4827 ASTContext &ASTCtx) {
4828 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4829 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4831 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4832 ASSERT_THAT(FooDecl, NotNull());
4834 auto &FooVal = getFormula(*FooDecl, Env);
4835 EXPECT_FALSE(Env.proves(FooVal));
4836 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));
4838 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/0}}});
4841 TEST(TransferTest, ContextSensitiveSetTrue) {
4842 std::string Code = R"(
4843 bool GiveBool();
4844 void SetBool(bool &Var) { Var = true; }
4846 void target() {
4847 bool Foo = GiveBool();
4848 SetBool(Foo);
4849 // [[p]]
4852 runDataflow(
4853 Code,
4854 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4855 ASTContext &ASTCtx) {
4856 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4857 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4859 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4860 ASSERT_THAT(FooDecl, NotNull());
4862 auto &FooVal = getFormula(*FooDecl, Env);
4863 EXPECT_TRUE(Env.proves(FooVal));
4865 {BuiltinOptions{ContextSensitiveOptions{}}});
4868 TEST(TransferTest, ContextSensitiveSetFalse) {
4869 std::string Code = R"(
4870 bool GiveBool();
4871 void SetBool(bool &Var) { Var = false; }
4873 void target() {
4874 bool Foo = GiveBool();
4875 SetBool(Foo);
4876 // [[p]]
4879 runDataflow(
4880 Code,
4881 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4882 ASTContext &ASTCtx) {
4883 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4884 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4886 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4887 ASSERT_THAT(FooDecl, NotNull());
4889 auto &FooVal = getFormula(*FooDecl, Env);
4890 EXPECT_TRUE(Env.proves(Env.arena().makeNot(FooVal)));
4892 {BuiltinOptions{ContextSensitiveOptions{}}});
4895 TEST(TransferTest, ContextSensitiveSetBothTrueAndFalse) {
4896 std::string Code = R"(
4897 bool GiveBool();
4898 void SetBool(bool &Var, bool Val) { Var = Val; }
4900 void target() {
4901 bool Foo = GiveBool();
4902 bool Bar = GiveBool();
4903 SetBool(Foo, true);
4904 SetBool(Bar, false);
4905 // [[p]]
4908 runDataflow(
4909 Code,
4910 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4911 ASTContext &ASTCtx) {
4912 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4913 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4914 auto &A = Env.arena();
4916 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4917 ASSERT_THAT(FooDecl, NotNull());
4919 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
4920 ASSERT_THAT(BarDecl, NotNull());
4922 auto &FooVal = getFormula(*FooDecl, Env);
4923 EXPECT_TRUE(Env.proves(FooVal));
4924 EXPECT_FALSE(Env.proves(A.makeNot(FooVal)));
4926 auto &BarVal = getFormula(*BarDecl, Env);
4927 EXPECT_FALSE(Env.proves(BarVal));
4928 EXPECT_TRUE(Env.proves(A.makeNot(BarVal)));
4930 {BuiltinOptions{ContextSensitiveOptions{}}});
4933 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthOne) {
4934 std::string Code = R"(
4935 bool GiveBool();
4936 void SetBool1(bool &Var) { Var = true; }
4937 void SetBool2(bool &Var) { SetBool1(Var); }
4939 void target() {
4940 bool Foo = GiveBool();
4941 SetBool2(Foo);
4942 // [[p]]
4945 runDataflow(
4946 Code,
4947 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4948 ASTContext &ASTCtx) {
4949 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4950 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4952 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4953 ASSERT_THAT(FooDecl, NotNull());
4955 auto &FooVal = getFormula(*FooDecl, Env);
4956 EXPECT_FALSE(Env.proves(FooVal));
4957 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));
4959 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/1}}});
4962 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthTwo) {
4963 std::string Code = R"(
4964 bool GiveBool();
4965 void SetBool1(bool &Var) { Var = true; }
4966 void SetBool2(bool &Var) { SetBool1(Var); }
4968 void target() {
4969 bool Foo = GiveBool();
4970 SetBool2(Foo);
4971 // [[p]]
4974 runDataflow(
4975 Code,
4976 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4977 ASTContext &ASTCtx) {
4978 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4979 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4981 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4982 ASSERT_THAT(FooDecl, NotNull());
4984 auto &FooVal = getFormula(*FooDecl, Env);
4985 EXPECT_TRUE(Env.proves(FooVal));
4987 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}});
4990 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthTwo) {
4991 std::string Code = R"(
4992 bool GiveBool();
4993 void SetBool1(bool &Var) { Var = true; }
4994 void SetBool2(bool &Var) { SetBool1(Var); }
4995 void SetBool3(bool &Var) { SetBool2(Var); }
4997 void target() {
4998 bool Foo = GiveBool();
4999 SetBool3(Foo);
5000 // [[p]]
5003 runDataflow(
5004 Code,
5005 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5006 ASTContext &ASTCtx) {
5007 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5008 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5010 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5011 ASSERT_THAT(FooDecl, NotNull());
5013 auto &FooVal = getFormula(*FooDecl, Env);
5014 EXPECT_FALSE(Env.proves(FooVal));
5015 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));
5017 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}});
5020 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthThree) {
5021 std::string Code = R"(
5022 bool GiveBool();
5023 void SetBool1(bool &Var) { Var = true; }
5024 void SetBool2(bool &Var) { SetBool1(Var); }
5025 void SetBool3(bool &Var) { SetBool2(Var); }
5027 void target() {
5028 bool Foo = GiveBool();
5029 SetBool3(Foo);
5030 // [[p]]
5033 runDataflow(
5034 Code,
5035 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5036 ASTContext &ASTCtx) {
5037 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5038 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5040 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5041 ASSERT_THAT(FooDecl, NotNull());
5043 auto &FooVal = getFormula(*FooDecl, Env);
5044 EXPECT_TRUE(Env.proves(FooVal));
5046 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/3}}});
5049 TEST(TransferTest, ContextSensitiveMutualRecursion) {
5050 std::string Code = R"(
5051 bool Pong(bool X, bool Y);
5053 bool Ping(bool X, bool Y) {
5054 if (X) {
5055 return Y;
5056 } else {
5057 return Pong(!X, Y);
5061 bool Pong(bool X, bool Y) {
5062 if (Y) {
5063 return X;
5064 } else {
5065 return Ping(X, !Y);
5069 void target() {
5070 bool Foo = Ping(false, false);
5071 // [[p]]
5074 runDataflow(
5075 Code,
5076 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5077 ASTContext &ASTCtx) {
5078 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5079 // The analysis doesn't crash...
5080 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5082 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5083 ASSERT_THAT(FooDecl, NotNull());
5085 auto &FooVal = getFormula(*FooDecl, Env);
5086 // ... but it also can't prove anything here.
5087 EXPECT_FALSE(Env.proves(FooVal));
5088 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));
5090 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/4}}});
5093 TEST(TransferTest, ContextSensitiveSetMultipleLines) {
5094 std::string Code = R"(
5095 void SetBools(bool &Var1, bool &Var2) {
5096 Var1 = true;
5097 Var2 = false;
5100 void target() {
5101 bool Foo = false;
5102 bool Bar = true;
5103 SetBools(Foo, Bar);
5104 // [[p]]
5107 runDataflow(
5108 Code,
5109 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5110 ASTContext &ASTCtx) {
5111 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5112 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5114 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5115 ASSERT_THAT(FooDecl, NotNull());
5117 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
5118 ASSERT_THAT(BarDecl, NotNull());
5120 auto &FooVal = getFormula(*FooDecl, Env);
5121 EXPECT_TRUE(Env.proves(FooVal));
5122 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));
5124 auto &BarVal = getFormula(*BarDecl, Env);
5125 EXPECT_FALSE(Env.proves(BarVal));
5126 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal)));
5128 {BuiltinOptions{ContextSensitiveOptions{}}});
5131 TEST(TransferTest, ContextSensitiveSetMultipleBlocks) {
5132 std::string Code = R"(
5133 void IfCond(bool Cond, bool &Then, bool &Else) {
5134 if (Cond) {
5135 Then = true;
5136 } else {
5137 Else = true;
5141 void target() {
5142 bool Foo = false;
5143 bool Bar = false;
5144 bool Baz = false;
5145 IfCond(Foo, Bar, Baz);
5146 // [[p]]
5149 runDataflow(
5150 Code,
5151 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5152 ASTContext &ASTCtx) {
5153 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5154 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5156 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
5157 ASSERT_THAT(BarDecl, NotNull());
5159 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
5160 ASSERT_THAT(BazDecl, NotNull());
5162 auto &BarVal = getFormula(*BarDecl, Env);
5163 EXPECT_FALSE(Env.proves(BarVal));
5164 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal)));
5166 auto &BazVal = getFormula(*BazDecl, Env);
5167 EXPECT_TRUE(Env.proves(BazVal));
5168 EXPECT_FALSE(Env.proves(Env.arena().makeNot(BazVal)));
5170 {BuiltinOptions{ContextSensitiveOptions{}}});
5173 TEST(TransferTest, ContextSensitiveReturnVoid) {
5174 std::string Code = R"(
5175 void Noop() { return; }
5177 void target() {
5178 Noop();
5179 // [[p]]
5182 runDataflow(
5183 Code,
5184 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5185 ASTContext &ASTCtx) {
5186 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5187 // This just tests that the analysis doesn't crash.
5189 {BuiltinOptions{ContextSensitiveOptions{}}});
5192 TEST(TransferTest, ContextSensitiveReturnTrue) {
5193 std::string Code = R"(
5194 bool GiveBool() { return true; }
5196 void target() {
5197 bool Foo = GiveBool();
5198 // [[p]]
5201 runDataflow(
5202 Code,
5203 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5204 ASTContext &ASTCtx) {
5205 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5206 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5208 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5209 ASSERT_THAT(FooDecl, NotNull());
5211 auto &FooVal = getFormula(*FooDecl, Env);
5212 EXPECT_TRUE(Env.proves(FooVal));
5214 {BuiltinOptions{ContextSensitiveOptions{}}});
5217 TEST(TransferTest, ContextSensitiveReturnFalse) {
5218 std::string Code = R"(
5219 bool GiveBool() { return false; }
5221 void target() {
5222 bool Foo = GiveBool();
5223 // [[p]]
5226 runDataflow(
5227 Code,
5228 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5229 ASTContext &ASTCtx) {
5230 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5231 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5233 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5234 ASSERT_THAT(FooDecl, NotNull());
5236 auto &FooVal = getFormula(*FooDecl, Env);
5237 EXPECT_TRUE(Env.proves(Env.arena().makeNot(FooVal)));
5239 {BuiltinOptions{ContextSensitiveOptions{}}});
5242 TEST(TransferTest, ContextSensitiveReturnArg) {
5243 std::string Code = R"(
5244 bool GiveBool();
5245 bool GiveBack(bool Arg) { return Arg; }
5247 void target() {
5248 bool Foo = GiveBool();
5249 bool Bar = GiveBack(Foo);
5250 bool Baz = Foo == Bar;
5251 // [[p]]
5254 runDataflow(
5255 Code,
5256 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5257 ASTContext &ASTCtx) {
5258 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5259 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5261 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
5262 ASSERT_THAT(BazDecl, NotNull());
5264 auto &BazVal = getFormula(*BazDecl, Env);
5265 EXPECT_TRUE(Env.proves(BazVal));
5267 {BuiltinOptions{ContextSensitiveOptions{}}});
5270 TEST(TransferTest, ContextSensitiveReturnInt) {
5271 std::string Code = R"(
5272 int identity(int x) { return x; }
5274 void target() {
5275 int y = identity(42);
5276 // [[p]]
5279 runDataflow(
5280 Code,
5281 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5282 ASTContext &ASTCtx) {
5283 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5284 // This just tests that the analysis doesn't crash.
5286 {BuiltinOptions{ContextSensitiveOptions{}}});
5289 TEST(TransferTest, ContextSensitiveMethodLiteral) {
5290 std::string Code = R"(
5291 class MyClass {
5292 public:
5293 bool giveBool() { return true; }
5296 void target() {
5297 MyClass MyObj;
5298 bool Foo = MyObj.giveBool();
5299 // [[p]]
5302 runDataflow(
5303 Code,
5304 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5305 ASTContext &ASTCtx) {
5306 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5307 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5309 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5310 ASSERT_THAT(FooDecl, NotNull());
5312 auto &FooVal = getFormula(*FooDecl, Env);
5313 EXPECT_TRUE(Env.proves(FooVal));
5315 {BuiltinOptions{ContextSensitiveOptions{}}});
5318 TEST(TransferTest, ContextSensitiveMethodGetter) {
5319 std::string Code = R"(
5320 class MyClass {
5321 public:
5322 bool getField() { return Field; }
5324 bool Field;
5327 void target() {
5328 MyClass MyObj;
5329 MyObj.Field = true;
5330 bool Foo = MyObj.getField();
5331 // [[p]]
5334 runDataflow(
5335 Code,
5336 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5337 ASTContext &ASTCtx) {
5338 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5339 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5341 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5342 ASSERT_THAT(FooDecl, NotNull());
5344 auto &FooVal = getFormula(*FooDecl, Env);
5345 EXPECT_TRUE(Env.proves(FooVal));
5347 {BuiltinOptions{ContextSensitiveOptions{}}});
5350 TEST(TransferTest, ContextSensitiveMethodSetter) {
5351 std::string Code = R"(
5352 class MyClass {
5353 public:
5354 void setField(bool Val) { Field = Val; }
5356 bool Field;
5359 void target() {
5360 MyClass MyObj;
5361 MyObj.setField(true);
5362 bool Foo = MyObj.Field;
5363 // [[p]]
5366 runDataflow(
5367 Code,
5368 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5369 ASTContext &ASTCtx) {
5370 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5371 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5373 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5374 ASSERT_THAT(FooDecl, NotNull());
5376 auto &FooVal = getFormula(*FooDecl, Env);
5377 EXPECT_TRUE(Env.proves(FooVal));
5379 {BuiltinOptions{ContextSensitiveOptions{}}});
5382 TEST(TransferTest, ContextSensitiveMethodGetterAndSetter) {
5383 std::string Code = R"(
5384 class MyClass {
5385 public:
5386 bool getField() { return Field; }
5387 void setField(bool Val) { Field = Val; }
5389 private:
5390 bool Field;
5393 void target() {
5394 MyClass MyObj;
5395 MyObj.setField(true);
5396 bool Foo = MyObj.getField();
5397 // [[p]]
5400 runDataflow(
5401 Code,
5402 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5403 ASTContext &ASTCtx) {
5404 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5405 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5407 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5408 ASSERT_THAT(FooDecl, NotNull());
5410 auto &FooVal = getFormula(*FooDecl, Env);
5411 EXPECT_TRUE(Env.proves(FooVal));
5413 {BuiltinOptions{ContextSensitiveOptions{}}});
5417 TEST(TransferTest, ContextSensitiveMethodTwoLayersVoid) {
5418 std::string Code = R"(
5419 class MyClass {
5420 public:
5421 void Inner() { MyField = true; }
5422 void Outer() { Inner(); }
5424 bool MyField;
5427 void target() {
5428 MyClass MyObj;
5429 MyObj.Outer();
5430 bool Foo = MyObj.MyField;
5431 // [[p]]
5434 runDataflow(
5435 Code,
5436 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5437 ASTContext &ASTCtx) {
5438 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5440 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5442 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5443 ASSERT_THAT(FooDecl, NotNull());
5445 auto &FooVal = getFormula(*FooDecl, Env);
5446 EXPECT_TRUE(Env.proves(FooVal));
5448 {BuiltinOptions{ContextSensitiveOptions{}}});
5451 TEST(TransferTest, ContextSensitiveMethodTwoLayersReturn) {
5452 std::string Code = R"(
5453 class MyClass {
5454 public:
5455 bool Inner() { return MyField; }
5456 bool Outer() { return Inner(); }
5458 bool MyField;
5461 void target() {
5462 MyClass MyObj;
5463 MyObj.MyField = true;
5464 bool Foo = MyObj.Outer();
5465 // [[p]]
5468 runDataflow(
5469 Code,
5470 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5471 ASTContext &ASTCtx) {
5472 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5474 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5476 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5477 ASSERT_THAT(FooDecl, NotNull());
5479 auto &FooVal = getFormula(*FooDecl, Env);
5480 EXPECT_TRUE(Env.proves(FooVal));
5482 {BuiltinOptions{ContextSensitiveOptions{}}});
5485 TEST(TransferTest, ContextSensitiveConstructorBody) {
5486 std::string Code = R"(
5487 class MyClass {
5488 public:
5489 MyClass() { MyField = true; }
5491 bool MyField;
5494 void target() {
5495 MyClass MyObj;
5496 bool Foo = MyObj.MyField;
5497 // [[p]]
5500 runDataflow(
5501 Code,
5502 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5503 ASTContext &ASTCtx) {
5504 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5505 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5507 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5508 ASSERT_THAT(FooDecl, NotNull());
5510 auto &FooVal = getFormula(*FooDecl, Env);
5511 EXPECT_TRUE(Env.proves(FooVal));
5513 {BuiltinOptions{ContextSensitiveOptions{}}});
5516 TEST(TransferTest, ContextSensitiveConstructorInitializer) {
5517 std::string Code = R"(
5518 class MyClass {
5519 public:
5520 MyClass() : MyField(true) {}
5522 bool MyField;
5525 void target() {
5526 MyClass MyObj;
5527 bool Foo = MyObj.MyField;
5528 // [[p]]
5531 runDataflow(
5532 Code,
5533 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5534 ASTContext &ASTCtx) {
5535 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5536 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5538 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5539 ASSERT_THAT(FooDecl, NotNull());
5541 auto &FooVal = getFormula(*FooDecl, Env);
5542 EXPECT_TRUE(Env.proves(FooVal));
5544 {BuiltinOptions{ContextSensitiveOptions{}}});
5547 TEST(TransferTest, ContextSensitiveConstructorDefault) {
5548 std::string Code = R"(
5549 class MyClass {
5550 public:
5551 MyClass() = default;
5553 bool MyField = true;
5556 void target() {
5557 MyClass MyObj;
5558 bool Foo = MyObj.MyField;
5559 // [[p]]
5562 runDataflow(
5563 Code,
5564 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5565 ASTContext &ASTCtx) {
5566 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5567 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5569 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5570 ASSERT_THAT(FooDecl, NotNull());
5572 auto &FooVal = getFormula(*FooDecl, Env);
5573 EXPECT_TRUE(Env.proves(FooVal));
5575 {BuiltinOptions{ContextSensitiveOptions{}}});
5578 TEST(TransferTest, ContextSensitiveSelfReferentialClass) {
5579 // Test that the `this` pointer seen in the constructor has the same value
5580 // as the address of the variable the object is constructed into.
5581 std::string Code = R"(
5582 class MyClass {
5583 public:
5584 MyClass() : Self(this) {}
5585 MyClass *Self;
5588 void target() {
5589 MyClass MyObj;
5590 MyClass *SelfPtr = MyObj.Self;
5591 // [[p]]
5594 runDataflow(
5595 Code,
5596 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5597 ASTContext &ASTCtx) {
5598 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5600 const ValueDecl *MyObjDecl = findValueDecl(ASTCtx, "MyObj");
5601 ASSERT_THAT(MyObjDecl, NotNull());
5603 const ValueDecl *SelfDecl = findValueDecl(ASTCtx, "SelfPtr");
5604 ASSERT_THAT(SelfDecl, NotNull());
5606 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5607 auto &SelfVal = *cast<PointerValue>(Env.getValue(*SelfDecl));
5608 EXPECT_EQ(Env.getStorageLocation(*MyObjDecl), &SelfVal.getPointeeLoc());
5610 {BuiltinOptions{ContextSensitiveOptions{}}});
5613 TEST(TransferTest, UnnamedBitfieldInitializer) {
5614 std::string Code = R"(
5615 struct B {};
5616 struct A {
5617 unsigned a;
5618 unsigned : 4;
5619 unsigned c;
5620 B b;
5622 void target() {
5623 A a = {};
5624 A test = a;
5625 (void)test.c;
5628 runDataflow(
5629 Code,
5630 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5631 ASTContext &ASTCtx) {
5632 // This doesn't need a body because this test was crashing the framework
5633 // before handling correctly Unnamed bitfields in `InitListExpr`.
5637 // Repro for a crash that used to occur with chained short-circuiting logical
5638 // operators.
5639 TEST(TransferTest, ChainedLogicalOps) {
5640 std::string Code = R"(
5641 bool target() {
5642 bool b = true || false || false || false;
5643 // [[p]]
5644 return b;
5647 runDataflow(
5648 Code,
5649 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5650 ASTContext &ASTCtx) {
5651 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5652 auto &B = getValueForDecl<BoolValue>(ASTCtx, Env, "b").formula();
5653 EXPECT_TRUE(Env.proves(B));
5657 // Repro for a crash that used to occur when we call a `noreturn` function
5658 // within one of the operands of a `&&` or `||` operator.
5659 TEST(TransferTest, NoReturnFunctionInsideShortCircuitedBooleanOp) {
5660 std::string Code = R"(
5661 __attribute__((noreturn)) int doesnt_return();
5662 bool some_condition();
5663 void target(bool b1, bool b2) {
5664 // Neither of these should crash. In addition, if we don't terminate the
5665 // program, we know that the operators need to trigger the short-circuit
5666 // logic, so `NoreturnOnRhsOfAnd` will be false and `NoreturnOnRhsOfOr`
5667 // will be true.
5668 bool NoreturnOnRhsOfAnd = b1 && doesnt_return() > 0;
5669 bool NoreturnOnRhsOfOr = b2 || doesnt_return() > 0;
5671 // Calling a `noreturn` function on the LHS of an `&&` or `||` makes the
5672 // entire expression unreachable. So we know that in both of the following
5673 // cases, if `target()` terminates, the `else` branch was taken.
5674 bool NoreturnOnLhsMakesAndUnreachable = false;
5675 if (some_condition())
5676 doesnt_return() > 0 && some_condition();
5677 else
5678 NoreturnOnLhsMakesAndUnreachable = true;
5680 bool NoreturnOnLhsMakesOrUnreachable = false;
5681 if (some_condition())
5682 doesnt_return() > 0 || some_condition();
5683 else
5684 NoreturnOnLhsMakesOrUnreachable = true;
5686 // [[p]]
5689 runDataflow(
5690 Code,
5691 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5692 ASTContext &ASTCtx) {
5693 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5694 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5695 auto &A = Env.arena();
5697 // Check that [[p]] is reachable with a non-false flow condition.
5698 EXPECT_FALSE(Env.proves(A.makeLiteral(false)));
5700 auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, "b1").formula();
5701 EXPECT_TRUE(Env.proves(A.makeNot(B1)));
5703 auto &NoreturnOnRhsOfAnd =
5704 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfAnd").formula();
5705 EXPECT_TRUE(Env.proves(A.makeNot(NoreturnOnRhsOfAnd)));
5707 auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, "b2").formula();
5708 EXPECT_TRUE(Env.proves(B2));
5710 auto &NoreturnOnRhsOfOr =
5711 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfOr")
5712 .formula();
5713 EXPECT_TRUE(Env.proves(NoreturnOnRhsOfOr));
5715 auto &NoreturnOnLhsMakesAndUnreachable = getValueForDecl<BoolValue>(
5716 ASTCtx, Env, "NoreturnOnLhsMakesAndUnreachable").formula();
5717 EXPECT_TRUE(Env.proves(NoreturnOnLhsMakesAndUnreachable));
5719 auto &NoreturnOnLhsMakesOrUnreachable = getValueForDecl<BoolValue>(
5720 ASTCtx, Env, "NoreturnOnLhsMakesOrUnreachable").formula();
5721 EXPECT_TRUE(Env.proves(NoreturnOnLhsMakesOrUnreachable));
5725 TEST(TransferTest, NewExpressions) {
5726 std::string Code = R"(
5727 void target() {
5728 int *p = new int(42);
5729 // [[after_new]]
5732 runDataflow(
5733 Code,
5734 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5735 ASTContext &ASTCtx) {
5736 const Environment &Env =
5737 getEnvironmentAtAnnotation(Results, "after_new");
5739 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p");
5741 EXPECT_THAT(Env.getValue(P.getPointeeLoc()), NotNull());
5745 TEST(TransferTest, NewExpressions_Structs) {
5746 std::string Code = R"(
5747 struct Inner {
5748 int InnerField;
5751 struct Outer {
5752 Inner OuterField;
5755 void target() {
5756 Outer *p = new Outer;
5757 // Access the fields to make sure the analysis actually generates children
5758 // for them in the `RecordStorageLocation` and `RecordValue`.
5759 p->OuterField.InnerField;
5760 // [[after_new]]
5763 runDataflow(
5764 Code,
5765 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5766 ASTContext &ASTCtx) {
5767 const Environment &Env =
5768 getEnvironmentAtAnnotation(Results, "after_new");
5770 const ValueDecl *OuterField = findValueDecl(ASTCtx, "OuterField");
5771 const ValueDecl *InnerField = findValueDecl(ASTCtx, "InnerField");
5773 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p");
5775 auto &OuterLoc = cast<RecordStorageLocation>(P.getPointeeLoc());
5776 auto &OuterFieldLoc =
5777 *cast<RecordStorageLocation>(OuterLoc.getChild(*OuterField));
5778 auto &InnerFieldLoc = *OuterFieldLoc.getChild(*InnerField);
5780 // Values for the struct and all fields exist after the new.
5781 EXPECT_THAT(Env.getValue(OuterLoc), NotNull());
5782 EXPECT_THAT(Env.getValue(OuterFieldLoc), NotNull());
5783 EXPECT_THAT(Env.getValue(InnerFieldLoc), NotNull());
5787 TEST(TransferTest, FunctionToPointerDecayHasValue) {
5788 std::string Code = R"(
5789 struct A { static void static_member_func(); };
5790 void target() {
5791 // To check that we're treating function-to-pointer decay correctly,
5792 // create two pointers, then verify they refer to the same storage
5793 // location.
5794 // We need to do the test this way because even if an initializer (in this
5795 // case, the function-to-pointer decay) does not create a value, we still
5796 // create a value for the variable.
5797 void (*non_member_p1)() = target;
5798 void (*non_member_p2)() = target;
5800 // Do the same thing but for a static member function.
5801 void (*member_p1)() = A::static_member_func;
5802 void (*member_p2)() = A::static_member_func;
5803 // [[p]]
5806 runDataflow(
5807 Code,
5808 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5809 ASTContext &ASTCtx) {
5810 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5812 auto &NonMemberP1 =
5813 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p1");
5814 auto &NonMemberP2 =
5815 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p2");
5816 EXPECT_EQ(&NonMemberP1.getPointeeLoc(), &NonMemberP2.getPointeeLoc());
5818 auto &MemberP1 =
5819 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p1");
5820 auto &MemberP2 =
5821 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p2");
5822 EXPECT_EQ(&MemberP1.getPointeeLoc(), &MemberP2.getPointeeLoc());
5826 // Check that a builtin function is not associated with a value. (It's only
5827 // possible to call builtin functions directly, not take their address.)
5828 TEST(TransferTest, BuiltinFunctionModeled) {
5829 std::string Code = R"(
5830 void target() {
5831 __builtin_expect(0, 0);
5832 // [[p]]
5835 runDataflow(
5836 Code,
5837 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5838 ASTContext &ASTCtx) {
5839 using ast_matchers::selectFirst;
5840 using ast_matchers::match;
5841 using ast_matchers::traverse;
5842 using ast_matchers::implicitCastExpr;
5843 using ast_matchers::hasCastKind;
5845 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5847 auto *ImplicitCast = selectFirst<ImplicitCastExpr>(
5848 "implicit_cast",
5849 match(traverse(TK_AsIs,
5850 implicitCastExpr(hasCastKind(CK_BuiltinFnToFnPtr))
5851 .bind("implicit_cast")),
5852 ASTCtx));
5854 ASSERT_THAT(ImplicitCast, NotNull());
5855 EXPECT_THAT(Env.getValue(*ImplicitCast), IsNull());
5859 // Check that a callee of a member operator call is modeled as a `PointerValue`.
5860 // Member operator calls are unusual in that their callee is a pointer that
5861 // stems from a `FunctionToPointerDecay`. In calls to non-operator non-static
5862 // member functions, the callee is a `MemberExpr` (which does not have pointer
5863 // type).
5864 // We want to make sure that we produce a pointer value for the callee in this
5865 // specific scenario and that its storage location is durable (for convergence).
5866 TEST(TransferTest, MemberOperatorCallModelsPointerForCallee) {
5867 std::string Code = R"(
5868 struct S {
5869 bool operator!=(S s);
5871 void target() {
5872 S s;
5873 (void)(s != s);
5874 (void)(s != s);
5875 // [[p]]
5878 runDataflow(
5879 Code,
5880 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5881 ASTContext &ASTCtx) {
5882 using ast_matchers::selectFirst;
5883 using ast_matchers::match;
5884 using ast_matchers::traverse;
5885 using ast_matchers::cxxOperatorCallExpr;
5887 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5889 auto Matches = match(
5890 traverse(TK_AsIs, cxxOperatorCallExpr().bind("call")), ASTCtx);
5892 ASSERT_EQ(Matches.size(), 2UL);
5894 auto *Call1 = Matches[0].getNodeAs<CXXOperatorCallExpr>("call");
5895 auto *Call2 = Matches[1].getNodeAs<CXXOperatorCallExpr>("call");
5897 ASSERT_THAT(Call1, NotNull());
5898 ASSERT_THAT(Call2, NotNull());
5900 EXPECT_EQ(cast<ImplicitCastExpr>(Call1->getCallee())->getCastKind(),
5901 CK_FunctionToPointerDecay);
5902 EXPECT_EQ(cast<ImplicitCastExpr>(Call2->getCallee())->getCastKind(),
5903 CK_FunctionToPointerDecay);
5905 auto *Ptr1 = cast<PointerValue>(Env.getValue(*Call1->getCallee()));
5906 auto *Ptr2 = cast<PointerValue>(Env.getValue(*Call2->getCallee()));
5908 ASSERT_EQ(&Ptr1->getPointeeLoc(), &Ptr2->getPointeeLoc());
5912 // Check that fields of anonymous records are modeled.
5913 TEST(TransferTest, AnonymousStruct) {
5914 std::string Code = R"(
5915 struct S {
5916 struct {
5917 bool b;
5920 void target() {
5921 S s;
5922 s.b = true;
5923 // [[p]]
5926 runDataflow(
5927 Code,
5928 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5929 ASTContext &ASTCtx) {
5930 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5931 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s");
5932 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b");
5933 const IndirectFieldDecl *IndirectField =
5934 findIndirectFieldDecl(ASTCtx, "b");
5936 auto *S = cast<RecordStorageLocation>(Env.getStorageLocation(*SDecl));
5937 auto &AnonStruct = *cast<RecordStorageLocation>(
5938 S->getChild(*cast<ValueDecl>(IndirectField->chain().front())));
5940 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env));
5941 ASSERT_TRUE(Env.proves(B->formula()));
5945 TEST(TransferTest, AnonymousStructWithInitializer) {
5946 std::string Code = R"(
5947 struct target {
5948 target() {
5949 (void)0;
5950 // [[p]]
5952 struct {
5953 bool b = true;
5957 runDataflow(
5958 Code,
5959 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5960 ASTContext &ASTCtx) {
5961 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5962 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b");
5963 const IndirectFieldDecl *IndirectField =
5964 findIndirectFieldDecl(ASTCtx, "b");
5966 auto *ThisLoc =
5967 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation());
5968 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild(
5969 *cast<ValueDecl>(IndirectField->chain().front())));
5971 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env));
5972 ASSERT_TRUE(Env.proves(B->formula()));
5976 TEST(TransferTest, AnonymousStructWithReferenceField) {
5977 std::string Code = R"(
5978 int global_i = 0;
5979 struct target {
5980 target() {
5981 (void)0;
5982 // [[p]]
5984 struct {
5985 int &i = global_i;
5989 runDataflow(
5990 Code,
5991 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5992 ASTContext &ASTCtx) {
5993 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5994 const ValueDecl *GlobalIDecl = findValueDecl(ASTCtx, "global_i");
5995 const ValueDecl *IDecl = findValueDecl(ASTCtx, "i");
5996 const IndirectFieldDecl *IndirectField =
5997 findIndirectFieldDecl(ASTCtx, "i");
5999 auto *ThisLoc =
6000 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation());
6001 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild(
6002 *cast<ValueDecl>(IndirectField->chain().front())));
6004 ASSERT_EQ(AnonStruct.getChild(*IDecl),
6005 Env.getStorageLocation(*GlobalIDecl));
6009 TEST(TransferTest, EvaluateBlockWithUnreachablePreds) {
6010 // This is a crash repro.
6011 // `false` block may not have been processed when we try to evaluate the `||`
6012 // after visiting `true`, because it is not necessary (and therefore the edge
6013 // is marked unreachable). Trying to get the analysis state via
6014 // `getEnvironment` for the subexpression still should not crash.
6015 std::string Code = R"(
6016 int target(int i) {
6017 if ((i < 0 && true) || false) {
6018 return 0;
6020 return 0;
6023 runDataflow(
6024 Code,
6025 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6026 ASTContext &ASTCtx) {});
6029 TEST(TransferTest, LambdaCaptureByCopy) {
6030 std::string Code = R"(
6031 void target(int Foo, int Bar) {
6032 [Foo]() {
6033 (void)0;
6034 // [[p]]
6035 }();
6038 runDataflowOnLambda(
6039 Code,
6040 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6041 ASTContext &ASTCtx) {
6042 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6043 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
6045 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
6046 ASSERT_THAT(FooDecl, NotNull());
6048 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
6049 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
6051 const Value *FooVal = Env.getValue(*FooLoc);
6052 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
6054 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
6055 ASSERT_THAT(BarDecl, NotNull());
6057 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
6058 EXPECT_THAT(BarLoc, IsNull());
6062 TEST(TransferTest, LambdaCaptureByReference) {
6063 std::string Code = R"(
6064 void target(int Foo, int Bar) {
6065 [&Foo]() {
6066 (void)0;
6067 // [[p]]
6068 }();
6071 runDataflowOnLambda(
6072 Code,
6073 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6074 ASTContext &ASTCtx) {
6075 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6076 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
6078 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
6079 ASSERT_THAT(FooDecl, NotNull());
6081 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
6082 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
6084 const Value *FooVal = Env.getValue(*FooLoc);
6085 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
6087 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
6088 ASSERT_THAT(BarDecl, NotNull());
6090 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
6091 EXPECT_THAT(BarLoc, IsNull());
6095 TEST(TransferTest, LambdaCaptureWithInitializer) {
6096 std::string Code = R"(
6097 void target(int Bar) {
6098 [Foo=Bar]() {
6099 (void)0;
6100 // [[p]]
6101 }();
6104 runDataflowOnLambda(
6105 Code,
6106 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6107 ASTContext &ASTCtx) {
6108 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6109 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
6111 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
6112 ASSERT_THAT(FooDecl, NotNull());
6114 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
6115 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
6117 const Value *FooVal = Env.getValue(*FooLoc);
6118 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
6120 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
6121 ASSERT_THAT(BarDecl, NotNull());
6123 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
6124 EXPECT_THAT(BarLoc, IsNull());
6128 TEST(TransferTest, LambdaCaptureByCopyImplicit) {
6129 std::string Code = R"(
6130 void target(int Foo, int Bar) {
6131 [=]() {
6132 Foo;
6133 // [[p]]
6134 }();
6137 runDataflowOnLambda(
6138 Code,
6139 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6140 ASTContext &ASTCtx) {
6141 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6142 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
6144 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
6145 ASSERT_THAT(FooDecl, NotNull());
6147 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
6148 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
6150 const Value *FooVal = Env.getValue(*FooLoc);
6151 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
6153 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
6154 ASSERT_THAT(BarDecl, NotNull());
6156 // There is no storage location for `Bar` because it isn't used in the
6157 // body of the lambda.
6158 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
6159 EXPECT_THAT(BarLoc, IsNull());
6163 TEST(TransferTest, LambdaCaptureByReferenceImplicit) {
6164 std::string Code = R"(
6165 void target(int Foo, int Bar) {
6166 [&]() {
6167 Foo;
6168 // [[p]]
6169 }();
6172 runDataflowOnLambda(
6173 Code,
6174 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6175 ASTContext &ASTCtx) {
6176 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6177 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
6179 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
6180 ASSERT_THAT(FooDecl, NotNull());
6182 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
6183 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
6185 const Value *FooVal = Env.getValue(*FooLoc);
6186 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
6188 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
6189 ASSERT_THAT(BarDecl, NotNull());
6191 // There is no storage location for `Bar` because it isn't used in the
6192 // body of the lambda.
6193 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
6194 EXPECT_THAT(BarLoc, IsNull());
6198 TEST(TransferTest, LambdaCaptureThis) {
6199 std::string Code = R"(
6200 struct Bar {
6201 int Foo;
6203 void target() {
6204 [this]() {
6205 Foo;
6206 // [[p]]
6207 }();
6211 runDataflowOnLambda(
6212 Code,
6213 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6214 ASTContext &ASTCtx) {
6215 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6216 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
6218 const RecordStorageLocation *ThisPointeeLoc =
6219 Env.getThisPointeeStorageLocation();
6220 ASSERT_THAT(ThisPointeeLoc, NotNull());
6222 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
6223 ASSERT_THAT(FooDecl, NotNull());
6225 const StorageLocation *FooLoc = ThisPointeeLoc->getChild(*FooDecl);
6226 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
6228 const Value *FooVal = Env.getValue(*FooLoc);
6229 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
6233 TEST(TransferTest, DifferentReferenceLocInJoin) {
6234 // This test triggers a case where the storage location for a reference-type
6235 // variable is different for two states being joined. We used to believe this
6236 // could not happen and therefore had an assertion disallowing this; this test
6237 // exists to demonstrate that we can handle this condition without a failing
6238 // assertion. See also the discussion here:
6239 // https://discourse.llvm.org/t/70086/6
6240 std::string Code = R"(
6241 namespace std {
6242 template <class T> struct initializer_list {
6243 const T* begin();
6244 const T* end();
6248 void target(char* p, char* end) {
6249 while (p != end) {
6250 if (*p == ' ') {
6251 p++;
6252 continue;
6255 auto && range = {1, 2};
6256 for (auto b = range.begin(), e = range.end(); b != e; ++b) {
6258 (void)0;
6259 // [[p]]
6263 runDataflow(
6264 Code,
6265 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6266 ASTContext &ASTCtx) {
6267 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
6269 // Joining environments with different storage locations for the same
6270 // declaration results in the declaration being removed from the joined
6271 // environment.
6272 const ValueDecl *VD = findValueDecl(ASTCtx, "range");
6273 ASSERT_EQ(Env.getStorageLocation(*VD), nullptr);
6277 } // namespace