[clang-format] Fix a bug in aligning comments above PPDirective (#72791)
[llvm-project.git] / clang / unittests / Analysis / FlowSensitive / TransferTest.cpp
blobade0d202ced2f37c8b4588936be898c9c3fea882
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 // It's legal for the assignment operator to take its source parameter by value.
2217 // Check that we handle this correctly. (This is a repro -- we used to
2218 // assert-fail on this.)
2219 TEST(TransferTest, AssignmentOperator_ArgByValue) {
2220 std::string Code = R"(
2221 struct A {
2222 int Baz;
2223 A &operator=(A);
2226 void target() {
2227 A Foo = { 1 };
2228 A Bar = { 2 };
2229 Foo = Bar;
2230 // [[p]]
2233 runDataflow(
2234 Code,
2235 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2236 ASTContext &ASTCtx) {
2237 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2238 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2240 const auto &FooLoc =
2241 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo");
2242 const auto &BarLoc =
2243 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar");
2245 const auto *FooBazVal =
2246 cast<IntegerValue>(getFieldValue(&FooLoc, *BazDecl, Env));
2247 const auto *BarBazVal =
2248 cast<IntegerValue>(getFieldValue(&BarLoc, *BazDecl, Env));
2249 EXPECT_EQ(FooBazVal, BarBazVal);
2253 TEST(TransferTest, AssignmentOperatorFromBase) {
2254 // This is a crash repro. We don't model the copy this case, so no
2255 // expectations on the copied field of the base class are checked.
2256 std::string Code = R"(
2257 struct Base {
2258 int base;
2260 struct Derived : public Base {
2261 using Base::operator=;
2262 int derived;
2264 void target(Base B, Derived D) {
2265 D.base = 1;
2266 D.derived = 1;
2267 D = B;
2268 // [[p]]
2271 runDataflow(
2272 Code,
2273 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2274 ASTContext &ASTCtx) {});
2277 TEST(TransferTest, AssignmentOperatorFromCallResult) {
2278 std::string Code = R"(
2279 struct A {};
2280 A ReturnA();
2282 void target() {
2283 A MyA;
2284 MyA = ReturnA();
2287 runDataflow(
2288 Code,
2289 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2290 ASTContext &ASTCtx) {
2291 // As of this writing, we don't produce a `Value` for the call
2292 // `ReturnA()`. The only condition we're testing for is that the
2293 // analysis should not crash in this case.
2297 TEST(TransferTest, AssignmentOperatorWithInitAndInheritance) {
2298 // This is a crash repro.
2299 std::string Code = R"(
2300 struct B { int Foo; };
2301 struct S : public B {};
2302 void target() {
2303 S S1 = { 1 };
2304 S S2;
2305 S S3;
2306 S1 = S2; // Only Dst has InitListExpr.
2307 S3 = S1; // Only Src has InitListExpr.
2308 // [[p]]
2311 runDataflow(
2312 Code,
2313 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2314 ASTContext &ASTCtx) {});
2317 TEST(TransferTest, CopyConstructor) {
2318 std::string Code = R"(
2319 struct A {
2320 int Baz;
2323 void target() {
2324 A Foo = { 1 };
2325 A Bar = Foo;
2326 // [[after_copy]]
2327 Foo.Baz = 2;
2328 // [[after_update]]
2331 runDataflow(
2332 Code,
2333 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2334 ASTContext &ASTCtx) {
2335 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2336 ASSERT_THAT(FooDecl, NotNull());
2338 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2339 ASSERT_THAT(BarDecl, NotNull());
2341 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2342 ASSERT_THAT(BazDecl, NotNull());
2344 // after_copy
2346 const Environment &Env =
2347 getEnvironmentAtAnnotation(Results, "after_copy");
2349 const auto *FooLoc =
2350 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2351 const auto *BarLoc =
2352 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl));
2354 // `Foo` and `Bar` have different `RecordValue`s associated with them.
2355 const auto *FooVal = cast<RecordValue>(Env.getValue(*FooLoc));
2356 const auto *BarVal = cast<RecordValue>(Env.getValue(*BarLoc));
2357 EXPECT_NE(FooVal, BarVal);
2359 // But the records compare equal.
2360 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env));
2362 // In particular, the value of `Baz` in both records is the same.
2363 const auto *FooBazVal =
2364 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env));
2365 const auto *BarBazVal =
2366 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env));
2367 EXPECT_EQ(FooBazVal, BarBazVal);
2370 // after_update
2372 const Environment &Env =
2373 getEnvironmentAtAnnotation(Results, "after_update");
2375 const auto *FooLoc =
2376 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2377 const auto *BarLoc =
2378 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl));
2380 EXPECT_FALSE(recordsEqual(*FooLoc, *BarLoc, Env));
2382 const auto *FooBazVal =
2383 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env));
2384 const auto *BarBazVal =
2385 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env));
2386 EXPECT_NE(FooBazVal, BarBazVal);
2391 TEST(TransferTest, CopyConstructorWithDefaultArgument) {
2392 std::string Code = R"(
2393 struct A {
2394 int Baz;
2395 A() = default;
2396 A(const A& a, bool def = true) { Baz = a.Baz; }
2399 void target() {
2400 A Foo;
2401 (void)Foo.Baz;
2402 A Bar = Foo;
2403 // [[p]]
2406 runDataflow(
2407 Code,
2408 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2409 ASTContext &ASTCtx) {
2410 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2411 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2413 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2414 ASSERT_THAT(FooDecl, NotNull());
2416 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2417 ASSERT_THAT(BarDecl, NotNull());
2419 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2420 ASSERT_THAT(BazDecl, NotNull());
2422 const auto *FooLoc =
2423 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2424 const auto *BarLoc =
2425 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl));
2426 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env));
2428 const auto *FooBazVal =
2429 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env));
2430 const auto *BarBazVal =
2431 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env));
2432 EXPECT_EQ(FooBazVal, BarBazVal);
2436 TEST(TransferTest, CopyConstructorWithParens) {
2437 std::string Code = R"(
2438 struct A {
2439 int Baz;
2442 void target() {
2443 A Foo;
2444 (void)Foo.Baz;
2445 A Bar((A(Foo)));
2446 // [[p]]
2449 runDataflow(
2450 Code,
2451 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2452 ASTContext &ASTCtx) {
2453 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2454 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2456 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2457 ASSERT_THAT(FooDecl, NotNull());
2459 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2460 ASSERT_THAT(BarDecl, NotNull());
2462 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2463 ASSERT_THAT(BazDecl, NotNull());
2465 const auto *FooLoc =
2466 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2467 const auto *BarLoc =
2468 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl));
2469 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env));
2471 const auto *FooBazVal =
2472 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env));
2473 const auto *BarBazVal =
2474 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env));
2475 EXPECT_EQ(FooBazVal, BarBazVal);
2479 TEST(TransferTest, CopyConstructorWithInitializerListAsSyntacticSugar) {
2480 std::string Code = R"(
2481 struct A {
2482 int Baz;
2484 void target() {
2485 A Foo = {3};
2486 (void)Foo.Baz;
2487 A Bar = {A(Foo)};
2488 // [[p]]
2491 runDataflow(
2492 Code,
2493 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2494 ASTContext &ASTCtx) {
2495 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2497 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2499 const auto &FooLoc =
2500 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo");
2501 const auto &BarLoc =
2502 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar");
2504 const auto *FooBazVal =
2505 cast<IntegerValue>(getFieldValue(&FooLoc, *BazDecl, Env));
2506 const auto *BarBazVal =
2507 cast<IntegerValue>(getFieldValue(&BarLoc, *BazDecl, Env));
2508 EXPECT_EQ(FooBazVal, BarBazVal);
2512 TEST(TransferTest, CopyConstructorArgIsRefReturnedByFunction) {
2513 // This is a crash repro.
2514 std::string Code = R"(
2515 struct S {};
2516 const S &returnsSRef();
2517 void target() {
2518 S s(returnsSRef());
2521 runDataflow(
2522 Code,
2523 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2524 ASTContext &ASTCtx) {});
2527 TEST(TransferTest, MoveConstructor) {
2528 std::string Code = R"(
2529 namespace std {
2531 template <typename T> struct remove_reference { using type = T; };
2532 template <typename T> struct remove_reference<T&> { using type = T; };
2533 template <typename T> struct remove_reference<T&&> { using type = T; };
2535 template <typename T>
2536 using remove_reference_t = typename remove_reference<T>::type;
2538 template <typename T>
2539 std::remove_reference_t<T>&& move(T&& x);
2541 } // namespace std
2543 struct A {
2544 int Baz;
2547 void target() {
2548 A Foo;
2549 A Bar;
2550 (void)Foo.Baz;
2551 // [[p1]]
2552 Foo = std::move(Bar);
2553 // [[p2]]
2556 runDataflow(
2557 Code,
2558 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2559 ASTContext &ASTCtx) {
2560 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
2561 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
2562 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
2564 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2565 ASSERT_THAT(FooDecl, NotNull());
2567 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2568 ASSERT_THAT(BarDecl, NotNull());
2570 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2571 ASSERT_THAT(BazDecl, NotNull());
2573 const auto *FooLoc1 =
2574 cast<RecordStorageLocation>(Env1.getStorageLocation(*FooDecl));
2575 const auto *BarLoc1 =
2576 cast<RecordStorageLocation>(Env1.getStorageLocation(*BarDecl));
2578 EXPECT_FALSE(recordsEqual(*FooLoc1, *BarLoc1, Env1));
2580 const auto *FooVal1 = cast<RecordValue>(Env1.getValue(*FooLoc1));
2581 const auto *BarVal1 = cast<RecordValue>(Env1.getValue(*BarLoc1));
2582 EXPECT_NE(FooVal1, BarVal1);
2584 const auto *FooBazVal1 =
2585 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env1));
2586 const auto *BarBazVal1 =
2587 cast<IntegerValue>(getFieldValue(BarLoc1, *BazDecl, Env1));
2588 EXPECT_NE(FooBazVal1, BarBazVal1);
2590 const auto *FooLoc2 =
2591 cast<RecordStorageLocation>(Env2.getStorageLocation(*FooDecl));
2592 const auto *FooVal2 = cast<RecordValue>(Env2.getValue(*FooLoc2));
2593 EXPECT_NE(FooVal2, BarVal1);
2594 EXPECT_TRUE(recordsEqual(*FooLoc2, Env2, *BarLoc1, Env1));
2596 const auto *FooBazVal2 =
2597 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env2));
2598 EXPECT_EQ(FooBazVal2, BarBazVal1);
2602 TEST(TransferTest, BindTemporary) {
2603 std::string Code = R"(
2604 struct A {
2605 virtual ~A() = default;
2607 int Baz;
2610 void target(A Foo) {
2611 int Bar = A(Foo).Baz;
2612 // [[p]]
2615 runDataflow(
2616 Code,
2617 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2618 ASTContext &ASTCtx) {
2619 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2620 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2622 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2623 ASSERT_THAT(FooDecl, NotNull());
2625 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2626 ASSERT_THAT(BarDecl, NotNull());
2628 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2629 ASSERT_THAT(BazDecl, NotNull());
2631 const auto &FooLoc =
2632 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2633 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));
2634 EXPECT_EQ(BarVal, getFieldValue(&FooLoc, *BazDecl, Env));
2638 TEST(TransferTest, StaticCast) {
2639 std::string Code = R"(
2640 void target(int Foo) {
2641 int Bar = static_cast<int>(Foo);
2642 // [[p]]
2645 runDataflow(
2646 Code,
2647 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2648 ASTContext &ASTCtx) {
2649 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2650 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2652 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2653 ASSERT_THAT(FooDecl, NotNull());
2655 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2656 ASSERT_THAT(BarDecl, NotNull());
2658 const auto *FooVal = Env.getValue(*FooDecl);
2659 const auto *BarVal = Env.getValue(*BarDecl);
2660 EXPECT_TRUE(isa<IntegerValue>(FooVal));
2661 EXPECT_TRUE(isa<IntegerValue>(BarVal));
2662 EXPECT_EQ(FooVal, BarVal);
2666 TEST(TransferTest, IntegralCast) {
2667 std::string Code = R"(
2668 void target(int Foo) {
2669 long Bar = Foo;
2670 // [[p]]
2673 runDataflow(
2674 Code,
2675 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2676 ASTContext &ASTCtx) {
2677 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2678 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2680 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2681 ASSERT_THAT(FooDecl, NotNull());
2683 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2684 ASSERT_THAT(BarDecl, NotNull());
2686 const auto *FooVal = Env.getValue(*FooDecl);
2687 const auto *BarVal = Env.getValue(*BarDecl);
2688 EXPECT_TRUE(isa<IntegerValue>(FooVal));
2689 EXPECT_TRUE(isa<IntegerValue>(BarVal));
2690 EXPECT_EQ(FooVal, BarVal);
2694 TEST(TransferTest, IntegraltoBooleanCast) {
2695 std::string Code = R"(
2696 void target(int Foo) {
2697 bool Bar = Foo;
2698 // [[p]]
2701 runDataflow(
2702 Code,
2703 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2704 ASTContext &ASTCtx) {
2705 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2706 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2708 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2709 ASSERT_THAT(FooDecl, NotNull());
2711 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2712 ASSERT_THAT(BarDecl, NotNull());
2714 const auto *FooVal = Env.getValue(*FooDecl);
2715 const auto *BarVal = Env.getValue(*BarDecl);
2716 EXPECT_TRUE(isa<IntegerValue>(FooVal));
2717 EXPECT_TRUE(isa<BoolValue>(BarVal));
2721 TEST(TransferTest, IntegralToBooleanCastFromBool) {
2722 std::string Code = R"(
2723 void target(bool Foo) {
2724 int Zab = Foo;
2725 bool Bar = Zab;
2726 // [[p]]
2729 runDataflow(
2730 Code,
2731 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2732 ASTContext &ASTCtx) {
2733 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2734 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2736 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2737 ASSERT_THAT(FooDecl, NotNull());
2739 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2740 ASSERT_THAT(BarDecl, NotNull());
2742 const auto *FooVal = Env.getValue(*FooDecl);
2743 const auto *BarVal = Env.getValue(*BarDecl);
2744 EXPECT_TRUE(isa<BoolValue>(FooVal));
2745 EXPECT_TRUE(isa<BoolValue>(BarVal));
2746 EXPECT_EQ(FooVal, BarVal);
2750 TEST(TransferTest, NullToPointerCast) {
2751 std::string Code = R"(
2752 using my_nullptr_t = decltype(nullptr);
2753 struct Baz {};
2754 void target() {
2755 int *FooX = nullptr;
2756 int *FooY = nullptr;
2757 bool **Bar = nullptr;
2758 Baz *Baz = nullptr;
2759 my_nullptr_t Null = 0;
2760 // [[p]]
2763 runDataflow(
2764 Code,
2765 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2766 ASTContext &ASTCtx) {
2767 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2768 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2770 const ValueDecl *FooXDecl = findValueDecl(ASTCtx, "FooX");
2771 ASSERT_THAT(FooXDecl, NotNull());
2773 const ValueDecl *FooYDecl = findValueDecl(ASTCtx, "FooY");
2774 ASSERT_THAT(FooYDecl, NotNull());
2776 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2777 ASSERT_THAT(BarDecl, NotNull());
2779 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2780 ASSERT_THAT(BazDecl, NotNull());
2782 const ValueDecl *NullDecl = findValueDecl(ASTCtx, "Null");
2783 ASSERT_THAT(NullDecl, NotNull());
2785 const auto *FooXVal = cast<PointerValue>(Env.getValue(*FooXDecl));
2786 const auto *FooYVal = cast<PointerValue>(Env.getValue(*FooYDecl));
2787 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl));
2788 const auto *BazVal = cast<PointerValue>(Env.getValue(*BazDecl));
2789 const auto *NullVal = cast<PointerValue>(Env.getValue(*NullDecl));
2791 EXPECT_EQ(FooXVal, FooYVal);
2792 EXPECT_NE(FooXVal, BarVal);
2793 EXPECT_NE(FooXVal, BazVal);
2794 EXPECT_NE(BarVal, BazVal);
2796 const StorageLocation &FooPointeeLoc = FooXVal->getPointeeLoc();
2797 EXPECT_TRUE(isa<ScalarStorageLocation>(FooPointeeLoc));
2798 EXPECT_THAT(Env.getValue(FooPointeeLoc), IsNull());
2800 const StorageLocation &BarPointeeLoc = BarVal->getPointeeLoc();
2801 EXPECT_TRUE(isa<ScalarStorageLocation>(BarPointeeLoc));
2802 EXPECT_THAT(Env.getValue(BarPointeeLoc), IsNull());
2804 const StorageLocation &BazPointeeLoc = BazVal->getPointeeLoc();
2805 EXPECT_TRUE(isa<RecordStorageLocation>(BazPointeeLoc));
2806 EXPECT_THAT(Env.getValue(BazPointeeLoc), IsNull());
2808 const StorageLocation &NullPointeeLoc = NullVal->getPointeeLoc();
2809 EXPECT_TRUE(isa<ScalarStorageLocation>(NullPointeeLoc));
2810 EXPECT_THAT(Env.getValue(NullPointeeLoc), IsNull());
2814 TEST(TransferTest, PointerToMemberVariable) {
2815 std::string Code = R"(
2816 struct S {
2817 int i;
2819 void target() {
2820 int S::*MemberPointer = &S::i;
2821 // [[p]]
2824 runDataflow(
2825 Code,
2826 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2827 ASTContext &ASTCtx) {
2828 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2830 const ValueDecl *MemberPointerDecl =
2831 findValueDecl(ASTCtx, "MemberPointer");
2832 ASSERT_THAT(MemberPointerDecl, NotNull());
2833 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull());
2837 TEST(TransferTest, PointerToMemberFunction) {
2838 std::string Code = R"(
2839 struct S {
2840 void Method();
2842 void target() {
2843 void (S::*MemberPointer)() = &S::Method;
2844 // [[p]]
2847 runDataflow(
2848 Code,
2849 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2850 ASTContext &ASTCtx) {
2851 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2853 const ValueDecl *MemberPointerDecl =
2854 findValueDecl(ASTCtx, "MemberPointer");
2855 ASSERT_THAT(MemberPointerDecl, NotNull());
2856 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull());
2860 TEST(TransferTest, NullToMemberPointerCast) {
2861 std::string Code = R"(
2862 struct Foo {};
2863 void target() {
2864 int Foo::*MemberPointer = nullptr;
2865 // [[p]]
2868 runDataflow(
2869 Code,
2870 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2871 ASTContext &ASTCtx) {
2872 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2873 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2875 const ValueDecl *MemberPointerDecl =
2876 findValueDecl(ASTCtx, "MemberPointer");
2877 ASSERT_THAT(MemberPointerDecl, NotNull());
2878 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull());
2882 TEST(TransferTest, AddrOfValue) {
2883 std::string Code = R"(
2884 void target() {
2885 int Foo;
2886 int *Bar = &Foo;
2887 // [[p]]
2890 runDataflow(
2891 Code,
2892 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2893 ASTContext &ASTCtx) {
2894 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2895 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2897 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2898 ASSERT_THAT(FooDecl, NotNull());
2900 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2901 ASSERT_THAT(BarDecl, NotNull());
2903 const auto *FooLoc =
2904 cast<ScalarStorageLocation>(Env.getStorageLocation(*FooDecl));
2905 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl));
2906 EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc);
2910 TEST(TransferTest, AddrOfReference) {
2911 std::string Code = R"(
2912 void target(int *Foo) {
2913 int *Bar = &(*Foo);
2914 // [[p]]
2917 runDataflow(
2918 Code,
2919 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2920 ASTContext &ASTCtx) {
2921 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2922 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2924 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2925 ASSERT_THAT(FooDecl, NotNull());
2927 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2928 ASSERT_THAT(BarDecl, NotNull());
2930 const auto *FooVal = cast<PointerValue>(Env.getValue(*FooDecl));
2931 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl));
2932 EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc());
2936 TEST(TransferTest, CannotAnalyzeFunctionTemplate) {
2937 std::string Code = R"(
2938 template <typename T>
2939 void target() {}
2941 ASSERT_THAT_ERROR(
2942 checkDataflowWithNoopAnalysis(Code),
2943 llvm::FailedWithMessage("Cannot analyze templated declarations"));
2946 TEST(TransferTest, CannotAnalyzeMethodOfClassTemplate) {
2947 std::string Code = R"(
2948 template <typename T>
2949 struct A {
2950 void target() {}
2953 ASSERT_THAT_ERROR(
2954 checkDataflowWithNoopAnalysis(Code),
2955 llvm::FailedWithMessage("Cannot analyze templated declarations"));
2958 TEST(TransferTest, VarDeclInitAssignConditionalOperator) {
2959 std::string Code = R"(
2960 struct A {};
2962 void target(A Foo, A Bar, bool Cond) {
2963 A Baz = Cond ? Foo : Bar;
2964 /*[[p]]*/
2967 runDataflow(
2968 Code,
2969 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2970 ASTContext &ASTCtx) {
2971 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2972 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2974 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2975 ASSERT_THAT(FooDecl, NotNull());
2977 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2978 ASSERT_THAT(BarDecl, NotNull());
2980 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2981 ASSERT_THAT(BazDecl, NotNull());
2983 const auto *FooVal = cast<RecordValue>(Env.getValue(*FooDecl));
2984 const auto *BarVal = cast<RecordValue>(Env.getValue(*BarDecl));
2986 const auto *BazVal = dyn_cast<RecordValue>(Env.getValue(*BazDecl));
2987 ASSERT_THAT(BazVal, NotNull());
2989 EXPECT_NE(BazVal, FooVal);
2990 EXPECT_NE(BazVal, BarVal);
2994 TEST(TransferTest, VarDeclInDoWhile) {
2995 std::string Code = R"(
2996 void target(int *Foo) {
2997 do {
2998 int Bar = *Foo;
2999 // [[in_loop]]
3000 } while (false);
3001 (void)0;
3002 // [[after_loop]]
3005 runDataflow(
3006 Code,
3007 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3008 ASTContext &ASTCtx) {
3009 const Environment &EnvInLoop =
3010 getEnvironmentAtAnnotation(Results, "in_loop");
3011 const Environment &EnvAfterLoop =
3012 getEnvironmentAtAnnotation(Results, "after_loop");
3014 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3015 ASSERT_THAT(FooDecl, NotNull());
3017 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3018 ASSERT_THAT(BarDecl, NotNull());
3020 const auto *FooVal =
3021 cast<PointerValue>(EnvAfterLoop.getValue(*FooDecl));
3022 const auto *FooPointeeVal =
3023 cast<IntegerValue>(EnvAfterLoop.getValue(FooVal->getPointeeLoc()));
3025 const auto *BarVal = cast<IntegerValue>(EnvInLoop.getValue(*BarDecl));
3026 EXPECT_EQ(BarVal, FooPointeeVal);
3028 ASSERT_THAT(EnvAfterLoop.getValue(*BarDecl), IsNull());
3032 TEST(TransferTest, UnreachableAfterWhileTrue) {
3033 std::string Code = R"(
3034 void target() {
3035 while (true) {}
3036 (void)0;
3037 /*[[p]]*/
3040 runDataflow(
3041 Code,
3042 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3043 ASTContext &ASTCtx) {
3044 // The node after the while-true is pruned because it is trivially
3045 // known to be unreachable.
3046 ASSERT_TRUE(Results.empty());
3050 TEST(TransferTest, AggregateInitialization) {
3051 std::string BracesCode = R"(
3052 struct A {
3053 int Foo;
3056 struct B {
3057 int Bar;
3058 A Baz;
3059 int Qux;
3062 void target(int BarArg, int FooArg, int QuxArg) {
3063 B Quux{BarArg, {FooArg}, QuxArg};
3064 B OtherB;
3065 /*[[p]]*/
3068 std::string BraceElisionCode = R"(
3069 struct A {
3070 int Foo;
3073 struct B {
3074 int Bar;
3075 A Baz;
3076 int Qux;
3079 void target(int BarArg, int FooArg, int QuxArg) {
3080 B Quux = {BarArg, FooArg, QuxArg};
3081 B OtherB;
3082 /*[[p]]*/
3085 for (const std::string &Code : {BracesCode, BraceElisionCode}) {
3086 runDataflow(
3087 Code,
3088 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3089 ASTContext &ASTCtx) {
3090 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3091 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3093 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3094 ASSERT_THAT(FooDecl, NotNull());
3096 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3097 ASSERT_THAT(BarDecl, NotNull());
3099 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3100 ASSERT_THAT(BazDecl, NotNull());
3102 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
3103 ASSERT_THAT(QuxDecl, NotNull());
3105 const ValueDecl *FooArgDecl = findValueDecl(ASTCtx, "FooArg");
3106 ASSERT_THAT(FooArgDecl, NotNull());
3108 const ValueDecl *BarArgDecl = findValueDecl(ASTCtx, "BarArg");
3109 ASSERT_THAT(BarArgDecl, NotNull());
3111 const ValueDecl *QuxArgDecl = findValueDecl(ASTCtx, "QuxArg");
3112 ASSERT_THAT(QuxArgDecl, NotNull());
3114 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
3115 ASSERT_THAT(QuuxDecl, NotNull());
3117 const auto *FooArgVal = cast<IntegerValue>(Env.getValue(*FooArgDecl));
3118 const auto *BarArgVal = cast<IntegerValue>(Env.getValue(*BarArgDecl));
3119 const auto *QuxArgVal = cast<IntegerValue>(Env.getValue(*QuxArgDecl));
3121 const auto &QuuxLoc =
3122 *cast<RecordStorageLocation>(Env.getStorageLocation(*QuuxDecl));
3123 const auto &BazLoc =
3124 *cast<RecordStorageLocation>(QuuxLoc.getChild(*BazDecl));
3126 EXPECT_EQ(getFieldValue(&QuuxLoc, *BarDecl, Env), BarArgVal);
3127 EXPECT_EQ(getFieldValue(&BazLoc, *FooDecl, Env), FooArgVal);
3128 EXPECT_EQ(getFieldValue(&QuuxLoc, *QuxDecl, Env), QuxArgVal);
3130 // Check that fields initialized in an initializer list are always
3131 // modeled in other instances of the same type.
3132 const auto &OtherBLoc =
3133 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "OtherB");
3134 EXPECT_THAT(OtherBLoc.getChild(*BarDecl), NotNull());
3135 EXPECT_THAT(OtherBLoc.getChild(*BazDecl), NotNull());
3136 EXPECT_THAT(OtherBLoc.getChild(*QuxDecl), NotNull());
3141 TEST(TransferTest, AggregateInitializationReferenceField) {
3142 std::string Code = R"(
3143 struct S {
3144 int &RefField;
3147 void target(int i) {
3148 S s = { i };
3149 /*[[p]]*/
3152 runDataflow(
3153 Code,
3154 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3155 ASTContext &ASTCtx) {
3156 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3158 const ValueDecl *RefFieldDecl = findValueDecl(ASTCtx, "RefField");
3160 auto &ILoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "i");
3161 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s");
3163 EXPECT_EQ(SLoc.getChild(*RefFieldDecl), &ILoc);
3167 TEST(TransferTest, AggregateInitialization_NotExplicitlyInitializedField) {
3168 std::string Code = R"(
3169 struct S {
3170 int i1;
3171 int i2;
3174 void target(int i) {
3175 S s = { i };
3176 /*[[p]]*/
3179 runDataflow(
3180 Code,
3181 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3182 ASTContext &ASTCtx) {
3183 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3185 const ValueDecl *I1FieldDecl = findValueDecl(ASTCtx, "i1");
3186 const ValueDecl *I2FieldDecl = findValueDecl(ASTCtx, "i2");
3188 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s");
3190 auto &IValue = getValueForDecl<IntegerValue>(ASTCtx, Env, "i");
3191 auto &I1Value =
3192 *cast<IntegerValue>(getFieldValue(&SLoc, *I1FieldDecl, Env));
3193 EXPECT_EQ(&I1Value, &IValue);
3194 auto &I2Value =
3195 *cast<IntegerValue>(getFieldValue(&SLoc, *I2FieldDecl, Env));
3196 EXPECT_NE(&I2Value, &IValue);
3200 TEST(TransferTest, AggregateInitializationFunctionPointer) {
3201 // This is a repro for an assertion failure.
3202 // nullptr takes on the type of a const function pointer, but its type was
3203 // asserted to be equal to the *unqualified* type of Field, which no longer
3204 // included the const.
3205 std::string Code = R"(
3206 struct S {
3207 void (*const Field)();
3210 void target() {
3211 S s{nullptr};
3214 runDataflow(
3215 Code,
3216 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3217 ASTContext &ASTCtx) {});
3220 TEST(TransferTest, AssignToUnionMember) {
3221 std::string Code = R"(
3222 union A {
3223 int Foo;
3226 void target(int Bar) {
3227 A Baz;
3228 Baz.Foo = Bar;
3229 // [[p]]
3232 runDataflow(
3233 Code,
3234 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3235 ASTContext &ASTCtx) {
3236 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3237 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3239 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3240 ASSERT_THAT(BazDecl, NotNull());
3241 ASSERT_TRUE(BazDecl->getType()->isUnionType());
3243 auto BazFields = BazDecl->getType()->getAsRecordDecl()->fields();
3244 FieldDecl *FooDecl = nullptr;
3245 for (FieldDecl *Field : BazFields) {
3246 if (Field->getNameAsString() == "Foo") {
3247 FooDecl = Field;
3248 } else {
3249 FAIL() << "Unexpected field: " << Field->getNameAsString();
3252 ASSERT_THAT(FooDecl, NotNull());
3254 const auto *BazLoc = dyn_cast_or_null<RecordStorageLocation>(
3255 Env.getStorageLocation(*BazDecl));
3256 ASSERT_THAT(BazLoc, NotNull());
3257 ASSERT_THAT(Env.getValue(*BazLoc), NotNull());
3259 const auto *FooVal =
3260 cast<IntegerValue>(getFieldValue(BazLoc, *FooDecl, Env));
3262 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3263 ASSERT_THAT(BarDecl, NotNull());
3264 const auto *BarLoc = Env.getStorageLocation(*BarDecl);
3265 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
3267 EXPECT_EQ(Env.getValue(*BarLoc), FooVal);
3271 TEST(TransferTest, AssignFromBoolLiteral) {
3272 std::string Code = R"(
3273 void target() {
3274 bool Foo = true;
3275 bool Bar = false;
3276 // [[p]]
3279 runDataflow(
3280 Code,
3281 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3282 ASTContext &ASTCtx) {
3283 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3284 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3286 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3287 ASSERT_THAT(FooDecl, NotNull());
3289 const auto *FooVal =
3290 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));
3291 ASSERT_THAT(FooVal, NotNull());
3293 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3294 ASSERT_THAT(BarDecl, NotNull());
3296 const auto *BarVal =
3297 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl));
3298 ASSERT_THAT(BarVal, NotNull());
3300 EXPECT_EQ(FooVal, &Env.getBoolLiteralValue(true));
3301 EXPECT_EQ(BarVal, &Env.getBoolLiteralValue(false));
3305 TEST(TransferTest, AssignFromCompositeBoolExpression) {
3307 std::string Code = R"(
3308 void target(bool Foo, bool Bar, bool Qux) {
3309 bool Baz = (Foo) && (Bar || Qux);
3310 // [[p]]
3313 runDataflow(
3314 Code,
3315 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3316 ASTContext &ASTCtx) {
3317 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3318 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3320 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3321 ASSERT_THAT(FooDecl, NotNull());
3323 const auto *FooVal =
3324 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));
3325 ASSERT_THAT(FooVal, NotNull());
3327 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3328 ASSERT_THAT(BarDecl, NotNull());
3330 const auto *BarVal =
3331 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl));
3332 ASSERT_THAT(BarVal, NotNull());
3334 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
3335 ASSERT_THAT(QuxDecl, NotNull());
3337 const auto *QuxVal =
3338 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl));
3339 ASSERT_THAT(QuxVal, NotNull());
3341 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3342 ASSERT_THAT(BazDecl, NotNull());
3344 const auto *BazVal =
3345 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl));
3346 ASSERT_THAT(BazVal, NotNull());
3347 auto &A = Env.arena();
3348 EXPECT_EQ(&BazVal->formula(),
3349 &A.makeAnd(FooVal->formula(),
3350 A.makeOr(BarVal->formula(), QuxVal->formula())));
3355 std::string Code = R"(
3356 void target(bool Foo, bool Bar, bool Qux) {
3357 bool Baz = (Foo && Qux) || (Bar);
3358 // [[p]]
3361 runDataflow(
3362 Code,
3363 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3364 ASTContext &ASTCtx) {
3365 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3366 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3368 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3369 ASSERT_THAT(FooDecl, NotNull());
3371 const auto *FooVal =
3372 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));
3373 ASSERT_THAT(FooVal, NotNull());
3375 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3376 ASSERT_THAT(BarDecl, NotNull());
3378 const auto *BarVal =
3379 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl));
3380 ASSERT_THAT(BarVal, NotNull());
3382 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
3383 ASSERT_THAT(QuxDecl, NotNull());
3385 const auto *QuxVal =
3386 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl));
3387 ASSERT_THAT(QuxVal, NotNull());
3389 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3390 ASSERT_THAT(BazDecl, NotNull());
3392 const auto *BazVal =
3393 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl));
3394 ASSERT_THAT(BazVal, NotNull());
3395 auto &A = Env.arena();
3396 EXPECT_EQ(&BazVal->formula(),
3397 &A.makeOr(A.makeAnd(FooVal->formula(), QuxVal->formula()),
3398 BarVal->formula()));
3403 std::string Code = R"(
3404 void target(bool A, bool B, bool C, bool D) {
3405 bool Foo = ((A && B) && C) && D;
3406 // [[p]]
3409 runDataflow(
3410 Code,
3411 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3412 ASTContext &ASTCtx) {
3413 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3414 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3416 const ValueDecl *ADecl = findValueDecl(ASTCtx, "A");
3417 ASSERT_THAT(ADecl, NotNull());
3419 const auto *AVal = dyn_cast_or_null<BoolValue>(Env.getValue(*ADecl));
3420 ASSERT_THAT(AVal, NotNull());
3422 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B");
3423 ASSERT_THAT(BDecl, NotNull());
3425 const auto *BVal = dyn_cast_or_null<BoolValue>(Env.getValue(*BDecl));
3426 ASSERT_THAT(BVal, NotNull());
3428 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C");
3429 ASSERT_THAT(CDecl, NotNull());
3431 const auto *CVal = dyn_cast_or_null<BoolValue>(Env.getValue(*CDecl));
3432 ASSERT_THAT(CVal, NotNull());
3434 const ValueDecl *DDecl = findValueDecl(ASTCtx, "D");
3435 ASSERT_THAT(DDecl, NotNull());
3437 const auto *DVal = dyn_cast_or_null<BoolValue>(Env.getValue(*DDecl));
3438 ASSERT_THAT(DVal, NotNull());
3440 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3441 ASSERT_THAT(FooDecl, NotNull());
3443 const auto *FooVal =
3444 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));
3445 ASSERT_THAT(FooVal, NotNull());
3446 auto &A = Env.arena();
3447 EXPECT_EQ(
3448 &FooVal->formula(),
3449 &A.makeAnd(A.makeAnd(A.makeAnd(AVal->formula(), BVal->formula()),
3450 CVal->formula()),
3451 DVal->formula()));
3456 TEST(TransferTest, AssignFromBoolNegation) {
3457 std::string Code = R"(
3458 void target() {
3459 bool Foo = true;
3460 bool Bar = !(Foo);
3461 // [[p]]
3464 runDataflow(
3465 Code,
3466 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3467 ASTContext &ASTCtx) {
3468 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3469 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3471 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3472 ASSERT_THAT(FooDecl, NotNull());
3474 const auto *FooVal =
3475 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));
3476 ASSERT_THAT(FooVal, NotNull());
3478 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3479 ASSERT_THAT(BarDecl, NotNull());
3481 const auto *BarVal =
3482 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl));
3483 ASSERT_THAT(BarVal, NotNull());
3484 auto &A = Env.arena();
3485 EXPECT_EQ(&BarVal->formula(), &A.makeNot(FooVal->formula()));
3489 TEST(TransferTest, BuiltinExpect) {
3490 std::string Code = R"(
3491 void target(long Foo) {
3492 long Bar = __builtin_expect(Foo, true);
3493 /*[[p]]*/
3496 runDataflow(
3497 Code,
3498 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3499 ASTContext &ASTCtx) {
3500 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3501 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3503 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3504 ASSERT_THAT(FooDecl, NotNull());
3506 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3507 ASSERT_THAT(BarDecl, NotNull());
3509 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
3513 // `__builtin_expect` takes and returns a `long` argument, so other types
3514 // involve casts. This verifies that we identify the input and output in that
3515 // case.
3516 TEST(TransferTest, BuiltinExpectBoolArg) {
3517 std::string Code = R"(
3518 void target(bool Foo) {
3519 bool Bar = __builtin_expect(Foo, true);
3520 /*[[p]]*/
3523 runDataflow(
3524 Code,
3525 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3526 ASTContext &ASTCtx) {
3527 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3528 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3530 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3531 ASSERT_THAT(FooDecl, NotNull());
3533 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3534 ASSERT_THAT(BarDecl, NotNull());
3536 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
3540 TEST(TransferTest, BuiltinUnreachable) {
3541 std::string Code = R"(
3542 void target(bool Foo) {
3543 bool Bar = false;
3544 if (Foo)
3545 Bar = Foo;
3546 else
3547 __builtin_unreachable();
3548 (void)0;
3549 /*[[p]]*/
3552 runDataflow(
3553 Code,
3554 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3555 ASTContext &ASTCtx) {
3556 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3557 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3559 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3560 ASSERT_THAT(FooDecl, NotNull());
3562 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3563 ASSERT_THAT(BarDecl, NotNull());
3565 // `__builtin_unreachable` promises that the code is
3566 // unreachable, so the compiler treats the "then" branch as the
3567 // only possible predecessor of this statement.
3568 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
3572 TEST(TransferTest, BuiltinTrap) {
3573 std::string Code = R"(
3574 void target(bool Foo) {
3575 bool Bar = false;
3576 if (Foo)
3577 Bar = Foo;
3578 else
3579 __builtin_trap();
3580 (void)0;
3581 /*[[p]]*/
3584 runDataflow(
3585 Code,
3586 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3587 ASTContext &ASTCtx) {
3588 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3589 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3591 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3592 ASSERT_THAT(FooDecl, NotNull());
3594 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3595 ASSERT_THAT(BarDecl, NotNull());
3597 // `__builtin_trap` ensures program termination, so only the
3598 // "then" branch is a predecessor of this statement.
3599 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
3603 TEST(TransferTest, BuiltinDebugTrap) {
3604 std::string Code = R"(
3605 void target(bool Foo) {
3606 bool Bar = false;
3607 if (Foo)
3608 Bar = Foo;
3609 else
3610 __builtin_debugtrap();
3611 (void)0;
3612 /*[[p]]*/
3615 runDataflow(
3616 Code,
3617 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3618 ASTContext &ASTCtx) {
3619 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3620 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3622 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3623 ASSERT_THAT(FooDecl, NotNull());
3625 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3626 ASSERT_THAT(BarDecl, NotNull());
3628 // `__builtin_debugtrap` doesn't ensure program termination.
3629 EXPECT_NE(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
3633 TEST(TransferTest, StaticIntSingleVarDecl) {
3634 std::string Code = R"(
3635 void target() {
3636 static int Foo;
3637 // [[p]]
3640 runDataflow(
3641 Code,
3642 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3643 ASTContext &ASTCtx) {
3644 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3645 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3647 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3648 ASSERT_THAT(FooDecl, NotNull());
3650 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
3651 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
3653 const Value *FooVal = Env.getValue(*FooLoc);
3654 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
3658 TEST(TransferTest, StaticIntGroupVarDecl) {
3659 std::string Code = R"(
3660 void target() {
3661 static int Foo, Bar;
3662 (void)0;
3663 // [[p]]
3666 runDataflow(
3667 Code,
3668 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3669 ASTContext &ASTCtx) {
3670 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3671 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3673 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3674 ASSERT_THAT(FooDecl, NotNull());
3676 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3677 ASSERT_THAT(BarDecl, NotNull());
3679 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
3680 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
3682 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
3683 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
3685 const Value *FooVal = Env.getValue(*FooLoc);
3686 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
3688 const Value *BarVal = Env.getValue(*BarLoc);
3689 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
3691 EXPECT_NE(FooVal, BarVal);
3695 TEST(TransferTest, GlobalIntVarDecl) {
3696 std::string Code = R"(
3697 static int Foo;
3699 void target() {
3700 int Bar = Foo;
3701 int Baz = Foo;
3702 // [[p]]
3705 runDataflow(
3706 Code,
3707 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3708 ASTContext &ASTCtx) {
3709 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3710 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3712 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3713 ASSERT_THAT(BarDecl, NotNull());
3715 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3716 ASSERT_THAT(BazDecl, NotNull());
3718 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));
3719 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl));
3720 EXPECT_EQ(BarVal, BazVal);
3724 TEST(TransferTest, StaticMemberIntVarDecl) {
3725 std::string Code = R"(
3726 struct A {
3727 static int Foo;
3730 void target(A a) {
3731 int Bar = a.Foo;
3732 int Baz = a.Foo;
3733 // [[p]]
3736 runDataflow(
3737 Code,
3738 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3739 ASTContext &ASTCtx) {
3740 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3741 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3743 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3744 ASSERT_THAT(BarDecl, NotNull());
3746 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3747 ASSERT_THAT(BazDecl, NotNull());
3749 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));
3750 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl));
3751 EXPECT_EQ(BarVal, BazVal);
3755 TEST(TransferTest, StaticMemberRefVarDecl) {
3756 std::string Code = R"(
3757 struct A {
3758 static int &Foo;
3761 void target(A a) {
3762 int Bar = a.Foo;
3763 int Baz = a.Foo;
3764 // [[p]]
3767 runDataflow(
3768 Code,
3769 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3770 ASTContext &ASTCtx) {
3771 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3772 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3774 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3775 ASSERT_THAT(BarDecl, NotNull());
3777 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3778 ASSERT_THAT(BazDecl, NotNull());
3780 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));
3781 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl));
3782 EXPECT_EQ(BarVal, BazVal);
3786 TEST(TransferTest, AssignMemberBeforeCopy) {
3787 std::string Code = R"(
3788 struct A {
3789 int Foo;
3792 void target() {
3793 A A1;
3794 A A2;
3795 int Bar;
3796 A1.Foo = Bar;
3797 A2 = A1;
3798 // [[p]]
3801 runDataflow(
3802 Code,
3803 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3804 ASTContext &ASTCtx) {
3805 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3806 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3808 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3809 ASSERT_THAT(FooDecl, NotNull());
3811 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3812 ASSERT_THAT(BarDecl, NotNull());
3814 const ValueDecl *A1Decl = findValueDecl(ASTCtx, "A1");
3815 ASSERT_THAT(A1Decl, NotNull());
3817 const ValueDecl *A2Decl = findValueDecl(ASTCtx, "A2");
3818 ASSERT_THAT(A2Decl, NotNull());
3820 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));
3822 const auto &A2Loc =
3823 *cast<RecordStorageLocation>(Env.getStorageLocation(*A2Decl));
3824 EXPECT_EQ(getFieldValue(&A2Loc, *FooDecl, Env), BarVal);
3828 TEST(TransferTest, BooleanEquality) {
3829 std::string Code = R"(
3830 void target(bool Bar) {
3831 bool Foo = true;
3832 if (Bar == Foo) {
3833 (void)0;
3834 /*[[p-then]]*/
3835 } else {
3836 (void)0;
3837 /*[[p-else]]*/
3841 runDataflow(
3842 Code,
3843 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3844 ASTContext &ASTCtx) {
3845 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else"));
3846 const Environment &EnvThen =
3847 getEnvironmentAtAnnotation(Results, "p-then");
3848 const Environment &EnvElse =
3849 getEnvironmentAtAnnotation(Results, "p-else");
3851 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3852 ASSERT_THAT(BarDecl, NotNull());
3854 auto &BarValThen = getFormula(*BarDecl, EnvThen);
3855 EXPECT_TRUE(EnvThen.proves(BarValThen));
3857 auto &BarValElse = getFormula(*BarDecl, EnvElse);
3858 EXPECT_TRUE(EnvElse.proves(EnvElse.arena().makeNot(BarValElse)));
3862 TEST(TransferTest, BooleanInequality) {
3863 std::string Code = R"(
3864 void target(bool Bar) {
3865 bool Foo = true;
3866 if (Bar != Foo) {
3867 (void)0;
3868 /*[[p-then]]*/
3869 } else {
3870 (void)0;
3871 /*[[p-else]]*/
3875 runDataflow(
3876 Code,
3877 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3878 ASTContext &ASTCtx) {
3879 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else"));
3880 const Environment &EnvThen =
3881 getEnvironmentAtAnnotation(Results, "p-then");
3882 const Environment &EnvElse =
3883 getEnvironmentAtAnnotation(Results, "p-else");
3885 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3886 ASSERT_THAT(BarDecl, NotNull());
3888 auto &BarValThen = getFormula(*BarDecl, EnvThen);
3889 EXPECT_TRUE(EnvThen.proves(EnvThen.arena().makeNot(BarValThen)));
3891 auto &BarValElse = getFormula(*BarDecl, EnvElse);
3892 EXPECT_TRUE(EnvElse.proves(BarValElse));
3896 TEST(TransferTest, IntegerLiteralEquality) {
3897 std::string Code = R"(
3898 void target() {
3899 bool equal = (42 == 42);
3900 // [[p]]
3903 runDataflow(
3904 Code,
3905 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3906 ASTContext &ASTCtx) {
3907 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3909 auto &Equal =
3910 getValueForDecl<BoolValue>(ASTCtx, Env, "equal").formula();
3911 EXPECT_TRUE(Env.proves(Equal));
3915 TEST(TransferTest, CorrelatedBranches) {
3916 std::string Code = R"(
3917 void target(bool B, bool C) {
3918 if (B) {
3919 return;
3921 (void)0;
3922 /*[[p0]]*/
3923 if (C) {
3924 B = true;
3925 /*[[p1]]*/
3927 if (B) {
3928 (void)0;
3929 /*[[p2]]*/
3933 runDataflow(
3934 Code,
3935 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3936 ASTContext &ASTCtx) {
3937 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p0", "p1", "p2"));
3939 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C");
3940 ASSERT_THAT(CDecl, NotNull());
3943 const Environment &Env = getEnvironmentAtAnnotation(Results, "p0");
3944 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B");
3945 ASSERT_THAT(BDecl, NotNull());
3946 auto &BVal = getFormula(*BDecl, Env);
3948 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BVal)));
3952 const Environment &Env = getEnvironmentAtAnnotation(Results, "p1");
3953 auto &CVal = getFormula(*CDecl, Env);
3954 EXPECT_TRUE(Env.proves(CVal));
3958 const Environment &Env = getEnvironmentAtAnnotation(Results, "p2");
3959 auto &CVal = getFormula(*CDecl, Env);
3960 EXPECT_TRUE(Env.proves(CVal));
3965 TEST(TransferTest, LoopWithAssignmentConverges) {
3966 std::string Code = R"(
3967 bool foo();
3969 void target() {
3970 do {
3971 bool Bar = foo();
3972 if (Bar) break;
3973 (void)Bar;
3974 /*[[p]]*/
3975 } while (true);
3978 // The key property that we are verifying is implicit in `runDataflow` --
3979 // namely, that the analysis succeeds, rather than hitting the maximum number
3980 // of iterations.
3981 runDataflow(
3982 Code,
3983 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3984 ASTContext &ASTCtx) {
3985 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3986 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3988 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3989 ASSERT_THAT(BarDecl, NotNull());
3991 auto &BarVal = getFormula(*BarDecl, Env);
3992 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal)));
3996 TEST(TransferTest, LoopWithStagedAssignments) {
3997 std::string Code = R"(
3998 bool foo();
4000 void target() {
4001 bool Bar = false;
4002 bool Err = false;
4003 while (foo()) {
4004 if (Bar)
4005 Err = true;
4006 Bar = true;
4007 /*[[p]]*/
4011 runDataflow(
4012 Code,
4013 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4014 ASTContext &ASTCtx) {
4015 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4016 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4018 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
4019 ASSERT_THAT(BarDecl, NotNull());
4020 const ValueDecl *ErrDecl = findValueDecl(ASTCtx, "Err");
4021 ASSERT_THAT(ErrDecl, NotNull());
4023 auto &BarVal = getFormula(*BarDecl, Env);
4024 auto &ErrVal = getFormula(*ErrDecl, Env);
4025 EXPECT_TRUE(Env.proves(BarVal));
4026 // An unsound analysis, for example only evaluating the loop once, can
4027 // conclude that `Err` is false. So, we test that this conclusion is not
4028 // reached.
4029 EXPECT_FALSE(Env.proves(Env.arena().makeNot(ErrVal)));
4033 TEST(TransferTest, LoopWithReferenceAssignmentConverges) {
4034 std::string Code = R"(
4035 bool &foo();
4037 void target() {
4038 do {
4039 bool& Bar = foo();
4040 if (Bar) break;
4041 (void)Bar;
4042 /*[[p]]*/
4043 } while (true);
4046 // The key property that we are verifying is that the analysis succeeds,
4047 // rather than hitting the maximum number of iterations.
4048 runDataflow(
4049 Code,
4050 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4051 ASTContext &ASTCtx) {
4052 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4053 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4055 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
4056 ASSERT_THAT(BarDecl, NotNull());
4058 auto &BarVal = getFormula(*BarDecl, Env);
4059 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal)));
4063 TEST(TransferTest, LoopWithStructReferenceAssignmentConverges) {
4064 std::string Code = R"(
4065 struct Lookup {
4066 int x;
4069 void target(Lookup val, bool b) {
4070 const Lookup* l = nullptr;
4071 while (b) {
4072 l = &val;
4073 /*[[p-inner]]*/
4075 (void)0;
4076 /*[[p-outer]]*/
4079 // The key property that we are verifying is implicit in `runDataflow` --
4080 // namely, that the analysis succeeds, rather than hitting the maximum number
4081 // of iterations.
4082 runDataflow(
4083 Code,
4084 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4085 ASTContext &ASTCtx) {
4086 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-inner", "p-outer"));
4087 const Environment &InnerEnv =
4088 getEnvironmentAtAnnotation(Results, "p-inner");
4089 const Environment &OuterEnv =
4090 getEnvironmentAtAnnotation(Results, "p-outer");
4092 const ValueDecl *ValDecl = findValueDecl(ASTCtx, "val");
4093 ASSERT_THAT(ValDecl, NotNull());
4095 const ValueDecl *LDecl = findValueDecl(ASTCtx, "l");
4096 ASSERT_THAT(LDecl, NotNull());
4098 // Inner.
4099 auto *LVal = dyn_cast<PointerValue>(InnerEnv.getValue(*LDecl));
4100 ASSERT_THAT(LVal, NotNull());
4102 EXPECT_EQ(&LVal->getPointeeLoc(),
4103 InnerEnv.getStorageLocation(*ValDecl));
4105 // Outer.
4106 LVal = dyn_cast<PointerValue>(OuterEnv.getValue(*LDecl));
4107 ASSERT_THAT(LVal, NotNull());
4109 // The loop body may not have been executed, so we should not conclude
4110 // that `l` points to `val`.
4111 EXPECT_NE(&LVal->getPointeeLoc(),
4112 OuterEnv.getStorageLocation(*ValDecl));
4116 TEST(TransferTest, LoopDereferencingChangingPointerConverges) {
4117 std::string Code = R"cc(
4118 bool some_condition();
4120 void target(int i1, int i2) {
4121 int *p = &i1;
4122 while (true) {
4123 (void)*p;
4124 if (some_condition())
4125 p = &i1;
4126 else
4127 p = &i2;
4130 )cc";
4131 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded());
4134 TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) {
4135 std::string Code = R"cc(
4136 struct Lookup {
4137 int x;
4140 bool some_condition();
4142 void target(Lookup l1, Lookup l2) {
4143 Lookup *l = &l1;
4144 while (true) {
4145 (void)l->x;
4146 if (some_condition())
4147 l = &l1;
4148 else
4149 l = &l2;
4152 )cc";
4153 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded());
4156 TEST(TransferTest, LoopWithShortCircuitedConditionConverges) {
4157 std::string Code = R"cc(
4158 bool foo();
4160 void target() {
4161 bool c = false;
4162 while (foo() || foo()) {
4163 c = true;
4166 )cc";
4167 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded());
4170 TEST(TransferTest, DoesNotCrashOnUnionThisExpr) {
4171 std::string Code = R"(
4172 union Union {
4173 int A;
4174 float B;
4177 void foo() {
4178 Union A;
4179 Union B;
4180 A = B;
4183 // This is a crash regression test when calling the transfer function on a
4184 // `CXXThisExpr` that refers to a union.
4185 runDataflow(
4186 Code,
4187 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
4188 ASTContext &) {},
4189 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator=");
4192 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToRefs) {
4193 std::string Code = R"(
4194 struct A {
4195 int Foo;
4196 int Bar;
4199 void target() {
4200 int Qux;
4201 A Baz;
4202 Baz.Foo = Qux;
4203 auto &FooRef = Baz.Foo;
4204 auto &BarRef = Baz.Bar;
4205 auto &[BoundFooRef, BoundBarRef] = Baz;
4206 // [[p]]
4209 runDataflow(
4210 Code,
4211 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4212 ASTContext &ASTCtx) {
4213 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4214 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4216 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef");
4217 ASSERT_THAT(FooRefDecl, NotNull());
4219 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef");
4220 ASSERT_THAT(BarRefDecl, NotNull());
4222 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
4223 ASSERT_THAT(QuxDecl, NotNull());
4225 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef");
4226 ASSERT_THAT(BoundFooRefDecl, NotNull());
4228 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef");
4229 ASSERT_THAT(BoundBarRefDecl, NotNull());
4231 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl);
4232 ASSERT_THAT(FooRefLoc, NotNull());
4234 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl);
4235 ASSERT_THAT(BarRefLoc, NotNull());
4237 const Value *QuxVal = Env.getValue(*QuxDecl);
4238 ASSERT_THAT(QuxVal, NotNull());
4240 const StorageLocation *BoundFooRefLoc =
4241 Env.getStorageLocation(*BoundFooRefDecl);
4242 EXPECT_EQ(BoundFooRefLoc, FooRefLoc);
4244 const StorageLocation *BoundBarRefLoc =
4245 Env.getStorageLocation(*BoundBarRefDecl);
4246 EXPECT_EQ(BoundBarRefLoc, BarRefLoc);
4248 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal);
4252 TEST(TransferTest, StructuredBindingAssignFromStructRefMembersToRefs) {
4253 std::string Code = R"(
4254 struct A {
4255 int &Foo;
4256 int &Bar;
4259 void target(A Baz) {
4260 int Qux;
4261 Baz.Foo = Qux;
4262 auto &FooRef = Baz.Foo;
4263 auto &BarRef = Baz.Bar;
4264 auto &[BoundFooRef, BoundBarRef] = Baz;
4265 // [[p]]
4268 runDataflow(
4269 Code,
4270 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4271 ASTContext &ASTCtx) {
4272 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4273 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4275 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef");
4276 ASSERT_THAT(FooRefDecl, NotNull());
4278 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef");
4279 ASSERT_THAT(BarRefDecl, NotNull());
4281 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
4282 ASSERT_THAT(QuxDecl, NotNull());
4284 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef");
4285 ASSERT_THAT(BoundFooRefDecl, NotNull());
4287 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef");
4288 ASSERT_THAT(BoundBarRefDecl, NotNull());
4290 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl);
4291 ASSERT_THAT(FooRefLoc, NotNull());
4293 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl);
4294 ASSERT_THAT(BarRefLoc, NotNull());
4296 const Value *QuxVal = Env.getValue(*QuxDecl);
4297 ASSERT_THAT(QuxVal, NotNull());
4299 const StorageLocation *BoundFooRefLoc =
4300 Env.getStorageLocation(*BoundFooRefDecl);
4301 EXPECT_EQ(BoundFooRefLoc, FooRefLoc);
4303 const StorageLocation *BoundBarRefLoc =
4304 Env.getStorageLocation(*BoundBarRefDecl);
4305 EXPECT_EQ(BoundBarRefLoc, BarRefLoc);
4307 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal);
4311 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToInts) {
4312 std::string Code = R"(
4313 struct A {
4314 int Foo;
4315 int Bar;
4318 void target() {
4319 int Qux;
4320 A Baz;
4321 Baz.Foo = Qux;
4322 auto &FooRef = Baz.Foo;
4323 auto &BarRef = Baz.Bar;
4324 auto [BoundFoo, BoundBar] = Baz;
4325 // [[p]]
4328 runDataflow(
4329 Code,
4330 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4331 ASTContext &ASTCtx) {
4332 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4333 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4335 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef");
4336 ASSERT_THAT(FooRefDecl, NotNull());
4338 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef");
4339 ASSERT_THAT(BarRefDecl, NotNull());
4341 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo");
4342 ASSERT_THAT(BoundFooDecl, NotNull());
4344 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");
4345 ASSERT_THAT(BoundBarDecl, NotNull());
4347 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
4348 ASSERT_THAT(QuxDecl, NotNull());
4350 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl);
4351 ASSERT_THAT(FooRefLoc, NotNull());
4353 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl);
4354 ASSERT_THAT(BarRefLoc, NotNull());
4356 const Value *QuxVal = Env.getValue(*QuxDecl);
4357 ASSERT_THAT(QuxVal, NotNull());
4359 const StorageLocation *BoundFooLoc =
4360 Env.getStorageLocation(*BoundFooDecl);
4361 EXPECT_NE(BoundFooLoc, FooRefLoc);
4363 const StorageLocation *BoundBarLoc =
4364 Env.getStorageLocation(*BoundBarDecl);
4365 EXPECT_NE(BoundBarLoc, BarRefLoc);
4367 EXPECT_EQ(Env.getValue(*BoundFooDecl), QuxVal);
4371 TEST(TransferTest, StructuredBindingAssignFromTupleLikeType) {
4372 std::string Code = R"(
4373 namespace std {
4374 using size_t = int;
4375 template <class> struct tuple_size;
4376 template <std::size_t, class> struct tuple_element;
4377 template <class...> class tuple;
4379 namespace {
4380 template <class T, T v>
4381 struct size_helper { static const T value = v; };
4382 } // namespace
4384 template <class... T>
4385 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {};
4387 template <std::size_t I, class... T>
4388 struct tuple_element<I, tuple<T...>> {
4389 using type = __type_pack_element<I, T...>;
4392 template <class...> class tuple {};
4394 template <std::size_t I, class... T>
4395 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
4396 } // namespace std
4398 std::tuple<bool, int> makeTuple();
4400 void target(bool B) {
4401 auto [BoundFoo, BoundBar] = makeTuple();
4402 bool Baz;
4403 // Include if-then-else to test interaction of `BindingDecl` with join.
4404 if (B) {
4405 Baz = BoundFoo;
4406 (void)BoundBar;
4407 // [[p1]]
4408 } else {
4409 Baz = BoundFoo;
4411 (void)0;
4412 // [[p2]]
4415 runDataflow(
4416 Code,
4417 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4418 ASTContext &ASTCtx) {
4419 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
4420 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
4422 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo");
4423 ASSERT_THAT(BoundFooDecl, NotNull());
4425 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");
4426 ASSERT_THAT(BoundBarDecl, NotNull());
4428 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
4429 ASSERT_THAT(BazDecl, NotNull());
4431 // BindingDecls always map to references -- either lvalue or rvalue, so
4432 // we still need to skip here.
4433 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl);
4434 ASSERT_THAT(BoundFooValue, NotNull());
4435 EXPECT_TRUE(isa<BoolValue>(BoundFooValue));
4437 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl);
4438 ASSERT_THAT(BoundBarValue, NotNull());
4439 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue));
4441 // Test that a `DeclRefExpr` to a `BindingDecl` works as expected.
4442 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue);
4444 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
4446 // Test that `BoundFooDecl` retains the value we expect, after the join.
4447 BoundFooValue = Env2.getValue(*BoundFooDecl);
4448 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue);
4452 TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) {
4453 std::string Code = R"(
4454 namespace std {
4455 using size_t = int;
4456 template <class> struct tuple_size;
4457 template <std::size_t, class> struct tuple_element;
4458 template <class...> class tuple;
4460 namespace {
4461 template <class T, T v>
4462 struct size_helper { static const T value = v; };
4463 } // namespace
4465 template <class... T>
4466 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {};
4468 template <std::size_t I, class... T>
4469 struct tuple_element<I, tuple<T...>> {
4470 using type = __type_pack_element<I, T...>;
4473 template <class...> class tuple {};
4475 template <std::size_t I, class... T>
4476 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
4477 } // namespace std
4479 std::tuple<bool, int> &getTuple();
4481 void target(bool B) {
4482 auto &[BoundFoo, BoundBar] = getTuple();
4483 bool Baz;
4484 // Include if-then-else to test interaction of `BindingDecl` with join.
4485 if (B) {
4486 Baz = BoundFoo;
4487 (void)BoundBar;
4488 // [[p1]]
4489 } else {
4490 Baz = BoundFoo;
4492 (void)0;
4493 // [[p2]]
4496 runDataflow(
4497 Code,
4498 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4499 ASTContext &ASTCtx) {
4500 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
4501 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
4503 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo");
4504 ASSERT_THAT(BoundFooDecl, NotNull());
4506 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");
4507 ASSERT_THAT(BoundBarDecl, NotNull());
4509 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
4510 ASSERT_THAT(BazDecl, NotNull());
4512 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl);
4513 ASSERT_THAT(BoundFooValue, NotNull());
4514 EXPECT_TRUE(isa<BoolValue>(BoundFooValue));
4516 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl);
4517 ASSERT_THAT(BoundBarValue, NotNull());
4518 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue));
4520 // Test that a `DeclRefExpr` to a `BindingDecl` (with reference type)
4521 // works as expected. We don't test aliasing properties of the
4522 // reference, because we don't model `std::get` and so have no way to
4523 // equate separate references into the tuple.
4524 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue);
4526 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
4528 // Test that `BoundFooDecl` retains the value we expect, after the join.
4529 BoundFooValue = Env2.getValue(*BoundFooDecl);
4530 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue);
4534 TEST(TransferTest, BinaryOperatorComma) {
4535 std::string Code = R"(
4536 void target(int Foo, int Bar) {
4537 int &Baz = (Foo, Bar);
4538 // [[p]]
4541 runDataflow(
4542 Code,
4543 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4544 ASTContext &ASTCtx) {
4545 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4546 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4548 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
4549 ASSERT_THAT(BarDecl, NotNull());
4551 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
4552 ASSERT_THAT(BazDecl, NotNull());
4554 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
4555 ASSERT_THAT(BarLoc, NotNull());
4557 const StorageLocation *BazLoc = Env.getStorageLocation(*BazDecl);
4558 EXPECT_EQ(BazLoc, BarLoc);
4562 TEST(TransferTest, IfStmtBranchExtendsFlowCondition) {
4563 std::string Code = R"(
4564 void target(bool Foo) {
4565 if (Foo) {
4566 (void)0;
4567 // [[if_then]]
4568 } else {
4569 (void)0;
4570 // [[if_else]]
4574 runDataflow(
4575 Code,
4576 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4577 ASTContext &ASTCtx) {
4578 ASSERT_THAT(Results.keys(), UnorderedElementsAre("if_then", "if_else"));
4579 const Environment &ThenEnv =
4580 getEnvironmentAtAnnotation(Results, "if_then");
4581 const Environment &ElseEnv =
4582 getEnvironmentAtAnnotation(Results, "if_else");
4584 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4585 ASSERT_THAT(FooDecl, NotNull());
4587 auto &ThenFooVal= getFormula(*FooDecl, ThenEnv);
4588 EXPECT_TRUE(ThenEnv.proves(ThenFooVal));
4590 auto &ElseFooVal = getFormula(*FooDecl, ElseEnv);
4591 EXPECT_TRUE(ElseEnv.proves(ElseEnv.arena().makeNot(ElseFooVal)));
4595 TEST(TransferTest, WhileStmtBranchExtendsFlowCondition) {
4596 std::string Code = R"(
4597 void target(bool Foo) {
4598 while (Foo) {
4599 (void)0;
4600 // [[loop_body]]
4602 (void)0;
4603 // [[after_loop]]
4606 runDataflow(
4607 Code,
4608 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4609 ASTContext &ASTCtx) {
4610 ASSERT_THAT(Results.keys(),
4611 UnorderedElementsAre("loop_body", "after_loop"));
4612 const Environment &LoopBodyEnv =
4613 getEnvironmentAtAnnotation(Results, "loop_body");
4614 const Environment &AfterLoopEnv =
4615 getEnvironmentAtAnnotation(Results, "after_loop");
4617 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4618 ASSERT_THAT(FooDecl, NotNull());
4620 auto &LoopBodyFooVal = getFormula(*FooDecl, LoopBodyEnv);
4621 EXPECT_TRUE(LoopBodyEnv.proves(LoopBodyFooVal));
4623 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv);
4624 EXPECT_TRUE(
4625 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal)));
4629 TEST(TransferTest, DoWhileStmtBranchExtendsFlowCondition) {
4630 std::string Code = R"(
4631 void target(bool Foo) {
4632 bool Bar = true;
4633 do {
4634 (void)0;
4635 // [[loop_body]]
4636 Bar = false;
4637 } while (Foo);
4638 (void)0;
4639 // [[after_loop]]
4642 runDataflow(
4643 Code,
4644 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4645 ASTContext &ASTCtx) {
4646 ASSERT_THAT(Results.keys(),
4647 UnorderedElementsAre("loop_body", "after_loop"));
4648 const Environment &LoopBodyEnv =
4649 getEnvironmentAtAnnotation(Results, "loop_body");
4650 const Environment &AfterLoopEnv =
4651 getEnvironmentAtAnnotation(Results, "after_loop");
4652 auto &A = AfterLoopEnv.arena();
4654 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4655 ASSERT_THAT(FooDecl, NotNull());
4657 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
4658 ASSERT_THAT(BarDecl, NotNull());
4660 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv);
4661 auto &LoopBodyBarVal = getFormula(*BarDecl, LoopBodyEnv);
4662 EXPECT_TRUE(
4663 LoopBodyEnv.proves(A.makeOr(LoopBodyBarVal, LoopBodyFooVal)));
4665 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv);
4666 auto &AfterLoopBarVal = getFormula(*BarDecl, AfterLoopEnv);
4667 EXPECT_TRUE(AfterLoopEnv.proves(A.makeNot(AfterLoopFooVal)));
4668 EXPECT_TRUE(AfterLoopEnv.proves(A.makeNot(AfterLoopBarVal)));
4672 TEST(TransferTest, ForStmtBranchExtendsFlowCondition) {
4673 std::string Code = R"(
4674 void target(bool Foo) {
4675 for (; Foo;) {
4676 (void)0;
4677 // [[loop_body]]
4679 (void)0;
4680 // [[after_loop]]
4683 runDataflow(
4684 Code,
4685 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4686 ASTContext &ASTCtx) {
4687 ASSERT_THAT(Results.keys(),
4688 UnorderedElementsAre("loop_body", "after_loop"));
4689 const Environment &LoopBodyEnv =
4690 getEnvironmentAtAnnotation(Results, "loop_body");
4691 const Environment &AfterLoopEnv =
4692 getEnvironmentAtAnnotation(Results, "after_loop");
4694 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4695 ASSERT_THAT(FooDecl, NotNull());
4697 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv);
4698 EXPECT_TRUE(LoopBodyEnv.proves(LoopBodyFooVal));
4700 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv);
4701 EXPECT_TRUE(
4702 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal)));
4706 TEST(TransferTest, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition) {
4707 std::string Code = R"(
4708 void target(bool Foo) {
4709 for (;;) {
4710 (void)0;
4711 // [[loop_body]]
4715 runDataflow(
4716 Code,
4717 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4718 ASTContext &ASTCtx) {
4719 ASSERT_THAT(Results.keys(), UnorderedElementsAre("loop_body"));
4720 const Environment &LoopBodyEnv =
4721 getEnvironmentAtAnnotation(Results, "loop_body");
4723 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4724 ASSERT_THAT(FooDecl, NotNull());
4726 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv);
4727 EXPECT_FALSE(LoopBodyEnv.proves(LoopBodyFooVal));
4731 TEST(TransferTest, ContextSensitiveOptionDisabled) {
4732 std::string Code = R"(
4733 bool GiveBool();
4734 void SetBool(bool &Var) { Var = true; }
4736 void target() {
4737 bool Foo = GiveBool();
4738 SetBool(Foo);
4739 // [[p]]
4742 runDataflow(
4743 Code,
4744 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4745 ASTContext &ASTCtx) {
4746 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4747 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4749 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4750 ASSERT_THAT(FooDecl, NotNull());
4752 auto &FooVal = getFormula(*FooDecl, Env);
4753 EXPECT_FALSE(Env.proves(FooVal));
4754 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));
4756 {BuiltinOptions{/*.ContextSensitiveOpts=*/std::nullopt}});
4759 TEST(TransferTest, ContextSensitiveReturnReference) {
4760 std::string Code = R"(
4761 class S {};
4762 S& target(bool b, S &s) {
4763 return s;
4764 // [[p]]
4767 runDataflow(
4768 Code,
4769 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4770 ASTContext &ASTCtx) {
4771 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4773 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s");
4774 ASSERT_THAT(SDecl, NotNull());
4776 auto *SLoc = Env.getStorageLocation(*SDecl);
4777 ASSERT_THAT(SLoc, NotNull());
4779 ASSERT_THAT(Env.getReturnStorageLocation(), Eq(SLoc));
4781 {BuiltinOptions{ContextSensitiveOptions{}}});
4784 // This test is a regression test, based on a real crash.
4785 TEST(TransferTest, ContextSensitiveReturnReferenceWithConditionalOperator) {
4786 std::string Code = R"(
4787 class S {};
4788 S& target(bool b, S &s) {
4789 return b ? s : s;
4790 // [[p]]
4793 runDataflow(
4794 Code,
4795 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4796 ASTContext &ASTCtx) {
4797 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4798 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4800 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s");
4801 ASSERT_THAT(SDecl, NotNull());
4803 auto *SLoc = Env.getStorageLocation(*SDecl);
4804 ASSERT_THAT(SLoc, NotNull());
4805 EXPECT_THAT(Env.getValue(*SLoc), NotNull());
4807 auto *Loc = Env.getReturnStorageLocation();
4808 ASSERT_THAT(Loc, NotNull());
4809 EXPECT_THAT(Env.getValue(*Loc), NotNull());
4811 // TODO: We would really like to make this stronger assertion, but that
4812 // doesn't work because we don't propagate values correctly through
4813 // the conditional operator yet.
4814 // ASSERT_THAT(Loc, Eq(SLoc));
4816 {BuiltinOptions{ContextSensitiveOptions{}}});
4819 TEST(TransferTest, ContextSensitiveReturnOneOfTwoReferences) {
4820 std::string Code = R"(
4821 class S {};
4822 S &callee(bool b, S &s1_parm, S &s2_parm) {
4823 if (b)
4824 return s1_parm;
4825 else
4826 return s2_parm;
4828 void target(bool b) {
4829 S s1;
4830 S s2;
4831 S &return_s1 = s1;
4832 S &return_s2 = s2;
4833 S &return_dont_know = callee(b, s1, s2);
4834 // [[p]]
4837 runDataflow(
4838 Code,
4839 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4840 ASTContext &ASTCtx) {
4841 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4843 const ValueDecl *S1 = findValueDecl(ASTCtx, "s1");
4844 ASSERT_THAT(S1, NotNull());
4845 const ValueDecl *S2 = findValueDecl(ASTCtx, "s2");
4846 ASSERT_THAT(S2, NotNull());
4847 const ValueDecl *ReturnS1 = findValueDecl(ASTCtx, "return_s1");
4848 ASSERT_THAT(ReturnS1, NotNull());
4849 const ValueDecl *ReturnS2 = findValueDecl(ASTCtx, "return_s2");
4850 ASSERT_THAT(ReturnS2, NotNull());
4851 const ValueDecl *ReturnDontKnow =
4852 findValueDecl(ASTCtx, "return_dont_know");
4853 ASSERT_THAT(ReturnDontKnow, NotNull());
4855 StorageLocation *S1Loc = Env.getStorageLocation(*S1);
4856 StorageLocation *S2Loc = Env.getStorageLocation(*S2);
4858 EXPECT_THAT(Env.getStorageLocation(*ReturnS1), Eq(S1Loc));
4859 EXPECT_THAT(Env.getStorageLocation(*ReturnS2), Eq(S2Loc));
4861 // In the case where we don't have a consistent storage location for
4862 // the return value, the framework creates a new storage location, which
4863 // should be different from the storage locations of `s1` and `s2`.
4864 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S1Loc));
4865 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S2Loc));
4867 {BuiltinOptions{ContextSensitiveOptions{}}});
4870 TEST(TransferTest, ContextSensitiveDepthZero) {
4871 std::string Code = R"(
4872 bool GiveBool();
4873 void SetBool(bool &Var) { Var = true; }
4875 void target() {
4876 bool Foo = GiveBool();
4877 SetBool(Foo);
4878 // [[p]]
4881 runDataflow(
4882 Code,
4883 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4884 ASTContext &ASTCtx) {
4885 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4886 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4888 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4889 ASSERT_THAT(FooDecl, NotNull());
4891 auto &FooVal = getFormula(*FooDecl, Env);
4892 EXPECT_FALSE(Env.proves(FooVal));
4893 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));
4895 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/0}}});
4898 TEST(TransferTest, ContextSensitiveSetTrue) {
4899 std::string Code = R"(
4900 bool GiveBool();
4901 void SetBool(bool &Var) { Var = true; }
4903 void target() {
4904 bool Foo = GiveBool();
4905 SetBool(Foo);
4906 // [[p]]
4909 runDataflow(
4910 Code,
4911 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4912 ASTContext &ASTCtx) {
4913 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4914 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4916 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4917 ASSERT_THAT(FooDecl, NotNull());
4919 auto &FooVal = getFormula(*FooDecl, Env);
4920 EXPECT_TRUE(Env.proves(FooVal));
4922 {BuiltinOptions{ContextSensitiveOptions{}}});
4925 TEST(TransferTest, ContextSensitiveSetFalse) {
4926 std::string Code = R"(
4927 bool GiveBool();
4928 void SetBool(bool &Var) { Var = false; }
4930 void target() {
4931 bool Foo = GiveBool();
4932 SetBool(Foo);
4933 // [[p]]
4936 runDataflow(
4937 Code,
4938 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4939 ASTContext &ASTCtx) {
4940 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4941 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4943 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4944 ASSERT_THAT(FooDecl, NotNull());
4946 auto &FooVal = getFormula(*FooDecl, Env);
4947 EXPECT_TRUE(Env.proves(Env.arena().makeNot(FooVal)));
4949 {BuiltinOptions{ContextSensitiveOptions{}}});
4952 TEST(TransferTest, ContextSensitiveSetBothTrueAndFalse) {
4953 std::string Code = R"(
4954 bool GiveBool();
4955 void SetBool(bool &Var, bool Val) { Var = Val; }
4957 void target() {
4958 bool Foo = GiveBool();
4959 bool Bar = GiveBool();
4960 SetBool(Foo, true);
4961 SetBool(Bar, false);
4962 // [[p]]
4965 runDataflow(
4966 Code,
4967 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4968 ASTContext &ASTCtx) {
4969 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4970 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4971 auto &A = Env.arena();
4973 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4974 ASSERT_THAT(FooDecl, NotNull());
4976 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
4977 ASSERT_THAT(BarDecl, NotNull());
4979 auto &FooVal = getFormula(*FooDecl, Env);
4980 EXPECT_TRUE(Env.proves(FooVal));
4981 EXPECT_FALSE(Env.proves(A.makeNot(FooVal)));
4983 auto &BarVal = getFormula(*BarDecl, Env);
4984 EXPECT_FALSE(Env.proves(BarVal));
4985 EXPECT_TRUE(Env.proves(A.makeNot(BarVal)));
4987 {BuiltinOptions{ContextSensitiveOptions{}}});
4990 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthOne) {
4991 std::string Code = R"(
4992 bool GiveBool();
4993 void SetBool1(bool &Var) { Var = true; }
4994 void SetBool2(bool &Var) { SetBool1(Var); }
4996 void target() {
4997 bool Foo = GiveBool();
4998 SetBool2(Foo);
4999 // [[p]]
5002 runDataflow(
5003 Code,
5004 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5005 ASTContext &ASTCtx) {
5006 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5007 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5009 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5010 ASSERT_THAT(FooDecl, NotNull());
5012 auto &FooVal = getFormula(*FooDecl, Env);
5013 EXPECT_FALSE(Env.proves(FooVal));
5014 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));
5016 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/1}}});
5019 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthTwo) {
5020 std::string Code = R"(
5021 bool GiveBool();
5022 void SetBool1(bool &Var) { Var = true; }
5023 void SetBool2(bool &Var) { SetBool1(Var); }
5025 void target() {
5026 bool Foo = GiveBool();
5027 SetBool2(Foo);
5028 // [[p]]
5031 runDataflow(
5032 Code,
5033 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5034 ASTContext &ASTCtx) {
5035 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5036 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5038 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5039 ASSERT_THAT(FooDecl, NotNull());
5041 auto &FooVal = getFormula(*FooDecl, Env);
5042 EXPECT_TRUE(Env.proves(FooVal));
5044 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}});
5047 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthTwo) {
5048 std::string Code = R"(
5049 bool GiveBool();
5050 void SetBool1(bool &Var) { Var = true; }
5051 void SetBool2(bool &Var) { SetBool1(Var); }
5052 void SetBool3(bool &Var) { SetBool2(Var); }
5054 void target() {
5055 bool Foo = GiveBool();
5056 SetBool3(Foo);
5057 // [[p]]
5060 runDataflow(
5061 Code,
5062 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5063 ASTContext &ASTCtx) {
5064 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5065 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5067 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5068 ASSERT_THAT(FooDecl, NotNull());
5070 auto &FooVal = getFormula(*FooDecl, Env);
5071 EXPECT_FALSE(Env.proves(FooVal));
5072 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));
5074 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}});
5077 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthThree) {
5078 std::string Code = R"(
5079 bool GiveBool();
5080 void SetBool1(bool &Var) { Var = true; }
5081 void SetBool2(bool &Var) { SetBool1(Var); }
5082 void SetBool3(bool &Var) { SetBool2(Var); }
5084 void target() {
5085 bool Foo = GiveBool();
5086 SetBool3(Foo);
5087 // [[p]]
5090 runDataflow(
5091 Code,
5092 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5093 ASTContext &ASTCtx) {
5094 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5095 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5097 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5098 ASSERT_THAT(FooDecl, NotNull());
5100 auto &FooVal = getFormula(*FooDecl, Env);
5101 EXPECT_TRUE(Env.proves(FooVal));
5103 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/3}}});
5106 TEST(TransferTest, ContextSensitiveMutualRecursion) {
5107 std::string Code = R"(
5108 bool Pong(bool X, bool Y);
5110 bool Ping(bool X, bool Y) {
5111 if (X) {
5112 return Y;
5113 } else {
5114 return Pong(!X, Y);
5118 bool Pong(bool X, bool Y) {
5119 if (Y) {
5120 return X;
5121 } else {
5122 return Ping(X, !Y);
5126 void target() {
5127 bool Foo = Ping(false, false);
5128 // [[p]]
5131 runDataflow(
5132 Code,
5133 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5134 ASTContext &ASTCtx) {
5135 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5136 // The analysis doesn't crash...
5137 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5139 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5140 ASSERT_THAT(FooDecl, NotNull());
5142 auto &FooVal = getFormula(*FooDecl, Env);
5143 // ... but it also can't prove anything here.
5144 EXPECT_FALSE(Env.proves(FooVal));
5145 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));
5147 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/4}}});
5150 TEST(TransferTest, ContextSensitiveSetMultipleLines) {
5151 std::string Code = R"(
5152 void SetBools(bool &Var1, bool &Var2) {
5153 Var1 = true;
5154 Var2 = false;
5157 void target() {
5158 bool Foo = false;
5159 bool Bar = true;
5160 SetBools(Foo, Bar);
5161 // [[p]]
5164 runDataflow(
5165 Code,
5166 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5167 ASTContext &ASTCtx) {
5168 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5169 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5171 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5172 ASSERT_THAT(FooDecl, NotNull());
5174 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
5175 ASSERT_THAT(BarDecl, NotNull());
5177 auto &FooVal = getFormula(*FooDecl, Env);
5178 EXPECT_TRUE(Env.proves(FooVal));
5179 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));
5181 auto &BarVal = getFormula(*BarDecl, Env);
5182 EXPECT_FALSE(Env.proves(BarVal));
5183 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal)));
5185 {BuiltinOptions{ContextSensitiveOptions{}}});
5188 TEST(TransferTest, ContextSensitiveSetMultipleBlocks) {
5189 std::string Code = R"(
5190 void IfCond(bool Cond, bool &Then, bool &Else) {
5191 if (Cond) {
5192 Then = true;
5193 } else {
5194 Else = true;
5198 void target() {
5199 bool Foo = false;
5200 bool Bar = false;
5201 bool Baz = false;
5202 IfCond(Foo, Bar, Baz);
5203 // [[p]]
5206 runDataflow(
5207 Code,
5208 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5209 ASTContext &ASTCtx) {
5210 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5211 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5213 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
5214 ASSERT_THAT(BarDecl, NotNull());
5216 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
5217 ASSERT_THAT(BazDecl, NotNull());
5219 auto &BarVal = getFormula(*BarDecl, Env);
5220 EXPECT_FALSE(Env.proves(BarVal));
5221 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal)));
5223 auto &BazVal = getFormula(*BazDecl, Env);
5224 EXPECT_TRUE(Env.proves(BazVal));
5225 EXPECT_FALSE(Env.proves(Env.arena().makeNot(BazVal)));
5227 {BuiltinOptions{ContextSensitiveOptions{}}});
5230 TEST(TransferTest, ContextSensitiveReturnVoid) {
5231 std::string Code = R"(
5232 void Noop() { return; }
5234 void target() {
5235 Noop();
5236 // [[p]]
5239 runDataflow(
5240 Code,
5241 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5242 ASTContext &ASTCtx) {
5243 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5244 // This just tests that the analysis doesn't crash.
5246 {BuiltinOptions{ContextSensitiveOptions{}}});
5249 TEST(TransferTest, ContextSensitiveReturnTrue) {
5250 std::string Code = R"(
5251 bool GiveBool() { return true; }
5253 void target() {
5254 bool Foo = GiveBool();
5255 // [[p]]
5258 runDataflow(
5259 Code,
5260 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5261 ASTContext &ASTCtx) {
5262 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5263 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5265 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5266 ASSERT_THAT(FooDecl, NotNull());
5268 auto &FooVal = getFormula(*FooDecl, Env);
5269 EXPECT_TRUE(Env.proves(FooVal));
5271 {BuiltinOptions{ContextSensitiveOptions{}}});
5274 TEST(TransferTest, ContextSensitiveReturnFalse) {
5275 std::string Code = R"(
5276 bool GiveBool() { return false; }
5278 void target() {
5279 bool Foo = GiveBool();
5280 // [[p]]
5283 runDataflow(
5284 Code,
5285 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5286 ASTContext &ASTCtx) {
5287 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5288 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5290 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5291 ASSERT_THAT(FooDecl, NotNull());
5293 auto &FooVal = getFormula(*FooDecl, Env);
5294 EXPECT_TRUE(Env.proves(Env.arena().makeNot(FooVal)));
5296 {BuiltinOptions{ContextSensitiveOptions{}}});
5299 TEST(TransferTest, ContextSensitiveReturnArg) {
5300 std::string Code = R"(
5301 bool GiveBool();
5302 bool GiveBack(bool Arg) { return Arg; }
5304 void target() {
5305 bool Foo = GiveBool();
5306 bool Bar = GiveBack(Foo);
5307 bool Baz = Foo == Bar;
5308 // [[p]]
5311 runDataflow(
5312 Code,
5313 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5314 ASTContext &ASTCtx) {
5315 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5316 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5318 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
5319 ASSERT_THAT(BazDecl, NotNull());
5321 auto &BazVal = getFormula(*BazDecl, Env);
5322 EXPECT_TRUE(Env.proves(BazVal));
5324 {BuiltinOptions{ContextSensitiveOptions{}}});
5327 TEST(TransferTest, ContextSensitiveReturnInt) {
5328 std::string Code = R"(
5329 int identity(int x) { return x; }
5331 void target() {
5332 int y = identity(42);
5333 // [[p]]
5336 runDataflow(
5337 Code,
5338 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5339 ASTContext &ASTCtx) {
5340 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5341 // This just tests that the analysis doesn't crash.
5343 {BuiltinOptions{ContextSensitiveOptions{}}});
5346 TEST(TransferTest, ContextSensitiveMethodLiteral) {
5347 std::string Code = R"(
5348 class MyClass {
5349 public:
5350 bool giveBool() { return true; }
5353 void target() {
5354 MyClass MyObj;
5355 bool Foo = MyObj.giveBool();
5356 // [[p]]
5359 runDataflow(
5360 Code,
5361 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5362 ASTContext &ASTCtx) {
5363 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5364 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5366 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5367 ASSERT_THAT(FooDecl, NotNull());
5369 auto &FooVal = getFormula(*FooDecl, Env);
5370 EXPECT_TRUE(Env.proves(FooVal));
5372 {BuiltinOptions{ContextSensitiveOptions{}}});
5375 TEST(TransferTest, ContextSensitiveMethodGetter) {
5376 std::string Code = R"(
5377 class MyClass {
5378 public:
5379 bool getField() { return Field; }
5381 bool Field;
5384 void target() {
5385 MyClass MyObj;
5386 MyObj.Field = true;
5387 bool Foo = MyObj.getField();
5388 // [[p]]
5391 runDataflow(
5392 Code,
5393 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5394 ASTContext &ASTCtx) {
5395 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5396 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5398 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5399 ASSERT_THAT(FooDecl, NotNull());
5401 auto &FooVal = getFormula(*FooDecl, Env);
5402 EXPECT_TRUE(Env.proves(FooVal));
5404 {BuiltinOptions{ContextSensitiveOptions{}}});
5407 TEST(TransferTest, ContextSensitiveMethodSetter) {
5408 std::string Code = R"(
5409 class MyClass {
5410 public:
5411 void setField(bool Val) { Field = Val; }
5413 bool Field;
5416 void target() {
5417 MyClass MyObj;
5418 MyObj.setField(true);
5419 bool Foo = MyObj.Field;
5420 // [[p]]
5423 runDataflow(
5424 Code,
5425 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5426 ASTContext &ASTCtx) {
5427 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5428 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5430 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5431 ASSERT_THAT(FooDecl, NotNull());
5433 auto &FooVal = getFormula(*FooDecl, Env);
5434 EXPECT_TRUE(Env.proves(FooVal));
5436 {BuiltinOptions{ContextSensitiveOptions{}}});
5439 TEST(TransferTest, ContextSensitiveMethodGetterAndSetter) {
5440 std::string Code = R"(
5441 class MyClass {
5442 public:
5443 bool getField() { return Field; }
5444 void setField(bool Val) { Field = Val; }
5446 private:
5447 bool Field;
5450 void target() {
5451 MyClass MyObj;
5452 MyObj.setField(true);
5453 bool Foo = MyObj.getField();
5454 // [[p]]
5457 runDataflow(
5458 Code,
5459 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5460 ASTContext &ASTCtx) {
5461 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5462 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5464 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5465 ASSERT_THAT(FooDecl, NotNull());
5467 auto &FooVal = getFormula(*FooDecl, Env);
5468 EXPECT_TRUE(Env.proves(FooVal));
5470 {BuiltinOptions{ContextSensitiveOptions{}}});
5474 TEST(TransferTest, ContextSensitiveMethodTwoLayersVoid) {
5475 std::string Code = R"(
5476 class MyClass {
5477 public:
5478 void Inner() { MyField = true; }
5479 void Outer() { Inner(); }
5481 bool MyField;
5484 void target() {
5485 MyClass MyObj;
5486 MyObj.Outer();
5487 bool Foo = MyObj.MyField;
5488 // [[p]]
5491 runDataflow(
5492 Code,
5493 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5494 ASTContext &ASTCtx) {
5495 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5497 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5499 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5500 ASSERT_THAT(FooDecl, NotNull());
5502 auto &FooVal = getFormula(*FooDecl, Env);
5503 EXPECT_TRUE(Env.proves(FooVal));
5505 {BuiltinOptions{ContextSensitiveOptions{}}});
5508 TEST(TransferTest, ContextSensitiveMethodTwoLayersReturn) {
5509 std::string Code = R"(
5510 class MyClass {
5511 public:
5512 bool Inner() { return MyField; }
5513 bool Outer() { return Inner(); }
5515 bool MyField;
5518 void target() {
5519 MyClass MyObj;
5520 MyObj.MyField = true;
5521 bool Foo = MyObj.Outer();
5522 // [[p]]
5525 runDataflow(
5526 Code,
5527 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5528 ASTContext &ASTCtx) {
5529 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5531 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5533 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5534 ASSERT_THAT(FooDecl, NotNull());
5536 auto &FooVal = getFormula(*FooDecl, Env);
5537 EXPECT_TRUE(Env.proves(FooVal));
5539 {BuiltinOptions{ContextSensitiveOptions{}}});
5542 TEST(TransferTest, ContextSensitiveConstructorBody) {
5543 std::string Code = R"(
5544 class MyClass {
5545 public:
5546 MyClass() { MyField = true; }
5548 bool MyField;
5551 void target() {
5552 MyClass MyObj;
5553 bool Foo = MyObj.MyField;
5554 // [[p]]
5557 runDataflow(
5558 Code,
5559 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5560 ASTContext &ASTCtx) {
5561 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5562 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5564 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5565 ASSERT_THAT(FooDecl, NotNull());
5567 auto &FooVal = getFormula(*FooDecl, Env);
5568 EXPECT_TRUE(Env.proves(FooVal));
5570 {BuiltinOptions{ContextSensitiveOptions{}}});
5573 TEST(TransferTest, ContextSensitiveConstructorInitializer) {
5574 std::string Code = R"(
5575 class MyClass {
5576 public:
5577 MyClass() : MyField(true) {}
5579 bool MyField;
5582 void target() {
5583 MyClass MyObj;
5584 bool Foo = MyObj.MyField;
5585 // [[p]]
5588 runDataflow(
5589 Code,
5590 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5591 ASTContext &ASTCtx) {
5592 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5593 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5595 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5596 ASSERT_THAT(FooDecl, NotNull());
5598 auto &FooVal = getFormula(*FooDecl, Env);
5599 EXPECT_TRUE(Env.proves(FooVal));
5601 {BuiltinOptions{ContextSensitiveOptions{}}});
5604 TEST(TransferTest, ContextSensitiveConstructorDefault) {
5605 std::string Code = R"(
5606 class MyClass {
5607 public:
5608 MyClass() = default;
5610 bool MyField = true;
5613 void target() {
5614 MyClass MyObj;
5615 bool Foo = MyObj.MyField;
5616 // [[p]]
5619 runDataflow(
5620 Code,
5621 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5622 ASTContext &ASTCtx) {
5623 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5624 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5626 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5627 ASSERT_THAT(FooDecl, NotNull());
5629 auto &FooVal = getFormula(*FooDecl, Env);
5630 EXPECT_TRUE(Env.proves(FooVal));
5632 {BuiltinOptions{ContextSensitiveOptions{}}});
5635 TEST(TransferTest, ContextSensitiveSelfReferentialClass) {
5636 // Test that the `this` pointer seen in the constructor has the same value
5637 // as the address of the variable the object is constructed into.
5638 std::string Code = R"(
5639 class MyClass {
5640 public:
5641 MyClass() : Self(this) {}
5642 MyClass *Self;
5645 void target() {
5646 MyClass MyObj;
5647 MyClass *SelfPtr = MyObj.Self;
5648 // [[p]]
5651 runDataflow(
5652 Code,
5653 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5654 ASTContext &ASTCtx) {
5655 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5657 const ValueDecl *MyObjDecl = findValueDecl(ASTCtx, "MyObj");
5658 ASSERT_THAT(MyObjDecl, NotNull());
5660 const ValueDecl *SelfDecl = findValueDecl(ASTCtx, "SelfPtr");
5661 ASSERT_THAT(SelfDecl, NotNull());
5663 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5664 auto &SelfVal = *cast<PointerValue>(Env.getValue(*SelfDecl));
5665 EXPECT_EQ(Env.getStorageLocation(*MyObjDecl), &SelfVal.getPointeeLoc());
5667 {BuiltinOptions{ContextSensitiveOptions{}}});
5670 TEST(TransferTest, UnnamedBitfieldInitializer) {
5671 std::string Code = R"(
5672 struct B {};
5673 struct A {
5674 unsigned a;
5675 unsigned : 4;
5676 unsigned c;
5677 B b;
5679 void target() {
5680 A a = {};
5681 A test = a;
5682 (void)test.c;
5685 runDataflow(
5686 Code,
5687 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5688 ASTContext &ASTCtx) {
5689 // This doesn't need a body because this test was crashing the framework
5690 // before handling correctly Unnamed bitfields in `InitListExpr`.
5694 // Repro for a crash that used to occur with chained short-circuiting logical
5695 // operators.
5696 TEST(TransferTest, ChainedLogicalOps) {
5697 std::string Code = R"(
5698 bool target() {
5699 bool b = true || false || false || false;
5700 // [[p]]
5701 return b;
5704 runDataflow(
5705 Code,
5706 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5707 ASTContext &ASTCtx) {
5708 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5709 auto &B = getValueForDecl<BoolValue>(ASTCtx, Env, "b").formula();
5710 EXPECT_TRUE(Env.proves(B));
5714 // Repro for a crash that used to occur when we call a `noreturn` function
5715 // within one of the operands of a `&&` or `||` operator.
5716 TEST(TransferTest, NoReturnFunctionInsideShortCircuitedBooleanOp) {
5717 std::string Code = R"(
5718 __attribute__((noreturn)) int doesnt_return();
5719 bool some_condition();
5720 void target(bool b1, bool b2) {
5721 // Neither of these should crash. In addition, if we don't terminate the
5722 // program, we know that the operators need to trigger the short-circuit
5723 // logic, so `NoreturnOnRhsOfAnd` will be false and `NoreturnOnRhsOfOr`
5724 // will be true.
5725 bool NoreturnOnRhsOfAnd = b1 && doesnt_return() > 0;
5726 bool NoreturnOnRhsOfOr = b2 || doesnt_return() > 0;
5728 // Calling a `noreturn` function on the LHS of an `&&` or `||` makes the
5729 // entire expression unreachable. So we know that in both of the following
5730 // cases, if `target()` terminates, the `else` branch was taken.
5731 bool NoreturnOnLhsMakesAndUnreachable = false;
5732 if (some_condition())
5733 doesnt_return() > 0 && some_condition();
5734 else
5735 NoreturnOnLhsMakesAndUnreachable = true;
5737 bool NoreturnOnLhsMakesOrUnreachable = false;
5738 if (some_condition())
5739 doesnt_return() > 0 || some_condition();
5740 else
5741 NoreturnOnLhsMakesOrUnreachable = true;
5743 // [[p]]
5746 runDataflow(
5747 Code,
5748 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5749 ASTContext &ASTCtx) {
5750 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5751 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5752 auto &A = Env.arena();
5754 // Check that [[p]] is reachable with a non-false flow condition.
5755 EXPECT_FALSE(Env.proves(A.makeLiteral(false)));
5757 auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, "b1").formula();
5758 EXPECT_TRUE(Env.proves(A.makeNot(B1)));
5760 auto &NoreturnOnRhsOfAnd =
5761 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfAnd").formula();
5762 EXPECT_TRUE(Env.proves(A.makeNot(NoreturnOnRhsOfAnd)));
5764 auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, "b2").formula();
5765 EXPECT_TRUE(Env.proves(B2));
5767 auto &NoreturnOnRhsOfOr =
5768 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfOr")
5769 .formula();
5770 EXPECT_TRUE(Env.proves(NoreturnOnRhsOfOr));
5772 auto &NoreturnOnLhsMakesAndUnreachable = getValueForDecl<BoolValue>(
5773 ASTCtx, Env, "NoreturnOnLhsMakesAndUnreachable").formula();
5774 EXPECT_TRUE(Env.proves(NoreturnOnLhsMakesAndUnreachable));
5776 auto &NoreturnOnLhsMakesOrUnreachable = getValueForDecl<BoolValue>(
5777 ASTCtx, Env, "NoreturnOnLhsMakesOrUnreachable").formula();
5778 EXPECT_TRUE(Env.proves(NoreturnOnLhsMakesOrUnreachable));
5782 TEST(TransferTest, NewExpressions) {
5783 std::string Code = R"(
5784 void target() {
5785 int *p = new int(42);
5786 // [[after_new]]
5789 runDataflow(
5790 Code,
5791 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5792 ASTContext &ASTCtx) {
5793 const Environment &Env =
5794 getEnvironmentAtAnnotation(Results, "after_new");
5796 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p");
5798 EXPECT_THAT(Env.getValue(P.getPointeeLoc()), NotNull());
5802 TEST(TransferTest, NewExpressions_Structs) {
5803 std::string Code = R"(
5804 struct Inner {
5805 int InnerField;
5808 struct Outer {
5809 Inner OuterField;
5812 void target() {
5813 Outer *p = new Outer;
5814 // Access the fields to make sure the analysis actually generates children
5815 // for them in the `RecordStorageLocation` and `RecordValue`.
5816 p->OuterField.InnerField;
5817 // [[after_new]]
5820 runDataflow(
5821 Code,
5822 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5823 ASTContext &ASTCtx) {
5824 const Environment &Env =
5825 getEnvironmentAtAnnotation(Results, "after_new");
5827 const ValueDecl *OuterField = findValueDecl(ASTCtx, "OuterField");
5828 const ValueDecl *InnerField = findValueDecl(ASTCtx, "InnerField");
5830 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p");
5832 auto &OuterLoc = cast<RecordStorageLocation>(P.getPointeeLoc());
5833 auto &OuterFieldLoc =
5834 *cast<RecordStorageLocation>(OuterLoc.getChild(*OuterField));
5835 auto &InnerFieldLoc = *OuterFieldLoc.getChild(*InnerField);
5837 // Values for the struct and all fields exist after the new.
5838 EXPECT_THAT(Env.getValue(OuterLoc), NotNull());
5839 EXPECT_THAT(Env.getValue(OuterFieldLoc), NotNull());
5840 EXPECT_THAT(Env.getValue(InnerFieldLoc), NotNull());
5844 TEST(TransferTest, FunctionToPointerDecayHasValue) {
5845 std::string Code = R"(
5846 struct A { static void static_member_func(); };
5847 void target() {
5848 // To check that we're treating function-to-pointer decay correctly,
5849 // create two pointers, then verify they refer to the same storage
5850 // location.
5851 // We need to do the test this way because even if an initializer (in this
5852 // case, the function-to-pointer decay) does not create a value, we still
5853 // create a value for the variable.
5854 void (*non_member_p1)() = target;
5855 void (*non_member_p2)() = target;
5857 // Do the same thing but for a static member function.
5858 void (*member_p1)() = A::static_member_func;
5859 void (*member_p2)() = A::static_member_func;
5860 // [[p]]
5863 runDataflow(
5864 Code,
5865 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5866 ASTContext &ASTCtx) {
5867 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5869 auto &NonMemberP1 =
5870 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p1");
5871 auto &NonMemberP2 =
5872 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p2");
5873 EXPECT_EQ(&NonMemberP1.getPointeeLoc(), &NonMemberP2.getPointeeLoc());
5875 auto &MemberP1 =
5876 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p1");
5877 auto &MemberP2 =
5878 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p2");
5879 EXPECT_EQ(&MemberP1.getPointeeLoc(), &MemberP2.getPointeeLoc());
5883 // Check that a builtin function is not associated with a value. (It's only
5884 // possible to call builtin functions directly, not take their address.)
5885 TEST(TransferTest, BuiltinFunctionModeled) {
5886 std::string Code = R"(
5887 void target() {
5888 __builtin_expect(0, 0);
5889 // [[p]]
5892 runDataflow(
5893 Code,
5894 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5895 ASTContext &ASTCtx) {
5896 using ast_matchers::selectFirst;
5897 using ast_matchers::match;
5898 using ast_matchers::traverse;
5899 using ast_matchers::implicitCastExpr;
5900 using ast_matchers::hasCastKind;
5902 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5904 auto *ImplicitCast = selectFirst<ImplicitCastExpr>(
5905 "implicit_cast",
5906 match(traverse(TK_AsIs,
5907 implicitCastExpr(hasCastKind(CK_BuiltinFnToFnPtr))
5908 .bind("implicit_cast")),
5909 ASTCtx));
5911 ASSERT_THAT(ImplicitCast, NotNull());
5912 EXPECT_THAT(Env.getValue(*ImplicitCast), IsNull());
5916 // Check that a callee of a member operator call is modeled as a `PointerValue`.
5917 // Member operator calls are unusual in that their callee is a pointer that
5918 // stems from a `FunctionToPointerDecay`. In calls to non-operator non-static
5919 // member functions, the callee is a `MemberExpr` (which does not have pointer
5920 // type).
5921 // We want to make sure that we produce a pointer value for the callee in this
5922 // specific scenario and that its storage location is durable (for convergence).
5923 TEST(TransferTest, MemberOperatorCallModelsPointerForCallee) {
5924 std::string Code = R"(
5925 struct S {
5926 bool operator!=(S s);
5928 void target() {
5929 S s;
5930 (void)(s != s);
5931 (void)(s != s);
5932 // [[p]]
5935 runDataflow(
5936 Code,
5937 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5938 ASTContext &ASTCtx) {
5939 using ast_matchers::selectFirst;
5940 using ast_matchers::match;
5941 using ast_matchers::traverse;
5942 using ast_matchers::cxxOperatorCallExpr;
5944 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5946 auto Matches = match(
5947 traverse(TK_AsIs, cxxOperatorCallExpr().bind("call")), ASTCtx);
5949 ASSERT_EQ(Matches.size(), 2UL);
5951 auto *Call1 = Matches[0].getNodeAs<CXXOperatorCallExpr>("call");
5952 auto *Call2 = Matches[1].getNodeAs<CXXOperatorCallExpr>("call");
5954 ASSERT_THAT(Call1, NotNull());
5955 ASSERT_THAT(Call2, NotNull());
5957 EXPECT_EQ(cast<ImplicitCastExpr>(Call1->getCallee())->getCastKind(),
5958 CK_FunctionToPointerDecay);
5959 EXPECT_EQ(cast<ImplicitCastExpr>(Call2->getCallee())->getCastKind(),
5960 CK_FunctionToPointerDecay);
5962 auto *Ptr1 = cast<PointerValue>(Env.getValue(*Call1->getCallee()));
5963 auto *Ptr2 = cast<PointerValue>(Env.getValue(*Call2->getCallee()));
5965 ASSERT_EQ(&Ptr1->getPointeeLoc(), &Ptr2->getPointeeLoc());
5969 // Check that fields of anonymous records are modeled.
5970 TEST(TransferTest, AnonymousStruct) {
5971 std::string Code = R"(
5972 struct S {
5973 struct {
5974 bool b;
5977 void target() {
5978 S s;
5979 s.b = true;
5980 // [[p]]
5983 runDataflow(
5984 Code,
5985 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5986 ASTContext &ASTCtx) {
5987 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5988 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s");
5989 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b");
5990 const IndirectFieldDecl *IndirectField =
5991 findIndirectFieldDecl(ASTCtx, "b");
5993 auto *S = cast<RecordStorageLocation>(Env.getStorageLocation(*SDecl));
5994 auto &AnonStruct = *cast<RecordStorageLocation>(
5995 S->getChild(*cast<ValueDecl>(IndirectField->chain().front())));
5997 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env));
5998 ASSERT_TRUE(Env.proves(B->formula()));
6002 TEST(TransferTest, AnonymousStructWithInitializer) {
6003 std::string Code = R"(
6004 struct target {
6005 target() {
6006 (void)0;
6007 // [[p]]
6009 struct {
6010 bool b = true;
6014 runDataflow(
6015 Code,
6016 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6017 ASTContext &ASTCtx) {
6018 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
6019 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b");
6020 const IndirectFieldDecl *IndirectField =
6021 findIndirectFieldDecl(ASTCtx, "b");
6023 auto *ThisLoc =
6024 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation());
6025 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild(
6026 *cast<ValueDecl>(IndirectField->chain().front())));
6028 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env));
6029 ASSERT_TRUE(Env.proves(B->formula()));
6033 TEST(TransferTest, AnonymousStructWithReferenceField) {
6034 std::string Code = R"(
6035 int global_i = 0;
6036 struct target {
6037 target() {
6038 (void)0;
6039 // [[p]]
6041 struct {
6042 int &i = global_i;
6046 runDataflow(
6047 Code,
6048 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6049 ASTContext &ASTCtx) {
6050 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
6051 const ValueDecl *GlobalIDecl = findValueDecl(ASTCtx, "global_i");
6052 const ValueDecl *IDecl = findValueDecl(ASTCtx, "i");
6053 const IndirectFieldDecl *IndirectField =
6054 findIndirectFieldDecl(ASTCtx, "i");
6056 auto *ThisLoc =
6057 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation());
6058 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild(
6059 *cast<ValueDecl>(IndirectField->chain().front())));
6061 ASSERT_EQ(AnonStruct.getChild(*IDecl),
6062 Env.getStorageLocation(*GlobalIDecl));
6066 TEST(TransferTest, EvaluateBlockWithUnreachablePreds) {
6067 // This is a crash repro.
6068 // `false` block may not have been processed when we try to evaluate the `||`
6069 // after visiting `true`, because it is not necessary (and therefore the edge
6070 // is marked unreachable). Trying to get the analysis state via
6071 // `getEnvironment` for the subexpression still should not crash.
6072 std::string Code = R"(
6073 int target(int i) {
6074 if ((i < 0 && true) || false) {
6075 return 0;
6077 return 0;
6080 runDataflow(
6081 Code,
6082 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6083 ASTContext &ASTCtx) {});
6086 TEST(TransferTest, LambdaCaptureByCopy) {
6087 std::string Code = R"(
6088 void target(int Foo, int Bar) {
6089 [Foo]() {
6090 (void)0;
6091 // [[p]]
6092 }();
6095 runDataflowOnLambda(
6096 Code,
6097 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6098 ASTContext &ASTCtx) {
6099 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6100 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
6102 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
6103 ASSERT_THAT(FooDecl, NotNull());
6105 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
6106 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
6108 const Value *FooVal = Env.getValue(*FooLoc);
6109 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
6111 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
6112 ASSERT_THAT(BarDecl, NotNull());
6114 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
6115 EXPECT_THAT(BarLoc, IsNull());
6119 TEST(TransferTest, LambdaCaptureByReference) {
6120 std::string Code = R"(
6121 void target(int Foo, int Bar) {
6122 [&Foo]() {
6123 (void)0;
6124 // [[p]]
6125 }();
6128 runDataflowOnLambda(
6129 Code,
6130 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6131 ASTContext &ASTCtx) {
6132 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6133 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
6135 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
6136 ASSERT_THAT(FooDecl, NotNull());
6138 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
6139 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
6141 const Value *FooVal = Env.getValue(*FooLoc);
6142 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
6144 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
6145 ASSERT_THAT(BarDecl, NotNull());
6147 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
6148 EXPECT_THAT(BarLoc, IsNull());
6152 TEST(TransferTest, LambdaCaptureWithInitializer) {
6153 std::string Code = R"(
6154 void target(int Bar) {
6155 [Foo=Bar]() {
6156 (void)0;
6157 // [[p]]
6158 }();
6161 runDataflowOnLambda(
6162 Code,
6163 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6164 ASTContext &ASTCtx) {
6165 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6166 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
6168 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
6169 ASSERT_THAT(FooDecl, NotNull());
6171 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
6172 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
6174 const Value *FooVal = Env.getValue(*FooLoc);
6175 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
6177 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
6178 ASSERT_THAT(BarDecl, NotNull());
6180 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
6181 EXPECT_THAT(BarLoc, IsNull());
6185 TEST(TransferTest, LambdaCaptureByCopyImplicit) {
6186 std::string Code = R"(
6187 void target(int Foo, int Bar) {
6188 [=]() {
6189 Foo;
6190 // [[p]]
6191 }();
6194 runDataflowOnLambda(
6195 Code,
6196 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6197 ASTContext &ASTCtx) {
6198 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6199 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
6201 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
6202 ASSERT_THAT(FooDecl, NotNull());
6204 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
6205 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
6207 const Value *FooVal = Env.getValue(*FooLoc);
6208 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
6210 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
6211 ASSERT_THAT(BarDecl, NotNull());
6213 // There is no storage location for `Bar` because it isn't used in the
6214 // body of the lambda.
6215 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
6216 EXPECT_THAT(BarLoc, IsNull());
6220 TEST(TransferTest, LambdaCaptureByReferenceImplicit) {
6221 std::string Code = R"(
6222 void target(int Foo, int Bar) {
6223 [&]() {
6224 Foo;
6225 // [[p]]
6226 }();
6229 runDataflowOnLambda(
6230 Code,
6231 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6232 ASTContext &ASTCtx) {
6233 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6234 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
6236 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
6237 ASSERT_THAT(FooDecl, NotNull());
6239 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
6240 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
6242 const Value *FooVal = Env.getValue(*FooLoc);
6243 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
6245 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
6246 ASSERT_THAT(BarDecl, NotNull());
6248 // There is no storage location for `Bar` because it isn't used in the
6249 // body of the lambda.
6250 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
6251 EXPECT_THAT(BarLoc, IsNull());
6255 TEST(TransferTest, LambdaCaptureThis) {
6256 std::string Code = R"(
6257 struct Bar {
6258 int Foo;
6260 void target() {
6261 [this]() {
6262 Foo;
6263 // [[p]]
6264 }();
6268 runDataflowOnLambda(
6269 Code,
6270 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6271 ASTContext &ASTCtx) {
6272 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
6273 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
6275 const RecordStorageLocation *ThisPointeeLoc =
6276 Env.getThisPointeeStorageLocation();
6277 ASSERT_THAT(ThisPointeeLoc, NotNull());
6279 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
6280 ASSERT_THAT(FooDecl, NotNull());
6282 const StorageLocation *FooLoc = ThisPointeeLoc->getChild(*FooDecl);
6283 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
6285 const Value *FooVal = Env.getValue(*FooLoc);
6286 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
6290 TEST(TransferTest, DifferentReferenceLocInJoin) {
6291 // This test triggers a case where the storage location for a reference-type
6292 // variable is different for two states being joined. We used to believe this
6293 // could not happen and therefore had an assertion disallowing this; this test
6294 // exists to demonstrate that we can handle this condition without a failing
6295 // assertion. See also the discussion here:
6296 // https://discourse.llvm.org/t/70086/6
6297 std::string Code = R"(
6298 namespace std {
6299 template <class T> struct initializer_list {
6300 const T* begin();
6301 const T* end();
6305 void target(char* p, char* end) {
6306 while (p != end) {
6307 if (*p == ' ') {
6308 p++;
6309 continue;
6312 auto && range = {1, 2};
6313 for (auto b = range.begin(), e = range.end(); b != e; ++b) {
6315 (void)0;
6316 // [[p]]
6320 runDataflow(
6321 Code,
6322 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6323 ASTContext &ASTCtx) {
6324 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
6326 // Joining environments with different storage locations for the same
6327 // declaration results in the declaration being removed from the joined
6328 // environment.
6329 const ValueDecl *VD = findValueDecl(ASTCtx, "range");
6330 ASSERT_EQ(Env.getStorageLocation(*VD), nullptr);
6334 } // namespace