[AMDGPU] Add True16 register classes.
[llvm-project.git] / clang / unittests / Analysis / FlowSensitive / TransferTest.cpp
blobe8cbca756460369050f5c642d308b6a23ee52929
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 const Formula &getFormula(const ValueDecl &D, const Environment &Env) {
70 return cast<BoolValue>(Env.getValue(D))->formula();
73 TEST(TransferTest, CNotSupported) {
74 std::string Code = R"(
75 void target() {}
76 )";
77 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(
78 Code, [](const auto &, auto &) {}, {BuiltinOptions{}},
79 LangStandard::lang_c89),
80 llvm::FailedWithMessage("Can only analyze C++"));
83 TEST(TransferTest, IntVarDeclNotTrackedWhenTransferDisabled) {
84 std::string Code = R"(
85 void target() {
86 int Foo;
87 // [[p]]
89 )";
90 runDataflow(
91 Code,
92 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
93 ASTContext &ASTCtx) {
94 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
95 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
97 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
98 ASSERT_THAT(FooDecl, NotNull());
100 EXPECT_EQ(Env.getStorageLocation(*FooDecl), nullptr);
102 LangStandard::lang_cxx17,
103 /*ApplyBuiltinTransfer=*/false);
106 TEST(TransferTest, BoolVarDecl) {
107 std::string Code = R"(
108 void target() {
109 bool Foo;
110 // [[p]]
113 runDataflow(
114 Code,
115 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
116 ASTContext &ASTCtx) {
117 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
118 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
120 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
121 ASSERT_THAT(FooDecl, NotNull());
123 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
124 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
126 const Value *FooVal = Env.getValue(*FooLoc);
127 EXPECT_TRUE(isa_and_nonnull<BoolValue>(FooVal));
131 TEST(TransferTest, IntVarDecl) {
132 std::string Code = R"(
133 void target() {
134 int Foo;
135 // [[p]]
138 runDataflow(
139 Code,
140 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
141 ASTContext &ASTCtx) {
142 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
143 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
145 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
146 ASSERT_THAT(FooDecl, NotNull());
148 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
149 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
151 const Value *FooVal = Env.getValue(*FooLoc);
152 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
156 TEST(TransferTest, StructIncomplete) {
157 std::string Code = R"(
158 struct A;
160 void target() {
161 A* Foo;
162 // [[p]]
165 runDataflow(
166 Code,
167 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
168 ASTContext &ASTCtx) {
169 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
170 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
172 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
173 ASSERT_THAT(FooDecl, NotNull());
174 auto *FooValue = dyn_cast_or_null<PointerValue>(Env.getValue(*FooDecl));
175 ASSERT_THAT(FooValue, NotNull());
177 EXPECT_TRUE(isa<RecordStorageLocation>(FooValue->getPointeeLoc()));
178 auto *FooPointeeValue = Env.getValue(FooValue->getPointeeLoc());
179 ASSERT_THAT(FooPointeeValue, NotNull());
180 EXPECT_TRUE(isa<RecordValue>(FooPointeeValue));
184 // As a memory optimization, we prevent modeling fields nested below a certain
185 // level (currently, depth 3). This test verifies this lack of modeling. We also
186 // include a regression test for the case that the unmodeled field is a
187 // reference to a struct; previously, we crashed when accessing such a field.
188 TEST(TransferTest, StructFieldUnmodeled) {
189 std::string Code = R"(
190 struct S { int X; };
191 S GlobalS;
192 struct A { S &Unmodeled = GlobalS; };
193 struct B { A F3; };
194 struct C { B F2; };
195 struct D { C F1; };
197 void target() {
198 D Bar;
199 A &Foo = Bar.F1.F2.F3;
200 int Zab = Foo.Unmodeled.X;
201 // [[p]]
204 runDataflow(
205 Code,
206 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
207 ASTContext &ASTCtx) {
208 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
209 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
211 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
212 ASSERT_THAT(FooDecl, NotNull());
213 QualType FooReferentType = FooDecl->getType()->getPointeeType();
214 ASSERT_TRUE(FooReferentType->isStructureType());
215 auto FooFields = FooReferentType->getAsRecordDecl()->fields();
217 FieldDecl *UnmodeledDecl = nullptr;
218 for (FieldDecl *Field : FooFields) {
219 if (Field->getNameAsString() == "Unmodeled") {
220 UnmodeledDecl = Field;
221 } else {
222 FAIL() << "Unexpected field: " << Field->getNameAsString();
225 ASSERT_THAT(UnmodeledDecl, NotNull());
227 const auto *FooLoc =
228 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
229 const auto *UnmodeledLoc = FooLoc->getChild(*UnmodeledDecl);
230 ASSERT_TRUE(isa<RecordStorageLocation>(UnmodeledLoc));
231 EXPECT_THAT(Env.getValue(*UnmodeledLoc), IsNull());
233 const ValueDecl *ZabDecl = findValueDecl(ASTCtx, "Zab");
234 ASSERT_THAT(ZabDecl, NotNull());
235 EXPECT_THAT(Env.getValue(*ZabDecl), NotNull());
239 TEST(TransferTest, StructVarDecl) {
240 std::string Code = R"(
241 struct A {
242 int Bar;
245 void target() {
246 A Foo;
247 (void)Foo.Bar;
248 // [[p]]
251 runDataflow(
252 Code,
253 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
254 ASTContext &ASTCtx) {
255 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
256 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
258 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
259 ASSERT_THAT(FooDecl, NotNull());
261 ASSERT_TRUE(FooDecl->getType()->isStructureType());
262 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
264 FieldDecl *BarDecl = nullptr;
265 for (FieldDecl *Field : FooFields) {
266 if (Field->getNameAsString() == "Bar") {
267 BarDecl = Field;
268 } else {
269 FAIL() << "Unexpected field: " << Field->getNameAsString();
272 ASSERT_THAT(BarDecl, NotNull());
274 const auto *FooLoc =
275 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
276 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
280 TEST(TransferTest, StructVarDeclWithInit) {
281 std::string Code = R"(
282 struct A {
283 int Bar;
286 A Gen();
288 void target() {
289 A Foo = Gen();
290 (void)Foo.Bar;
291 // [[p]]
294 runDataflow(
295 Code,
296 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
297 ASTContext &ASTCtx) {
298 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
299 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
301 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
302 ASSERT_THAT(FooDecl, NotNull());
304 ASSERT_TRUE(FooDecl->getType()->isStructureType());
305 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
307 FieldDecl *BarDecl = nullptr;
308 for (FieldDecl *Field : FooFields) {
309 if (Field->getNameAsString() == "Bar") {
310 BarDecl = Field;
311 } else {
312 FAIL() << "Unexpected field: " << Field->getNameAsString();
315 ASSERT_THAT(BarDecl, NotNull());
317 const auto *FooLoc =
318 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
319 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
323 TEST(TransferTest, StructArrayVarDecl) {
324 std::string Code = R"(
325 struct A {};
327 void target() {
328 A Array[2];
329 // [[p]]
332 runDataflow(
333 Code,
334 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
335 ASTContext &ASTCtx) {
336 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
338 const ValueDecl *ArrayDecl = findValueDecl(ASTCtx, "Array");
340 // We currently don't create values for arrays.
341 ASSERT_THAT(Env.getValue(*ArrayDecl), IsNull());
345 TEST(TransferTest, ClassVarDecl) {
346 std::string Code = R"(
347 class A {
348 public:
349 int Bar;
352 void target() {
353 A Foo;
354 (void)Foo.Bar;
355 // [[p]]
358 runDataflow(
359 Code,
360 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
361 ASTContext &ASTCtx) {
362 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
363 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
365 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
366 ASSERT_THAT(FooDecl, NotNull());
368 ASSERT_TRUE(FooDecl->getType()->isClassType());
369 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
371 FieldDecl *BarDecl = nullptr;
372 for (FieldDecl *Field : FooFields) {
373 if (Field->getNameAsString() == "Bar") {
374 BarDecl = Field;
375 } else {
376 FAIL() << "Unexpected field: " << Field->getNameAsString();
379 ASSERT_THAT(BarDecl, NotNull());
381 const auto *FooLoc =
382 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
383 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
387 TEST(TransferTest, ReferenceVarDecl) {
388 std::string Code = R"(
389 struct A {};
391 A &getA();
393 void target() {
394 A &Foo = getA();
395 // [[p]]
398 runDataflow(
399 Code,
400 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
401 ASTContext &ASTCtx) {
402 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
403 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
405 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
406 ASSERT_THAT(FooDecl, NotNull());
408 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
409 ASSERT_TRUE(isa_and_nonnull<RecordStorageLocation>(FooLoc));
411 const Value *FooReferentVal = Env.getValue(*FooLoc);
412 EXPECT_TRUE(isa_and_nonnull<RecordValue>(FooReferentVal));
416 TEST(TransferTest, SelfReferentialReferenceVarDecl) {
417 std::string Code = R"(
418 struct A;
420 struct B {};
422 struct C {
423 A &FooRef;
424 A *FooPtr;
425 B &BazRef;
426 B *BazPtr;
429 struct A {
430 C &Bar;
433 A &getA();
435 void target() {
436 A &Foo = getA();
437 (void)Foo.Bar.FooRef;
438 (void)Foo.Bar.FooPtr;
439 (void)Foo.Bar.BazRef;
440 (void)Foo.Bar.BazPtr;
441 // [[p]]
444 runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>>
445 &Results,
446 ASTContext &ASTCtx) {
447 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
448 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
450 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
451 ASSERT_THAT(FooDecl, NotNull());
453 ASSERT_TRUE(FooDecl->getType()->isReferenceType());
454 ASSERT_TRUE(FooDecl->getType().getNonReferenceType()->isStructureType());
455 const auto FooFields =
456 FooDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields();
458 FieldDecl *BarDecl = nullptr;
459 for (FieldDecl *Field : FooFields) {
460 if (Field->getNameAsString() == "Bar") {
461 BarDecl = Field;
462 } else {
463 FAIL() << "Unexpected field: " << Field->getNameAsString();
466 ASSERT_THAT(BarDecl, NotNull());
468 ASSERT_TRUE(BarDecl->getType()->isReferenceType());
469 ASSERT_TRUE(BarDecl->getType().getNonReferenceType()->isStructureType());
470 const auto BarFields =
471 BarDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields();
473 FieldDecl *FooRefDecl = nullptr;
474 FieldDecl *FooPtrDecl = nullptr;
475 FieldDecl *BazRefDecl = nullptr;
476 FieldDecl *BazPtrDecl = nullptr;
477 for (FieldDecl *Field : BarFields) {
478 if (Field->getNameAsString() == "FooRef") {
479 FooRefDecl = Field;
480 } else if (Field->getNameAsString() == "FooPtr") {
481 FooPtrDecl = Field;
482 } else if (Field->getNameAsString() == "BazRef") {
483 BazRefDecl = Field;
484 } else if (Field->getNameAsString() == "BazPtr") {
485 BazPtrDecl = Field;
486 } else {
487 FAIL() << "Unexpected field: " << Field->getNameAsString();
490 ASSERT_THAT(FooRefDecl, NotNull());
491 ASSERT_THAT(FooPtrDecl, NotNull());
492 ASSERT_THAT(BazRefDecl, NotNull());
493 ASSERT_THAT(BazPtrDecl, NotNull());
495 const auto &FooLoc =
496 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
498 const auto &BarLoc =
499 *cast<RecordStorageLocation>(FooLoc.getChild(*BarDecl));
501 const auto &FooReferentLoc =
502 *cast<RecordStorageLocation>(BarLoc.getChild(*FooRefDecl));
503 EXPECT_THAT(Env.getValue(FooReferentLoc), NotNull());
504 EXPECT_THAT(getFieldValue(&FooReferentLoc, *BarDecl, Env), IsNull());
506 const auto &FooPtrVal =
507 *cast<PointerValue>(getFieldValue(&BarLoc, *FooPtrDecl, Env));
508 const auto &FooPtrPointeeLoc =
509 cast<RecordStorageLocation>(FooPtrVal.getPointeeLoc());
510 EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), NotNull());
511 EXPECT_THAT(getFieldValue(&FooPtrPointeeLoc, *BarDecl, Env), IsNull());
513 EXPECT_THAT(getFieldValue(&BarLoc, *BazRefDecl, Env), NotNull());
515 const auto &BazPtrVal =
516 *cast<PointerValue>(getFieldValue(&BarLoc, *BazPtrDecl, Env));
517 const StorageLocation &BazPtrPointeeLoc = BazPtrVal.getPointeeLoc();
518 EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull());
522 TEST(TransferTest, PointerVarDecl) {
523 std::string Code = R"(
524 struct A {};
526 A *getA();
528 void target() {
529 A *Foo = getA();
530 // [[p]]
533 runDataflow(
534 Code,
535 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
536 ASTContext &ASTCtx) {
537 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
538 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
540 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
541 ASSERT_THAT(FooDecl, NotNull());
543 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
544 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
546 const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));
547 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
548 EXPECT_TRUE(isa<RecordStorageLocation>(&FooPointeeLoc));
550 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
551 EXPECT_TRUE(isa_and_nonnull<RecordValue>(FooPointeeVal));
555 TEST(TransferTest, SelfReferentialPointerVarDecl) {
556 std::string Code = R"(
557 struct A;
559 struct B {};
561 struct C {
562 A &FooRef;
563 A *FooPtr;
564 B &BazRef;
565 B *BazPtr;
568 struct A {
569 C *Bar;
572 A *getA();
574 void target() {
575 A *Foo = getA();
576 (void)Foo->Bar->FooRef;
577 (void)Foo->Bar->FooPtr;
578 (void)Foo->Bar->BazRef;
579 (void)Foo->Bar->BazPtr;
580 // [[p]]
583 runDataflow(
584 Code,
585 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
586 ASTContext &ASTCtx) {
587 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
588 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
590 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
591 ASSERT_THAT(FooDecl, NotNull());
593 ASSERT_TRUE(FooDecl->getType()->isPointerType());
594 ASSERT_TRUE(FooDecl->getType()
595 ->getAs<PointerType>()
596 ->getPointeeType()
597 ->isStructureType());
598 const auto FooFields = FooDecl->getType()
599 ->getAs<PointerType>()
600 ->getPointeeType()
601 ->getAsRecordDecl()
602 ->fields();
604 FieldDecl *BarDecl = nullptr;
605 for (FieldDecl *Field : FooFields) {
606 if (Field->getNameAsString() == "Bar") {
607 BarDecl = Field;
608 } else {
609 FAIL() << "Unexpected field: " << Field->getNameAsString();
612 ASSERT_THAT(BarDecl, NotNull());
614 ASSERT_TRUE(BarDecl->getType()->isPointerType());
615 ASSERT_TRUE(BarDecl->getType()
616 ->getAs<PointerType>()
617 ->getPointeeType()
618 ->isStructureType());
619 const auto BarFields = BarDecl->getType()
620 ->getAs<PointerType>()
621 ->getPointeeType()
622 ->getAsRecordDecl()
623 ->fields();
625 FieldDecl *FooRefDecl = nullptr;
626 FieldDecl *FooPtrDecl = nullptr;
627 FieldDecl *BazRefDecl = nullptr;
628 FieldDecl *BazPtrDecl = nullptr;
629 for (FieldDecl *Field : BarFields) {
630 if (Field->getNameAsString() == "FooRef") {
631 FooRefDecl = Field;
632 } else if (Field->getNameAsString() == "FooPtr") {
633 FooPtrDecl = Field;
634 } else if (Field->getNameAsString() == "BazRef") {
635 BazRefDecl = Field;
636 } else if (Field->getNameAsString() == "BazPtr") {
637 BazPtrDecl = Field;
638 } else {
639 FAIL() << "Unexpected field: " << Field->getNameAsString();
642 ASSERT_THAT(FooRefDecl, NotNull());
643 ASSERT_THAT(FooPtrDecl, NotNull());
644 ASSERT_THAT(BazRefDecl, NotNull());
645 ASSERT_THAT(BazPtrDecl, NotNull());
647 const auto &FooLoc =
648 *cast<ScalarStorageLocation>(Env.getStorageLocation(*FooDecl));
649 const auto &FooVal = *cast<PointerValue>(Env.getValue(FooLoc));
650 const auto &FooPointeeLoc =
651 cast<RecordStorageLocation>(FooVal.getPointeeLoc());
653 const auto &BarVal =
654 *cast<PointerValue>(getFieldValue(&FooPointeeLoc, *BarDecl, Env));
655 const auto &BarPointeeLoc =
656 cast<RecordStorageLocation>(BarVal.getPointeeLoc());
658 EXPECT_THAT(getFieldValue(&BarPointeeLoc, *FooRefDecl, Env), NotNull());
660 const auto &FooPtrVal = *cast<PointerValue>(
661 getFieldValue(&BarPointeeLoc, *FooPtrDecl, Env));
662 const auto &FooPtrPointeeLoc =
663 cast<RecordStorageLocation>(FooPtrVal.getPointeeLoc());
664 EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull());
666 EXPECT_THAT(getFieldValue(&BarPointeeLoc, *BazRefDecl, Env), NotNull());
668 const auto &BazPtrVal = *cast<PointerValue>(
669 getFieldValue(&BarPointeeLoc, *BazPtrDecl, Env));
670 const StorageLocation &BazPtrPointeeLoc = BazPtrVal.getPointeeLoc();
671 EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull());
675 TEST(TransferTest, DirectlySelfReferentialReference) {
676 std::string Code = R"(
677 struct target {
678 target() {
679 (void)0;
680 // [[p]]
682 target &self = *this;
685 runDataflow(
686 Code,
687 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
688 ASTContext &ASTCtx) {
689 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
690 const ValueDecl *SelfDecl = findValueDecl(ASTCtx, "self");
692 auto *ThisLoc = Env.getThisPointeeStorageLocation();
693 ASSERT_EQ(ThisLoc->getChild(*SelfDecl), ThisLoc);
697 TEST(TransferTest, MultipleVarsDecl) {
698 std::string Code = R"(
699 void target() {
700 int Foo, Bar;
701 (void)0;
702 // [[p]]
705 runDataflow(
706 Code,
707 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
708 ASTContext &ASTCtx) {
709 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
710 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
712 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
713 ASSERT_THAT(FooDecl, NotNull());
715 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
716 ASSERT_THAT(BarDecl, NotNull());
718 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
719 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
721 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
722 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
724 const Value *FooVal = Env.getValue(*FooLoc);
725 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
727 const Value *BarVal = Env.getValue(*BarLoc);
728 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
732 TEST(TransferTest, JoinVarDecl) {
733 std::string Code = R"(
734 void target(bool B) {
735 int Foo;
736 // [[p1]]
737 if (B) {
738 int Bar;
739 // [[p2]]
740 } else {
741 int Baz;
742 // [[p3]]
744 (void)0;
745 // [[p4]]
748 runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>>
749 &Results,
750 ASTContext &ASTCtx) {
751 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2", "p3", "p4"));
753 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
754 ASSERT_THAT(FooDecl, NotNull());
756 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
757 ASSERT_THAT(BarDecl, NotNull());
759 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
760 ASSERT_THAT(BazDecl, NotNull());
762 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
764 const StorageLocation *FooLoc = Env1.getStorageLocation(*FooDecl);
765 EXPECT_THAT(FooLoc, NotNull());
766 EXPECT_THAT(Env1.getStorageLocation(*BarDecl), IsNull());
767 EXPECT_THAT(Env1.getStorageLocation(*BazDecl), IsNull());
769 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
770 EXPECT_EQ(Env2.getStorageLocation(*FooDecl), FooLoc);
771 EXPECT_THAT(Env2.getStorageLocation(*BarDecl), NotNull());
772 EXPECT_THAT(Env2.getStorageLocation(*BazDecl), IsNull());
774 const Environment &Env3 = getEnvironmentAtAnnotation(Results, "p3");
775 EXPECT_EQ(Env3.getStorageLocation(*FooDecl), FooLoc);
776 EXPECT_THAT(Env3.getStorageLocation(*BarDecl), IsNull());
777 EXPECT_THAT(Env3.getStorageLocation(*BazDecl), NotNull());
779 const Environment &Env4 = getEnvironmentAtAnnotation(Results, "p4");
780 EXPECT_EQ(Env4.getStorageLocation(*FooDecl), FooLoc);
781 EXPECT_THAT(Env4.getStorageLocation(*BarDecl), IsNull());
782 EXPECT_THAT(Env4.getStorageLocation(*BazDecl), IsNull());
786 TEST(TransferTest, BinaryOperatorAssign) {
787 std::string Code = R"(
788 void target() {
789 int Foo;
790 int Bar;
791 (Bar) = (Foo);
792 // [[p]]
795 runDataflow(
796 Code,
797 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
798 ASTContext &ASTCtx) {
799 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
800 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
802 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
803 ASSERT_THAT(FooDecl, NotNull());
805 const Value *FooVal = Env.getValue(*FooDecl);
806 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
808 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
809 ASSERT_THAT(BarDecl, NotNull());
811 EXPECT_EQ(Env.getValue(*BarDecl), FooVal);
815 TEST(TransferTest, BinaryOperatorAssignIntegerLiteral) {
816 std::string Code = R"(
817 void target() {
818 int Foo = 1;
819 // [[before]]
820 Foo = 2;
821 // [[after]]
824 runDataflow(
825 Code,
826 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
827 ASTContext &ASTCtx) {
828 const Environment &Before =
829 getEnvironmentAtAnnotation(Results, "before");
830 const Environment &After = getEnvironmentAtAnnotation(Results, "after");
832 const auto &ValBefore =
833 getValueForDecl<IntegerValue>(ASTCtx, Before, "Foo");
834 const auto &ValAfter =
835 getValueForDecl<IntegerValue>(ASTCtx, After, "Foo");
836 EXPECT_NE(&ValBefore, &ValAfter);
840 TEST(TransferTest, VarDeclInitAssign) {
841 std::string Code = R"(
842 void target() {
843 int Foo;
844 int Bar = Foo;
845 // [[p]]
848 runDataflow(
849 Code,
850 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
851 ASTContext &ASTCtx) {
852 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
853 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
855 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
856 ASSERT_THAT(FooDecl, NotNull());
858 const Value *FooVal = Env.getValue(*FooDecl);
859 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
861 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
862 ASSERT_THAT(BarDecl, NotNull());
864 EXPECT_EQ(Env.getValue(*BarDecl), FooVal);
868 TEST(TransferTest, VarDeclInitAssignChained) {
869 std::string Code = R"(
870 void target() {
871 int Foo;
872 int Bar;
873 int Baz = (Bar = Foo);
874 // [[p]]
877 runDataflow(
878 Code,
879 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
880 ASTContext &ASTCtx) {
881 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
882 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
884 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
885 ASSERT_THAT(FooDecl, NotNull());
887 const Value *FooVal = Env.getValue(*FooDecl);
888 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
890 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
891 ASSERT_THAT(BarDecl, NotNull());
893 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
894 ASSERT_THAT(BazDecl, NotNull());
896 EXPECT_EQ(Env.getValue(*BarDecl), FooVal);
897 EXPECT_EQ(Env.getValue(*BazDecl), FooVal);
901 TEST(TransferTest, VarDeclInitAssignPtrDeref) {
902 std::string Code = R"(
903 void target() {
904 int Foo;
905 int *Bar;
906 *(Bar) = Foo;
907 int Baz = *(Bar);
908 // [[p]]
911 runDataflow(
912 Code,
913 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
914 ASTContext &ASTCtx) {
915 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
916 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
918 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
919 ASSERT_THAT(FooDecl, NotNull());
921 const Value *FooVal = Env.getValue(*FooDecl);
922 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
924 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
925 ASSERT_THAT(BarDecl, NotNull());
927 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl));
928 EXPECT_EQ(Env.getValue(BarVal->getPointeeLoc()), FooVal);
930 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
931 ASSERT_THAT(BazDecl, NotNull());
933 EXPECT_EQ(Env.getValue(*BazDecl), FooVal);
937 TEST(TransferTest, AssignToAndFromReference) {
938 std::string Code = R"(
939 void target() {
940 int Foo;
941 int Bar;
942 int &Baz = Foo;
943 // [[p1]]
944 Baz = Bar;
945 int Qux = Baz;
946 int &Quux = Baz;
947 // [[p2]]
950 runDataflow(
951 Code,
952 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
953 ASTContext &ASTCtx) {
954 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
955 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
956 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
958 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
959 ASSERT_THAT(FooDecl, NotNull());
961 const Value *FooVal = Env1.getValue(*FooDecl);
962 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
964 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
965 ASSERT_THAT(BarDecl, NotNull());
967 const Value *BarVal = Env1.getValue(*BarDecl);
968 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
970 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
971 ASSERT_THAT(BazDecl, NotNull());
973 EXPECT_EQ(Env1.getValue(*BazDecl), FooVal);
975 EXPECT_EQ(Env2.getValue(*BazDecl), BarVal);
976 EXPECT_EQ(Env2.getValue(*FooDecl), BarVal);
978 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
979 ASSERT_THAT(QuxDecl, NotNull());
980 EXPECT_EQ(Env2.getValue(*QuxDecl), BarVal);
982 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
983 ASSERT_THAT(QuuxDecl, NotNull());
984 EXPECT_EQ(Env2.getValue(*QuuxDecl), BarVal);
988 TEST(TransferTest, MultipleParamDecls) {
989 std::string Code = R"(
990 void target(int Foo, int Bar) {
991 (void)0;
992 // [[p]]
995 runDataflow(
996 Code,
997 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
998 ASTContext &ASTCtx) {
999 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1000 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1002 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1003 ASSERT_THAT(FooDecl, NotNull());
1005 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
1006 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
1008 const Value *FooVal = Env.getValue(*FooLoc);
1009 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
1011 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1012 ASSERT_THAT(BarDecl, NotNull());
1014 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
1015 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1017 const Value *BarVal = Env.getValue(*BarLoc);
1018 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1022 TEST(TransferTest, StructParamDecl) {
1023 std::string Code = R"(
1024 struct A {
1025 int Bar;
1028 void target(A Foo) {
1029 (void)Foo.Bar;
1030 // [[p]]
1033 runDataflow(
1034 Code,
1035 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1036 ASTContext &ASTCtx) {
1037 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1038 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1040 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1041 ASSERT_THAT(FooDecl, NotNull());
1043 ASSERT_TRUE(FooDecl->getType()->isStructureType());
1044 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1046 FieldDecl *BarDecl = nullptr;
1047 for (FieldDecl *Field : FooFields) {
1048 if (Field->getNameAsString() == "Bar") {
1049 BarDecl = Field;
1050 } else {
1051 FAIL() << "Unexpected field: " << Field->getNameAsString();
1054 ASSERT_THAT(BarDecl, NotNull());
1056 const auto *FooLoc =
1057 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
1058 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
1062 TEST(TransferTest, ReferenceParamDecl) {
1063 std::string Code = R"(
1064 struct A {};
1066 void target(A &Foo) {
1067 (void)0;
1068 // [[p]]
1071 runDataflow(
1072 Code,
1073 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1074 ASTContext &ASTCtx) {
1075 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1076 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1078 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1079 ASSERT_THAT(FooDecl, NotNull());
1081 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
1082 ASSERT_TRUE(isa_and_nonnull<RecordStorageLocation>(FooLoc));
1084 const Value *FooReferentVal = Env.getValue(*FooLoc);
1085 EXPECT_TRUE(isa_and_nonnull<RecordValue>(FooReferentVal));
1089 TEST(TransferTest, PointerParamDecl) {
1090 std::string Code = R"(
1091 struct A {};
1093 void target(A *Foo) {
1094 (void)0;
1095 // [[p]]
1098 runDataflow(
1099 Code,
1100 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1101 ASTContext &ASTCtx) {
1102 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1103 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1105 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1106 ASSERT_THAT(FooDecl, NotNull());
1108 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
1109 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
1111 const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));
1112 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
1113 EXPECT_TRUE(isa<RecordStorageLocation>(&FooPointeeLoc));
1115 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
1116 EXPECT_TRUE(isa_and_nonnull<RecordValue>(FooPointeeVal));
1120 TEST(TransferTest, StructMember) {
1121 std::string Code = R"(
1122 struct A {
1123 int Bar;
1126 void target(A Foo) {
1127 int Baz = Foo.Bar;
1128 // [[p]]
1131 runDataflow(
1132 Code,
1133 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1134 ASTContext &ASTCtx) {
1135 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1136 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1138 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1139 ASSERT_THAT(FooDecl, NotNull());
1141 ASSERT_TRUE(FooDecl->getType()->isStructureType());
1142 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1144 FieldDecl *BarDecl = nullptr;
1145 for (FieldDecl *Field : FooFields) {
1146 if (Field->getNameAsString() == "Bar") {
1147 BarDecl = Field;
1148 } else {
1149 FAIL() << "Unexpected field: " << Field->getNameAsString();
1152 ASSERT_THAT(BarDecl, NotNull());
1154 const auto *FooLoc =
1155 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
1156 const auto *BarVal =
1157 cast<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env));
1159 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1160 ASSERT_THAT(BazDecl, NotNull());
1162 EXPECT_EQ(Env.getValue(*BazDecl), BarVal);
1166 TEST(TransferTest, StructMemberEnum) {
1167 std::string Code = R"(
1168 struct A {
1169 int Bar;
1170 enum E { ONE, TWO };
1173 void target(A Foo) {
1174 A::E Baz = Foo.ONE;
1175 // [[p]]
1178 // Minimal expectations -- we're just testing that it doesn't crash, since
1179 // enums aren't interpreted.
1180 runDataflow(
1181 Code,
1182 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1183 ASTContext &ASTCtx) {
1184 EXPECT_THAT(Results.keys(), UnorderedElementsAre("p"));
1188 TEST(TransferTest, DerivedBaseMemberClass) {
1189 std::string Code = R"(
1190 class A {
1191 int ADefault;
1192 protected:
1193 int AProtected;
1194 private:
1195 int APrivate;
1196 public:
1197 int APublic;
1199 private:
1200 friend void target();
1203 class B : public A {
1204 int BDefault;
1205 protected:
1206 int BProtected;
1207 private:
1208 int BPrivate;
1210 private:
1211 friend void target();
1214 void target() {
1215 B Foo;
1216 (void)Foo.ADefault;
1217 (void)Foo.AProtected;
1218 (void)Foo.APrivate;
1219 (void)Foo.APublic;
1220 (void)Foo.BDefault;
1221 (void)Foo.BProtected;
1222 (void)Foo.BPrivate;
1223 // [[p]]
1226 runDataflow(
1227 Code,
1228 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1229 ASTContext &ASTCtx) {
1230 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1231 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1233 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1234 ASSERT_THAT(FooDecl, NotNull());
1235 ASSERT_TRUE(FooDecl->getType()->isRecordType());
1237 // Derived-class fields.
1238 const FieldDecl *BDefaultDecl = nullptr;
1239 const FieldDecl *BProtectedDecl = nullptr;
1240 const FieldDecl *BPrivateDecl = nullptr;
1241 for (const FieldDecl *Field :
1242 FooDecl->getType()->getAsRecordDecl()->fields()) {
1243 if (Field->getNameAsString() == "BDefault") {
1244 BDefaultDecl = Field;
1245 } else if (Field->getNameAsString() == "BProtected") {
1246 BProtectedDecl = Field;
1247 } else if (Field->getNameAsString() == "BPrivate") {
1248 BPrivateDecl = Field;
1249 } else {
1250 FAIL() << "Unexpected field: " << Field->getNameAsString();
1253 ASSERT_THAT(BDefaultDecl, NotNull());
1254 ASSERT_THAT(BProtectedDecl, NotNull());
1255 ASSERT_THAT(BPrivateDecl, NotNull());
1257 // Base-class fields.
1258 const FieldDecl *ADefaultDecl = nullptr;
1259 const FieldDecl *APrivateDecl = nullptr;
1260 const FieldDecl *AProtectedDecl = nullptr;
1261 const FieldDecl *APublicDecl = nullptr;
1262 for (const clang::CXXBaseSpecifier &Base :
1263 FooDecl->getType()->getAsCXXRecordDecl()->bases()) {
1264 QualType BaseType = Base.getType();
1265 ASSERT_TRUE(BaseType->isRecordType());
1266 for (const FieldDecl *Field : BaseType->getAsRecordDecl()->fields()) {
1267 if (Field->getNameAsString() == "ADefault") {
1268 ADefaultDecl = Field;
1269 } else if (Field->getNameAsString() == "AProtected") {
1270 AProtectedDecl = Field;
1271 } else if (Field->getNameAsString() == "APrivate") {
1272 APrivateDecl = Field;
1273 } else if (Field->getNameAsString() == "APublic") {
1274 APublicDecl = Field;
1275 } else {
1276 FAIL() << "Unexpected field: " << Field->getNameAsString();
1280 ASSERT_THAT(ADefaultDecl, NotNull());
1281 ASSERT_THAT(AProtectedDecl, NotNull());
1282 ASSERT_THAT(APrivateDecl, NotNull());
1283 ASSERT_THAT(APublicDecl, NotNull());
1285 ASSERT_TRUE(
1286 isa<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)));
1290 static void derivedBaseMemberExpectations(
1291 const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1292 ASTContext &ASTCtx) {
1293 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1294 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1296 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1297 ASSERT_THAT(FooDecl, NotNull());
1299 ASSERT_TRUE(FooDecl->getType()->isRecordType());
1300 const FieldDecl *BarDecl = nullptr;
1301 for (const clang::CXXBaseSpecifier &Base :
1302 FooDecl->getType()->getAsCXXRecordDecl()->bases()) {
1303 QualType BaseType = Base.getType();
1304 ASSERT_TRUE(BaseType->isStructureType());
1306 for (const FieldDecl *Field : BaseType->getAsRecordDecl()->fields()) {
1307 if (Field->getNameAsString() == "Bar") {
1308 BarDecl = Field;
1309 } else {
1310 FAIL() << "Unexpected field: " << Field->getNameAsString();
1314 ASSERT_THAT(BarDecl, NotNull());
1316 const auto &FooLoc =
1317 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
1318 const auto &FooVal = *cast<RecordValue>(Env.getValue(FooLoc));
1319 EXPECT_EQ(&FooVal.getLoc(), &FooLoc);
1322 TEST(TransferTest, DerivedBaseMemberStructDefault) {
1323 std::string Code = R"(
1324 struct A {
1325 int Bar;
1327 struct B : public A {
1330 void target() {
1331 B Foo;
1332 (void)Foo.Bar;
1333 // [[p]]
1336 runDataflow(Code, derivedBaseMemberExpectations);
1339 TEST(TransferTest, DerivedBaseMemberPrivateFriend) {
1340 // Include an access to `Foo.Bar` to verify the analysis doesn't crash on that
1341 // access.
1342 std::string Code = R"(
1343 struct A {
1344 private:
1345 friend void target();
1346 int Bar;
1348 struct B : public A {
1351 void target() {
1352 B Foo;
1353 (void)Foo.Bar;
1354 // [[p]]
1357 runDataflow(Code, derivedBaseMemberExpectations);
1360 TEST(TransferTest, ClassMember) {
1361 std::string Code = R"(
1362 class A {
1363 public:
1364 int Bar;
1367 void target(A Foo) {
1368 int Baz = Foo.Bar;
1369 // [[p]]
1372 runDataflow(
1373 Code,
1374 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1375 ASTContext &ASTCtx) {
1376 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1377 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1379 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1380 ASSERT_THAT(FooDecl, NotNull());
1382 ASSERT_TRUE(FooDecl->getType()->isClassType());
1383 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1385 FieldDecl *BarDecl = nullptr;
1386 for (FieldDecl *Field : FooFields) {
1387 if (Field->getNameAsString() == "Bar") {
1388 BarDecl = Field;
1389 } else {
1390 FAIL() << "Unexpected field: " << Field->getNameAsString();
1393 ASSERT_THAT(BarDecl, NotNull());
1395 const auto *FooLoc =
1396 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
1397 const auto *BarVal =
1398 cast<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env));
1400 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1401 ASSERT_THAT(BazDecl, NotNull());
1403 EXPECT_EQ(Env.getValue(*BazDecl), BarVal);
1407 TEST(TransferTest, BaseClassInitializer) {
1408 using ast_matchers::cxxConstructorDecl;
1409 using ast_matchers::hasName;
1410 using ast_matchers::ofClass;
1412 std::string Code = R"(
1413 class A {
1414 public:
1415 A(int I) : Bar(I) {}
1416 int Bar;
1419 class B : public A {
1420 public:
1421 B(int I) : A(I) {
1422 (void)0;
1423 // [[p]]
1427 ASSERT_THAT_ERROR(
1428 checkDataflow<NoopAnalysis>(
1429 AnalysisInputs<NoopAnalysis>(
1430 Code, cxxConstructorDecl(ofClass(hasName("B"))),
1431 [](ASTContext &C, Environment &) { return NoopAnalysis(C); })
1432 .withASTBuildArgs(
1433 {"-fsyntax-only", "-fno-delayed-template-parsing",
1434 "-std=" + std::string(LangStandard::getLangStandardForKind(
1435 LangStandard::lang_cxx17)
1436 .getName())}),
1437 /*VerifyResults=*/
1438 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1439 const AnalysisOutputs &) {
1440 // Regression test to verify that base-class initializers do not
1441 // trigger an assertion. If we add support for such initializers in
1442 // the future, we can expand this test to check more specific
1443 // properties.
1444 EXPECT_THAT(Results.keys(), UnorderedElementsAre("p"));
1446 llvm::Succeeded());
1449 TEST(TransferTest, StructModeledFieldsWithAccessor) {
1450 std::string Code = R"(
1451 class S {
1452 int *Ptr;
1453 int *PtrNonConst;
1454 int Int;
1455 int IntWithInc;
1456 int IntNotAccessed;
1457 int IntRef;
1458 public:
1459 int *getPtr() const { return Ptr; }
1460 int *getPtrNonConst() { return PtrNonConst; }
1461 int getInt(int i) const { return Int; }
1462 int getWithInc(int i) { IntWithInc += i; return IntWithInc; }
1463 int getIntNotAccessed() const { return IntNotAccessed; }
1464 int getIntNoDefinition() const;
1465 int &getIntRef() { return IntRef; }
1466 void returnVoid() const { return; }
1469 void target() {
1470 S s;
1471 int *p1 = s.getPtr();
1472 int *p2 = s.getPtrNonConst();
1473 int i1 = s.getInt(1);
1474 int i2 = s.getWithInc(1);
1475 int i3 = s.getIntNoDefinition();
1476 int &iref = s.getIntRef();
1478 // Regression test: Don't crash on an indirect call (which doesn't have
1479 // an associated `CXXMethodDecl`).
1480 auto ptr_to_member_fn = &S::getPtr;
1481 p1 = (s.*ptr_to_member_fn)();
1483 // Regression test: Don't crash on a return statement without a value.
1484 s.returnVoid();
1485 // [[p]]
1488 runDataflow(
1489 Code,
1490 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1491 ASTContext &ASTCtx) {
1492 const Environment &Env =
1493 getEnvironmentAtAnnotation(Results, "p");
1494 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s");
1495 std::vector<const ValueDecl*> Fields;
1496 for (auto [Field, _] : SLoc.children())
1497 Fields.push_back(Field);
1498 // Only the fields that have simple accessor methods (that have a
1499 // single statement body that returns the member variable) should be
1500 // modeled.
1501 ASSERT_THAT(Fields, UnorderedElementsAre(
1502 findValueDecl(ASTCtx, "Ptr"), findValueDecl(ASTCtx, "PtrNonConst"),
1503 findValueDecl(ASTCtx, "Int"), findValueDecl(ASTCtx, "IntRef")));
1507 TEST(TransferTest, StructModeledFieldsWithComplicatedInheritance) {
1508 std::string Code = R"(
1509 struct Base1 {
1510 int base1_1;
1511 int base1_2;
1513 struct Intermediate : Base1 {
1514 int intermediate_1;
1515 int intermediate_2;
1517 struct Base2 {
1518 int base2_1;
1519 int base2_2;
1521 struct MostDerived : public Intermediate, Base2 {
1522 int most_derived_1;
1523 int most_derived_2;
1526 void target() {
1527 MostDerived MD;
1528 MD.base1_2 = 1;
1529 MD.intermediate_2 = 1;
1530 MD.base2_2 = 1;
1531 MD.most_derived_2 = 1;
1532 // [[p]]
1535 runDataflow(
1536 Code,
1537 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1538 ASTContext &ASTCtx) {
1539 const Environment &Env =
1540 getEnvironmentAtAnnotation(Results, "p");
1542 // Only the accessed fields should exist in the model.
1543 auto &MDLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "MD");
1544 std::vector<const ValueDecl*> Fields;
1545 for (auto [Field, _] : MDLoc.children())
1546 Fields.push_back(Field);
1547 ASSERT_THAT(Fields, UnorderedElementsAre(
1548 findValueDecl(ASTCtx, "base1_2"),
1549 findValueDecl(ASTCtx, "intermediate_2"),
1550 findValueDecl(ASTCtx, "base2_2"),
1551 findValueDecl(ASTCtx, "most_derived_2")));
1555 TEST(TransferTest, StructInitializerListWithComplicatedInheritance) {
1556 std::string Code = R"(
1557 struct Base1 {
1558 int base1;
1560 struct Intermediate : Base1 {
1561 int intermediate;
1563 struct Base2 {
1564 int base2;
1566 struct MostDerived : public Intermediate, Base2 {
1567 int most_derived;
1570 void target() {
1571 MostDerived MD = {};
1572 // [[p]]
1575 runDataflow(
1576 Code,
1577 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1578 ASTContext &ASTCtx) {
1579 const Environment &Env =
1580 getEnvironmentAtAnnotation(Results, "p");
1582 // When a struct is initialized with a initializer list, all the
1583 // fields are considered "accessed", and therefore do exist.
1584 auto &MD = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "MD");
1585 ASSERT_THAT(cast<IntegerValue>(
1586 getFieldValue(&MD, *findValueDecl(ASTCtx, "base1"), Env)),
1587 NotNull());
1588 ASSERT_THAT(cast<IntegerValue>(
1589 getFieldValue(&MD, *findValueDecl(ASTCtx, "intermediate"), Env)),
1590 NotNull());
1591 ASSERT_THAT(cast<IntegerValue>(
1592 getFieldValue(&MD, *findValueDecl(ASTCtx, "base2"), Env)),
1593 NotNull());
1594 ASSERT_THAT(cast<IntegerValue>(
1595 getFieldValue(&MD, *findValueDecl(ASTCtx, "most_derived"), Env)),
1596 NotNull());
1600 TEST(TransferTest, ReferenceMember) {
1601 std::string Code = R"(
1602 struct A {
1603 int &Bar;
1606 void target(A Foo) {
1607 int Baz = Foo.Bar;
1608 // [[p]]
1611 runDataflow(
1612 Code,
1613 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1614 ASTContext &ASTCtx) {
1615 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1616 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1618 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1619 ASSERT_THAT(FooDecl, NotNull());
1621 ASSERT_TRUE(FooDecl->getType()->isStructureType());
1622 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1624 FieldDecl *BarDecl = nullptr;
1625 for (FieldDecl *Field : FooFields) {
1626 if (Field->getNameAsString() == "Bar") {
1627 BarDecl = Field;
1628 } else {
1629 FAIL() << "Unexpected field: " << Field->getNameAsString();
1632 ASSERT_THAT(BarDecl, NotNull());
1634 const auto *FooLoc =
1635 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
1636 const auto *BarReferentVal =
1637 cast<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env));
1639 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1640 ASSERT_THAT(BazDecl, NotNull());
1642 EXPECT_EQ(Env.getValue(*BazDecl), BarReferentVal);
1646 TEST(TransferTest, StructThisMember) {
1647 std::string Code = R"(
1648 struct A {
1649 int Bar;
1651 struct B {
1652 int Baz;
1655 B Qux;
1657 void target() {
1658 int Foo = Bar;
1659 int Quux = Qux.Baz;
1660 // [[p]]
1664 runDataflow(
1665 Code,
1666 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1667 ASTContext &ASTCtx) {
1668 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1669 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1671 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
1672 ASSERT_THAT(ThisLoc, NotNull());
1674 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1675 ASSERT_THAT(BarDecl, NotNull());
1677 const auto *BarLoc =
1678 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl));
1679 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1681 const Value *BarVal = Env.getValue(*BarLoc);
1682 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1684 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1685 ASSERT_THAT(FooDecl, NotNull());
1686 EXPECT_EQ(Env.getValue(*FooDecl), BarVal);
1688 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1689 ASSERT_THAT(QuxDecl, NotNull());
1691 ASSERT_TRUE(QuxDecl->getType()->isStructureType());
1692 auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields();
1694 FieldDecl *BazDecl = nullptr;
1695 for (FieldDecl *Field : QuxFields) {
1696 if (Field->getNameAsString() == "Baz") {
1697 BazDecl = Field;
1698 } else {
1699 FAIL() << "Unexpected field: " << Field->getNameAsString();
1702 ASSERT_THAT(BazDecl, NotNull());
1704 const auto *QuxLoc =
1705 cast<RecordStorageLocation>(ThisLoc->getChild(*QuxDecl));
1706 EXPECT_THAT(dyn_cast<RecordValue>(Env.getValue(*QuxLoc)), NotNull());
1708 const auto *BazVal =
1709 cast<IntegerValue>(getFieldValue(QuxLoc, *BazDecl, Env));
1711 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
1712 ASSERT_THAT(QuuxDecl, NotNull());
1713 EXPECT_EQ(Env.getValue(*QuuxDecl), BazVal);
1717 TEST(TransferTest, ClassThisMember) {
1718 std::string Code = R"(
1719 class A {
1720 int Bar;
1722 class B {
1723 public:
1724 int Baz;
1727 B Qux;
1729 void target() {
1730 int Foo = Bar;
1731 int Quux = Qux.Baz;
1732 // [[p]]
1736 runDataflow(
1737 Code,
1738 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1739 ASTContext &ASTCtx) {
1740 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1741 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1743 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
1745 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1746 ASSERT_THAT(BarDecl, NotNull());
1748 const auto *BarLoc =
1749 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl));
1750 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1752 const Value *BarVal = Env.getValue(*BarLoc);
1753 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1755 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1756 ASSERT_THAT(FooDecl, NotNull());
1757 EXPECT_EQ(Env.getValue(*FooDecl), BarVal);
1759 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1760 ASSERT_THAT(QuxDecl, NotNull());
1762 ASSERT_TRUE(QuxDecl->getType()->isClassType());
1763 auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields();
1765 FieldDecl *BazDecl = nullptr;
1766 for (FieldDecl *Field : QuxFields) {
1767 if (Field->getNameAsString() == "Baz") {
1768 BazDecl = Field;
1769 } else {
1770 FAIL() << "Unexpected field: " << Field->getNameAsString();
1773 ASSERT_THAT(BazDecl, NotNull());
1775 const auto *QuxLoc =
1776 cast<RecordStorageLocation>(ThisLoc->getChild(*QuxDecl));
1777 EXPECT_THAT(dyn_cast<RecordValue>(Env.getValue(*QuxLoc)), NotNull());
1779 const auto *BazVal =
1780 cast<IntegerValue>(getFieldValue(QuxLoc, *BazDecl, Env));
1782 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
1783 ASSERT_THAT(QuuxDecl, NotNull());
1784 EXPECT_EQ(Env.getValue(*QuuxDecl), BazVal);
1788 TEST(TransferTest, UnionThisMember) {
1789 std::string Code = R"(
1790 union A {
1791 int Foo;
1792 int Bar;
1794 void target() {
1795 A a;
1796 // Mention the fields to ensure they're included in the analysis.
1797 (void)a.Foo;
1798 (void)a.Bar;
1799 // [[p]]
1803 runDataflow(
1804 Code,
1805 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1806 ASTContext &ASTCtx) {
1807 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1808 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1810 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
1811 ASSERT_THAT(ThisLoc, NotNull());
1813 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1814 ASSERT_THAT(FooDecl, NotNull());
1816 const auto *FooLoc =
1817 cast<ScalarStorageLocation>(ThisLoc->getChild(*FooDecl));
1818 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
1820 const Value *FooVal = Env.getValue(*FooLoc);
1821 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
1823 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1824 ASSERT_THAT(BarDecl, NotNull());
1826 const auto *BarLoc =
1827 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl));
1828 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1830 const Value *BarVal = Env.getValue(*BarLoc);
1831 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1835 TEST(TransferTest, StructThisInLambda) {
1836 std::string ThisCaptureCode = R"(
1837 struct A {
1838 void frob() {
1839 [this]() {
1840 int Foo = Bar;
1841 // [[p1]]
1842 }();
1845 int Bar;
1848 runDataflow(
1849 ThisCaptureCode,
1850 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1851 ASTContext &ASTCtx) {
1852 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1"));
1853 const Environment &Env = getEnvironmentAtAnnotation(Results, "p1");
1855 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
1856 ASSERT_THAT(ThisLoc, NotNull());
1858 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1859 ASSERT_THAT(BarDecl, NotNull());
1861 const auto *BarLoc =
1862 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl));
1863 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1865 const Value *BarVal = Env.getValue(*BarLoc);
1866 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1868 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1869 ASSERT_THAT(FooDecl, NotNull());
1870 EXPECT_EQ(Env.getValue(*FooDecl), BarVal);
1872 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()");
1874 std::string RefCaptureDefaultCode = R"(
1875 struct A {
1876 void frob() {
1877 [&]() {
1878 int Foo = Bar;
1879 // [[p2]]
1880 }();
1883 int Bar;
1886 runDataflow(
1887 RefCaptureDefaultCode,
1888 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1889 ASTContext &ASTCtx) {
1890 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p2"));
1891 const Environment &Env = getEnvironmentAtAnnotation(Results, "p2");
1893 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
1894 ASSERT_THAT(ThisLoc, NotNull());
1896 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1897 ASSERT_THAT(BarDecl, NotNull());
1899 const auto *BarLoc =
1900 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl));
1901 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1903 const Value *BarVal = Env.getValue(*BarLoc);
1904 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1906 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1907 ASSERT_THAT(FooDecl, NotNull());
1908 EXPECT_EQ(Env.getValue(*FooDecl), BarVal);
1910 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()");
1912 std::string FreeFunctionLambdaCode = R"(
1913 void foo() {
1914 int Bar;
1915 [&]() {
1916 int Foo = Bar;
1917 // [[p3]]
1918 }();
1921 runDataflow(
1922 FreeFunctionLambdaCode,
1923 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1924 ASTContext &ASTCtx) {
1925 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p3"));
1926 const Environment &Env = getEnvironmentAtAnnotation(Results, "p3");
1928 EXPECT_THAT(Env.getThisPointeeStorageLocation(), IsNull());
1930 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()");
1933 TEST(TransferTest, ConstructorInitializer) {
1934 std::string Code = R"(
1935 struct target {
1936 int Bar;
1938 target(int Foo) : Bar(Foo) {
1939 int Qux = Bar;
1940 // [[p]]
1944 runDataflow(
1945 Code,
1946 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1947 ASTContext &ASTCtx) {
1948 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1949 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1951 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
1952 ASSERT_THAT(ThisLoc, NotNull());
1954 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1955 ASSERT_THAT(FooDecl, NotNull());
1957 const auto *FooVal = cast<IntegerValue>(Env.getValue(*FooDecl));
1959 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1960 ASSERT_THAT(QuxDecl, NotNull());
1961 EXPECT_EQ(Env.getValue(*QuxDecl), FooVal);
1965 TEST(TransferTest, DefaultInitializer) {
1966 std::string Code = R"(
1967 struct target {
1968 int Bar;
1969 int Baz = Bar;
1971 target(int Foo) : Bar(Foo) {
1972 int Qux = Baz;
1973 // [[p]]
1977 runDataflow(
1978 Code,
1979 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1980 ASTContext &ASTCtx) {
1981 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
1982 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1984 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
1985 ASSERT_THAT(ThisLoc, NotNull());
1987 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1988 ASSERT_THAT(FooDecl, NotNull());
1990 const auto *FooVal = cast<IntegerValue>(Env.getValue(*FooDecl));
1992 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1993 ASSERT_THAT(QuxDecl, NotNull());
1994 EXPECT_EQ(Env.getValue(*QuxDecl), FooVal);
1998 TEST(TransferTest, DefaultInitializerReference) {
1999 std::string Code = R"(
2000 struct target {
2001 int &Bar;
2002 int &Baz = Bar;
2004 target(int &Foo) : Bar(Foo) {
2005 int &Qux = Baz;
2006 // [[p]]
2010 runDataflow(
2011 Code,
2012 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2013 ASTContext &ASTCtx) {
2014 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2015 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2017 const auto *ThisLoc = Env.getThisPointeeStorageLocation();
2018 ASSERT_THAT(ThisLoc, NotNull());
2020 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2021 ASSERT_THAT(FooDecl, NotNull());
2023 const auto *FooLoc = Env.getStorageLocation(*FooDecl);
2025 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
2026 ASSERT_THAT(QuxDecl, NotNull());
2028 const auto *QuxLoc = Env.getStorageLocation(*QuxDecl);
2029 EXPECT_EQ(QuxLoc, FooLoc);
2033 TEST(TransferTest, TemporaryObject) {
2034 std::string Code = R"(
2035 struct A {
2036 int Bar;
2039 void target() {
2040 A Foo = A();
2041 (void)Foo.Bar;
2042 // [[p]]
2045 runDataflow(
2046 Code,
2047 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2048 ASTContext &ASTCtx) {
2049 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2050 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2052 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2053 ASSERT_THAT(FooDecl, NotNull());
2055 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2056 ASSERT_THAT(BarDecl, NotNull());
2058 const auto *FooLoc =
2059 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2060 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
2064 TEST(TransferTest, ElidableConstructor) {
2065 // This test is effectively the same as TransferTest.TemporaryObject, but
2066 // the code is compiled as C++ 14.
2067 std::string Code = R"(
2068 struct A {
2069 int Bar;
2072 void target() {
2073 A Foo = A();
2074 (void)Foo.Bar;
2075 // [[p]]
2078 runDataflow(
2079 Code,
2080 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2081 ASTContext &ASTCtx) {
2082 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2083 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2085 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2086 ASSERT_THAT(FooDecl, NotNull());
2088 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2089 ASSERT_THAT(BarDecl, NotNull());
2091 const auto *FooLoc =
2092 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2093 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
2095 LangStandard::lang_cxx14);
2098 TEST(TransferTest, AssignmentOperator) {
2099 std::string Code = R"(
2100 struct A {
2101 int Baz;
2104 void target() {
2105 A Foo = { 1 };
2106 A Bar = { 2 };
2107 // [[p1]]
2108 Foo = Bar;
2109 // [[p2]]
2110 Foo.Baz = 3;
2111 // [[p3]]
2114 runDataflow(
2115 Code,
2116 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2117 ASTContext &ASTCtx) {
2118 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2119 ASSERT_THAT(FooDecl, NotNull());
2121 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2122 ASSERT_THAT(BarDecl, NotNull());
2124 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2125 ASSERT_THAT(BazDecl, NotNull());
2127 // Before copy assignment.
2129 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
2131 const auto *FooLoc1 =
2132 cast<RecordStorageLocation>(Env1.getStorageLocation(*FooDecl));
2133 const auto *BarLoc1 =
2134 cast<RecordStorageLocation>(Env1.getStorageLocation(*BarDecl));
2135 EXPECT_FALSE(recordsEqual(*FooLoc1, *BarLoc1, Env1));
2137 const auto *FooBazVal1 =
2138 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env1));
2139 const auto *BarBazVal1 =
2140 cast<IntegerValue>(getFieldValue(BarLoc1, *BazDecl, Env1));
2141 EXPECT_NE(FooBazVal1, BarBazVal1);
2144 // After copy assignment.
2146 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
2148 const auto *FooLoc2 =
2149 cast<RecordStorageLocation>(Env2.getStorageLocation(*FooDecl));
2150 const auto *BarLoc2 =
2151 cast<RecordStorageLocation>(Env2.getStorageLocation(*BarDecl));
2153 const auto *FooVal2 = cast<RecordValue>(Env2.getValue(*FooLoc2));
2154 const auto *BarVal2 = cast<RecordValue>(Env2.getValue(*BarLoc2));
2155 EXPECT_NE(FooVal2, BarVal2);
2157 EXPECT_TRUE(recordsEqual(*FooLoc2, *BarLoc2, Env2));
2159 const auto *FooBazVal2 =
2160 cast<IntegerValue>(getFieldValue(FooLoc2, *BazDecl, Env2));
2161 const auto *BarBazVal2 =
2162 cast<IntegerValue>(getFieldValue(BarLoc2, *BazDecl, Env2));
2163 EXPECT_EQ(FooBazVal2, BarBazVal2);
2166 // After value update.
2168 const Environment &Env3 = getEnvironmentAtAnnotation(Results, "p3");
2170 const auto *FooLoc3 =
2171 cast<RecordStorageLocation>(Env3.getStorageLocation(*FooDecl));
2172 const auto *BarLoc3 =
2173 cast<RecordStorageLocation>(Env3.getStorageLocation(*BarDecl));
2174 EXPECT_FALSE(recordsEqual(*FooLoc3, *BarLoc3, Env3));
2176 const auto *FooBazVal3 =
2177 cast<IntegerValue>(getFieldValue(FooLoc3, *BazDecl, Env3));
2178 const auto *BarBazVal3 =
2179 cast<IntegerValue>(getFieldValue(BarLoc3, *BazDecl, Env3));
2180 EXPECT_NE(FooBazVal3, BarBazVal3);
2185 TEST(TransferTest, AssignmentOperatorFromBase) {
2186 // This is a crash repro. We don't model the copy this case, so no
2187 // expectations on the copied field of the base class are checked.
2188 std::string Code = R"(
2189 struct Base {
2190 int base;
2192 struct Derived : public Base {
2193 using Base::operator=;
2194 int derived;
2196 void target(Base B, Derived D) {
2197 D.base = 1;
2198 D.derived = 1;
2199 D = B;
2200 // [[p]]
2203 runDataflow(
2204 Code,
2205 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2206 ASTContext &ASTCtx) {});
2209 TEST(TransferTest, AssignmentOperatorFromCallResult) {
2210 std::string Code = R"(
2211 struct A {};
2212 A ReturnA();
2214 void target() {
2215 A MyA;
2216 MyA = ReturnA();
2219 runDataflow(
2220 Code,
2221 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2222 ASTContext &ASTCtx) {
2223 // As of this writing, we don't produce a `Value` for the call
2224 // `ReturnA()`. The only condition we're testing for is that the
2225 // analysis should not crash in this case.
2229 TEST(TransferTest, AssignmentOperatorWithInitAndInheritance) {
2230 // This is a crash repro.
2231 std::string Code = R"(
2232 struct B { int Foo; };
2233 struct S : public B {};
2234 void target() {
2235 S S1 = { 1 };
2236 S S2;
2237 S S3;
2238 S1 = S2; // Only Dst has InitListExpr.
2239 S3 = S1; // Only Src has InitListExpr.
2240 // [[p]]
2243 runDataflow(
2244 Code,
2245 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2246 ASTContext &ASTCtx) {});
2249 TEST(TransferTest, CopyConstructor) {
2250 std::string Code = R"(
2251 struct A {
2252 int Baz;
2255 void target() {
2256 A Foo = { 1 };
2257 A Bar = Foo;
2258 // [[after_copy]]
2259 Foo.Baz = 2;
2260 // [[after_update]]
2263 runDataflow(
2264 Code,
2265 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2266 ASTContext &ASTCtx) {
2267 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2268 ASSERT_THAT(FooDecl, NotNull());
2270 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2271 ASSERT_THAT(BarDecl, NotNull());
2273 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2274 ASSERT_THAT(BazDecl, NotNull());
2276 // after_copy
2278 const Environment &Env =
2279 getEnvironmentAtAnnotation(Results, "after_copy");
2281 const auto *FooLoc =
2282 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2283 const auto *BarLoc =
2284 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl));
2286 // `Foo` and `Bar` have different `RecordValue`s associated with them.
2287 const auto *FooVal = cast<RecordValue>(Env.getValue(*FooLoc));
2288 const auto *BarVal = cast<RecordValue>(Env.getValue(*BarLoc));
2289 EXPECT_NE(FooVal, BarVal);
2291 // But the records compare equal.
2292 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env));
2294 // In particular, the value of `Baz` in both records is the same.
2295 const auto *FooBazVal =
2296 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env));
2297 const auto *BarBazVal =
2298 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env));
2299 EXPECT_EQ(FooBazVal, BarBazVal);
2302 // after_update
2304 const Environment &Env =
2305 getEnvironmentAtAnnotation(Results, "after_update");
2307 const auto *FooLoc =
2308 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2309 const auto *BarLoc =
2310 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl));
2312 EXPECT_FALSE(recordsEqual(*FooLoc, *BarLoc, Env));
2314 const auto *FooBazVal =
2315 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env));
2316 const auto *BarBazVal =
2317 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env));
2318 EXPECT_NE(FooBazVal, BarBazVal);
2323 TEST(TransferTest, CopyConstructorWithDefaultArgument) {
2324 std::string Code = R"(
2325 struct A {
2326 int Baz;
2327 A() = default;
2328 A(const A& a, bool def = true) { Baz = a.Baz; }
2331 void target() {
2332 A Foo;
2333 (void)Foo.Baz;
2334 A Bar = Foo;
2335 // [[p]]
2338 runDataflow(
2339 Code,
2340 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2341 ASTContext &ASTCtx) {
2342 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2343 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2345 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2346 ASSERT_THAT(FooDecl, NotNull());
2348 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2349 ASSERT_THAT(BarDecl, NotNull());
2351 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2352 ASSERT_THAT(BazDecl, NotNull());
2354 const auto *FooLoc =
2355 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2356 const auto *BarLoc =
2357 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl));
2358 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env));
2360 const auto *FooBazVal =
2361 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env));
2362 const auto *BarBazVal =
2363 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env));
2364 EXPECT_EQ(FooBazVal, BarBazVal);
2368 TEST(TransferTest, CopyConstructorWithParens) {
2369 std::string Code = R"(
2370 struct A {
2371 int Baz;
2374 void target() {
2375 A Foo;
2376 (void)Foo.Baz;
2377 A Bar((A(Foo)));
2378 // [[p]]
2381 runDataflow(
2382 Code,
2383 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2384 ASTContext &ASTCtx) {
2385 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2386 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2388 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2389 ASSERT_THAT(FooDecl, NotNull());
2391 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2392 ASSERT_THAT(BarDecl, NotNull());
2394 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2395 ASSERT_THAT(BazDecl, NotNull());
2397 const auto *FooLoc =
2398 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2399 const auto *BarLoc =
2400 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl));
2401 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env));
2403 const auto *FooBazVal =
2404 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env));
2405 const auto *BarBazVal =
2406 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env));
2407 EXPECT_EQ(FooBazVal, BarBazVal);
2411 TEST(TransferTest, CopyConstructorWithInitializerListAsSyntacticSugar) {
2412 std::string Code = R"(
2413 struct A {
2414 int Baz;
2416 void target() {
2417 A Foo = {3};
2418 (void)Foo.Baz;
2419 A Bar = {A(Foo)};
2420 // [[p]]
2423 runDataflow(
2424 Code,
2425 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2426 ASTContext &ASTCtx) {
2427 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2429 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2431 const auto &FooLoc =
2432 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo");
2433 const auto &BarLoc =
2434 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar");
2436 const auto *FooBazVal =
2437 cast<IntegerValue>(getFieldValue(&FooLoc, *BazDecl, Env));
2438 const auto *BarBazVal =
2439 cast<IntegerValue>(getFieldValue(&BarLoc, *BazDecl, Env));
2440 EXPECT_EQ(FooBazVal, BarBazVal);
2444 TEST(TransferTest, CopyConstructorArgIsRefReturnedByFunction) {
2445 // This is a crash repro.
2446 std::string Code = R"(
2447 struct S {};
2448 const S &returnsSRef();
2449 void target() {
2450 S s(returnsSRef());
2453 runDataflow(
2454 Code,
2455 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2456 ASTContext &ASTCtx) {});
2459 TEST(TransferTest, MoveConstructor) {
2460 std::string Code = R"(
2461 namespace std {
2463 template <typename T> struct remove_reference { using type = T; };
2464 template <typename T> struct remove_reference<T&> { using type = T; };
2465 template <typename T> struct remove_reference<T&&> { using type = T; };
2467 template <typename T>
2468 using remove_reference_t = typename remove_reference<T>::type;
2470 template <typename T>
2471 std::remove_reference_t<T>&& move(T&& x);
2473 } // namespace std
2475 struct A {
2476 int Baz;
2479 void target() {
2480 A Foo;
2481 A Bar;
2482 (void)Foo.Baz;
2483 // [[p1]]
2484 Foo = std::move(Bar);
2485 // [[p2]]
2488 runDataflow(
2489 Code,
2490 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2491 ASTContext &ASTCtx) {
2492 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
2493 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
2494 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
2496 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2497 ASSERT_THAT(FooDecl, NotNull());
2499 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2500 ASSERT_THAT(BarDecl, NotNull());
2502 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2503 ASSERT_THAT(BazDecl, NotNull());
2505 const auto *FooLoc1 =
2506 cast<RecordStorageLocation>(Env1.getStorageLocation(*FooDecl));
2507 const auto *BarLoc1 =
2508 cast<RecordStorageLocation>(Env1.getStorageLocation(*BarDecl));
2510 EXPECT_FALSE(recordsEqual(*FooLoc1, *BarLoc1, Env1));
2512 const auto *FooVal1 = cast<RecordValue>(Env1.getValue(*FooLoc1));
2513 const auto *BarVal1 = cast<RecordValue>(Env1.getValue(*BarLoc1));
2514 EXPECT_NE(FooVal1, BarVal1);
2516 const auto *FooBazVal1 =
2517 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env1));
2518 const auto *BarBazVal1 =
2519 cast<IntegerValue>(getFieldValue(BarLoc1, *BazDecl, Env1));
2520 EXPECT_NE(FooBazVal1, BarBazVal1);
2522 const auto *FooLoc2 =
2523 cast<RecordStorageLocation>(Env2.getStorageLocation(*FooDecl));
2524 const auto *FooVal2 = cast<RecordValue>(Env2.getValue(*FooLoc2));
2525 EXPECT_NE(FooVal2, BarVal1);
2526 EXPECT_TRUE(recordsEqual(*FooLoc2, Env2, *BarLoc1, Env1));
2528 const auto *FooBazVal2 =
2529 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env2));
2530 EXPECT_EQ(FooBazVal2, BarBazVal1);
2534 TEST(TransferTest, BindTemporary) {
2535 std::string Code = R"(
2536 struct A {
2537 virtual ~A() = default;
2539 int Baz;
2542 void target(A Foo) {
2543 int Bar = A(Foo).Baz;
2544 // [[p]]
2547 runDataflow(
2548 Code,
2549 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2550 ASTContext &ASTCtx) {
2551 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2552 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2554 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2555 ASSERT_THAT(FooDecl, NotNull());
2557 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2558 ASSERT_THAT(BarDecl, NotNull());
2560 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2561 ASSERT_THAT(BazDecl, NotNull());
2563 const auto &FooLoc =
2564 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
2565 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));
2566 EXPECT_EQ(BarVal, getFieldValue(&FooLoc, *BazDecl, Env));
2570 TEST(TransferTest, StaticCast) {
2571 std::string Code = R"(
2572 void target(int Foo) {
2573 int Bar = static_cast<int>(Foo);
2574 // [[p]]
2577 runDataflow(
2578 Code,
2579 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2580 ASTContext &ASTCtx) {
2581 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2582 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2584 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2585 ASSERT_THAT(FooDecl, NotNull());
2587 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2588 ASSERT_THAT(BarDecl, NotNull());
2590 const auto *FooVal = Env.getValue(*FooDecl);
2591 const auto *BarVal = Env.getValue(*BarDecl);
2592 EXPECT_TRUE(isa<IntegerValue>(FooVal));
2593 EXPECT_TRUE(isa<IntegerValue>(BarVal));
2594 EXPECT_EQ(FooVal, BarVal);
2598 TEST(TransferTest, IntegralCast) {
2599 std::string Code = R"(
2600 void target(int Foo) {
2601 long Bar = Foo;
2602 // [[p]]
2605 runDataflow(
2606 Code,
2607 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2608 ASTContext &ASTCtx) {
2609 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2610 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2612 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2613 ASSERT_THAT(FooDecl, NotNull());
2615 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2616 ASSERT_THAT(BarDecl, NotNull());
2618 const auto *FooVal = Env.getValue(*FooDecl);
2619 const auto *BarVal = Env.getValue(*BarDecl);
2620 EXPECT_TRUE(isa<IntegerValue>(FooVal));
2621 EXPECT_TRUE(isa<IntegerValue>(BarVal));
2622 EXPECT_EQ(FooVal, BarVal);
2626 TEST(TransferTest, IntegraltoBooleanCast) {
2627 std::string Code = R"(
2628 void target(int Foo) {
2629 bool Bar = Foo;
2630 // [[p]]
2633 runDataflow(
2634 Code,
2635 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2636 ASTContext &ASTCtx) {
2637 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2638 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2640 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2641 ASSERT_THAT(FooDecl, NotNull());
2643 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2644 ASSERT_THAT(BarDecl, NotNull());
2646 const auto *FooVal = Env.getValue(*FooDecl);
2647 const auto *BarVal = Env.getValue(*BarDecl);
2648 EXPECT_TRUE(isa<IntegerValue>(FooVal));
2649 EXPECT_TRUE(isa<BoolValue>(BarVal));
2653 TEST(TransferTest, IntegralToBooleanCastFromBool) {
2654 std::string Code = R"(
2655 void target(bool Foo) {
2656 int Zab = Foo;
2657 bool Bar = Zab;
2658 // [[p]]
2661 runDataflow(
2662 Code,
2663 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2664 ASTContext &ASTCtx) {
2665 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2666 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2668 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2669 ASSERT_THAT(FooDecl, NotNull());
2671 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2672 ASSERT_THAT(BarDecl, NotNull());
2674 const auto *FooVal = Env.getValue(*FooDecl);
2675 const auto *BarVal = Env.getValue(*BarDecl);
2676 EXPECT_TRUE(isa<BoolValue>(FooVal));
2677 EXPECT_TRUE(isa<BoolValue>(BarVal));
2678 EXPECT_EQ(FooVal, BarVal);
2682 TEST(TransferTest, NullToPointerCast) {
2683 std::string Code = R"(
2684 using my_nullptr_t = decltype(nullptr);
2685 struct Baz {};
2686 void target() {
2687 int *FooX = nullptr;
2688 int *FooY = nullptr;
2689 bool **Bar = nullptr;
2690 Baz *Baz = nullptr;
2691 my_nullptr_t Null = 0;
2692 // [[p]]
2695 runDataflow(
2696 Code,
2697 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2698 ASTContext &ASTCtx) {
2699 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2700 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2702 const ValueDecl *FooXDecl = findValueDecl(ASTCtx, "FooX");
2703 ASSERT_THAT(FooXDecl, NotNull());
2705 const ValueDecl *FooYDecl = findValueDecl(ASTCtx, "FooY");
2706 ASSERT_THAT(FooYDecl, NotNull());
2708 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2709 ASSERT_THAT(BarDecl, NotNull());
2711 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2712 ASSERT_THAT(BazDecl, NotNull());
2714 const ValueDecl *NullDecl = findValueDecl(ASTCtx, "Null");
2715 ASSERT_THAT(NullDecl, NotNull());
2717 const auto *FooXVal = cast<PointerValue>(Env.getValue(*FooXDecl));
2718 const auto *FooYVal = cast<PointerValue>(Env.getValue(*FooYDecl));
2719 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl));
2720 const auto *BazVal = cast<PointerValue>(Env.getValue(*BazDecl));
2721 const auto *NullVal = cast<PointerValue>(Env.getValue(*NullDecl));
2723 EXPECT_EQ(FooXVal, FooYVal);
2724 EXPECT_NE(FooXVal, BarVal);
2725 EXPECT_NE(FooXVal, BazVal);
2726 EXPECT_NE(BarVal, BazVal);
2728 const StorageLocation &FooPointeeLoc = FooXVal->getPointeeLoc();
2729 EXPECT_TRUE(isa<ScalarStorageLocation>(FooPointeeLoc));
2730 EXPECT_THAT(Env.getValue(FooPointeeLoc), IsNull());
2732 const StorageLocation &BarPointeeLoc = BarVal->getPointeeLoc();
2733 EXPECT_TRUE(isa<ScalarStorageLocation>(BarPointeeLoc));
2734 EXPECT_THAT(Env.getValue(BarPointeeLoc), IsNull());
2736 const StorageLocation &BazPointeeLoc = BazVal->getPointeeLoc();
2737 EXPECT_TRUE(isa<RecordStorageLocation>(BazPointeeLoc));
2738 EXPECT_THAT(Env.getValue(BazPointeeLoc), IsNull());
2740 const StorageLocation &NullPointeeLoc = NullVal->getPointeeLoc();
2741 EXPECT_TRUE(isa<ScalarStorageLocation>(NullPointeeLoc));
2742 EXPECT_THAT(Env.getValue(NullPointeeLoc), IsNull());
2746 TEST(TransferTest, PointerToMemberVariable) {
2747 std::string Code = R"(
2748 struct S {
2749 int i;
2751 void target() {
2752 int S::*MemberPointer = &S::i;
2753 // [[p]]
2756 runDataflow(
2757 Code,
2758 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2759 ASTContext &ASTCtx) {
2760 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2762 const ValueDecl *MemberPointerDecl =
2763 findValueDecl(ASTCtx, "MemberPointer");
2764 ASSERT_THAT(MemberPointerDecl, NotNull());
2765 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull());
2769 TEST(TransferTest, PointerToMemberFunction) {
2770 std::string Code = R"(
2771 struct S {
2772 void Method();
2774 void target() {
2775 void (S::*MemberPointer)() = &S::Method;
2776 // [[p]]
2779 runDataflow(
2780 Code,
2781 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2782 ASTContext &ASTCtx) {
2783 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2785 const ValueDecl *MemberPointerDecl =
2786 findValueDecl(ASTCtx, "MemberPointer");
2787 ASSERT_THAT(MemberPointerDecl, NotNull());
2788 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull());
2792 TEST(TransferTest, NullToMemberPointerCast) {
2793 std::string Code = R"(
2794 struct Foo {};
2795 void target() {
2796 int Foo::*MemberPointer = nullptr;
2797 // [[p]]
2800 runDataflow(
2801 Code,
2802 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2803 ASTContext &ASTCtx) {
2804 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2805 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2807 const ValueDecl *MemberPointerDecl =
2808 findValueDecl(ASTCtx, "MemberPointer");
2809 ASSERT_THAT(MemberPointerDecl, NotNull());
2810 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull());
2814 TEST(TransferTest, AddrOfValue) {
2815 std::string Code = R"(
2816 void target() {
2817 int Foo;
2818 int *Bar = &Foo;
2819 // [[p]]
2822 runDataflow(
2823 Code,
2824 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2825 ASTContext &ASTCtx) {
2826 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2827 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2829 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2830 ASSERT_THAT(FooDecl, NotNull());
2832 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2833 ASSERT_THAT(BarDecl, NotNull());
2835 const auto *FooLoc =
2836 cast<ScalarStorageLocation>(Env.getStorageLocation(*FooDecl));
2837 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl));
2838 EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc);
2842 TEST(TransferTest, AddrOfReference) {
2843 std::string Code = R"(
2844 void target(int *Foo) {
2845 int *Bar = &(*Foo);
2846 // [[p]]
2849 runDataflow(
2850 Code,
2851 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2852 ASTContext &ASTCtx) {
2853 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2854 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2856 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2857 ASSERT_THAT(FooDecl, NotNull());
2859 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2860 ASSERT_THAT(BarDecl, NotNull());
2862 const auto *FooVal = cast<PointerValue>(Env.getValue(*FooDecl));
2863 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl));
2864 EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc());
2868 TEST(TransferTest, CannotAnalyzeFunctionTemplate) {
2869 std::string Code = R"(
2870 template <typename T>
2871 void target() {}
2873 ASSERT_THAT_ERROR(
2874 checkDataflowWithNoopAnalysis(Code),
2875 llvm::FailedWithMessage("Cannot analyze templated declarations"));
2878 TEST(TransferTest, CannotAnalyzeMethodOfClassTemplate) {
2879 std::string Code = R"(
2880 template <typename T>
2881 struct A {
2882 void target() {}
2885 ASSERT_THAT_ERROR(
2886 checkDataflowWithNoopAnalysis(Code),
2887 llvm::FailedWithMessage("Cannot analyze templated declarations"));
2890 TEST(TransferTest, VarDeclInitAssignConditionalOperator) {
2891 std::string Code = R"(
2892 struct A {};
2894 void target(A Foo, A Bar, bool Cond) {
2895 A Baz = Cond ? Foo : Bar;
2896 /*[[p]]*/
2899 runDataflow(
2900 Code,
2901 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2902 ASTContext &ASTCtx) {
2903 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
2904 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2906 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2907 ASSERT_THAT(FooDecl, NotNull());
2909 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2910 ASSERT_THAT(BarDecl, NotNull());
2912 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2913 ASSERT_THAT(BazDecl, NotNull());
2915 const auto *FooVal = cast<RecordValue>(Env.getValue(*FooDecl));
2916 const auto *BarVal = cast<RecordValue>(Env.getValue(*BarDecl));
2918 const auto *BazVal = dyn_cast<RecordValue>(Env.getValue(*BazDecl));
2919 ASSERT_THAT(BazVal, NotNull());
2921 EXPECT_NE(BazVal, FooVal);
2922 EXPECT_NE(BazVal, BarVal);
2926 TEST(TransferTest, VarDeclInDoWhile) {
2927 std::string Code = R"(
2928 void target(int *Foo) {
2929 do {
2930 int Bar = *Foo;
2931 // [[in_loop]]
2932 } while (false);
2933 (void)0;
2934 // [[after_loop]]
2937 runDataflow(
2938 Code,
2939 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2940 ASTContext &ASTCtx) {
2941 const Environment &EnvInLoop =
2942 getEnvironmentAtAnnotation(Results, "in_loop");
2943 const Environment &EnvAfterLoop =
2944 getEnvironmentAtAnnotation(Results, "after_loop");
2946 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2947 ASSERT_THAT(FooDecl, NotNull());
2949 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2950 ASSERT_THAT(BarDecl, NotNull());
2952 const auto *FooVal =
2953 cast<PointerValue>(EnvAfterLoop.getValue(*FooDecl));
2954 const auto *FooPointeeVal =
2955 cast<IntegerValue>(EnvAfterLoop.getValue(FooVal->getPointeeLoc()));
2957 const auto *BarVal = cast<IntegerValue>(EnvInLoop.getValue(*BarDecl));
2958 EXPECT_EQ(BarVal, FooPointeeVal);
2960 // FIXME: This assertion documents current behavior, but we would prefer
2961 // declarations to be removed from the environment when their lifetime
2962 // ends. Once this is the case, change this assertion accordingly.
2963 ASSERT_THAT(EnvAfterLoop.getValue(*BarDecl), BarVal);
2967 TEST(TransferTest, UnreachableAfterWhileTrue) {
2968 std::string Code = R"(
2969 void target() {
2970 while (true) {}
2971 (void)0;
2972 /*[[p]]*/
2975 runDataflow(
2976 Code,
2977 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2978 ASTContext &ASTCtx) {
2979 // The node after the while-true is pruned because it is trivially
2980 // known to be unreachable.
2981 ASSERT_TRUE(Results.empty());
2985 TEST(TransferTest, AggregateInitialization) {
2986 std::string BracesCode = R"(
2987 struct A {
2988 int Foo;
2991 struct B {
2992 int Bar;
2993 A Baz;
2994 int Qux;
2997 void target(int BarArg, int FooArg, int QuxArg) {
2998 B Quux{BarArg, {FooArg}, QuxArg};
2999 B OtherB;
3000 /*[[p]]*/
3003 std::string BraceElisionCode = R"(
3004 struct A {
3005 int Foo;
3008 struct B {
3009 int Bar;
3010 A Baz;
3011 int Qux;
3014 void target(int BarArg, int FooArg, int QuxArg) {
3015 B Quux = {BarArg, FooArg, QuxArg};
3016 B OtherB;
3017 /*[[p]]*/
3020 for (const std::string &Code : {BracesCode, BraceElisionCode}) {
3021 runDataflow(
3022 Code,
3023 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3024 ASTContext &ASTCtx) {
3025 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3026 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3028 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3029 ASSERT_THAT(FooDecl, NotNull());
3031 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3032 ASSERT_THAT(BarDecl, NotNull());
3034 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3035 ASSERT_THAT(BazDecl, NotNull());
3037 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
3038 ASSERT_THAT(QuxDecl, NotNull());
3040 const ValueDecl *FooArgDecl = findValueDecl(ASTCtx, "FooArg");
3041 ASSERT_THAT(FooArgDecl, NotNull());
3043 const ValueDecl *BarArgDecl = findValueDecl(ASTCtx, "BarArg");
3044 ASSERT_THAT(BarArgDecl, NotNull());
3046 const ValueDecl *QuxArgDecl = findValueDecl(ASTCtx, "QuxArg");
3047 ASSERT_THAT(QuxArgDecl, NotNull());
3049 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
3050 ASSERT_THAT(QuuxDecl, NotNull());
3052 const auto *FooArgVal = cast<IntegerValue>(Env.getValue(*FooArgDecl));
3053 const auto *BarArgVal = cast<IntegerValue>(Env.getValue(*BarArgDecl));
3054 const auto *QuxArgVal = cast<IntegerValue>(Env.getValue(*QuxArgDecl));
3056 const auto &QuuxLoc =
3057 *cast<RecordStorageLocation>(Env.getStorageLocation(*QuuxDecl));
3058 const auto &BazLoc =
3059 *cast<RecordStorageLocation>(QuuxLoc.getChild(*BazDecl));
3061 EXPECT_EQ(getFieldValue(&QuuxLoc, *BarDecl, Env), BarArgVal);
3062 EXPECT_EQ(getFieldValue(&BazLoc, *FooDecl, Env), FooArgVal);
3063 EXPECT_EQ(getFieldValue(&QuuxLoc, *QuxDecl, Env), QuxArgVal);
3065 // Check that fields initialized in an initializer list are always
3066 // modeled in other instances of the same type.
3067 const auto &OtherBLoc =
3068 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "OtherB");
3069 EXPECT_THAT(OtherBLoc.getChild(*BarDecl), NotNull());
3070 EXPECT_THAT(OtherBLoc.getChild(*BazDecl), NotNull());
3071 EXPECT_THAT(OtherBLoc.getChild(*QuxDecl), NotNull());
3076 TEST(TransferTest, AggregateInitializationReferenceField) {
3077 std::string Code = R"(
3078 struct S {
3079 int &RefField;
3082 void target(int i) {
3083 S s = { i };
3084 /*[[p]]*/
3087 runDataflow(
3088 Code,
3089 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3090 ASTContext &ASTCtx) {
3091 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3093 const ValueDecl *RefFieldDecl = findValueDecl(ASTCtx, "RefField");
3095 auto &ILoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "i");
3096 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s");
3098 EXPECT_EQ(SLoc.getChild(*RefFieldDecl), &ILoc);
3102 TEST(TransferTest, AggregateInitialization_NotExplicitlyInitializedField) {
3103 std::string Code = R"(
3104 struct S {
3105 int i1;
3106 int i2;
3109 void target(int i) {
3110 S s = { i };
3111 /*[[p]]*/
3114 runDataflow(
3115 Code,
3116 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3117 ASTContext &ASTCtx) {
3118 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3120 const ValueDecl *I1FieldDecl = findValueDecl(ASTCtx, "i1");
3121 const ValueDecl *I2FieldDecl = findValueDecl(ASTCtx, "i2");
3123 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s");
3125 auto &IValue = getValueForDecl<IntegerValue>(ASTCtx, Env, "i");
3126 auto &I1Value =
3127 *cast<IntegerValue>(getFieldValue(&SLoc, *I1FieldDecl, Env));
3128 EXPECT_EQ(&I1Value, &IValue);
3129 auto &I2Value =
3130 *cast<IntegerValue>(getFieldValue(&SLoc, *I2FieldDecl, Env));
3131 EXPECT_NE(&I2Value, &IValue);
3135 TEST(TransferTest, AssignToUnionMember) {
3136 std::string Code = R"(
3137 union A {
3138 int Foo;
3141 void target(int Bar) {
3142 A Baz;
3143 Baz.Foo = Bar;
3144 // [[p]]
3147 runDataflow(
3148 Code,
3149 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3150 ASTContext &ASTCtx) {
3151 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3152 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3154 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3155 ASSERT_THAT(BazDecl, NotNull());
3156 ASSERT_TRUE(BazDecl->getType()->isUnionType());
3158 auto BazFields = BazDecl->getType()->getAsRecordDecl()->fields();
3159 FieldDecl *FooDecl = nullptr;
3160 for (FieldDecl *Field : BazFields) {
3161 if (Field->getNameAsString() == "Foo") {
3162 FooDecl = Field;
3163 } else {
3164 FAIL() << "Unexpected field: " << Field->getNameAsString();
3167 ASSERT_THAT(FooDecl, NotNull());
3169 const auto *BazLoc = dyn_cast_or_null<RecordStorageLocation>(
3170 Env.getStorageLocation(*BazDecl));
3171 ASSERT_THAT(BazLoc, NotNull());
3172 ASSERT_THAT(Env.getValue(*BazLoc), NotNull());
3174 const auto *FooVal =
3175 cast<IntegerValue>(getFieldValue(BazLoc, *FooDecl, Env));
3177 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3178 ASSERT_THAT(BarDecl, NotNull());
3179 const auto *BarLoc = Env.getStorageLocation(*BarDecl);
3180 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
3182 EXPECT_EQ(Env.getValue(*BarLoc), FooVal);
3186 TEST(TransferTest, AssignFromBoolLiteral) {
3187 std::string Code = R"(
3188 void target() {
3189 bool Foo = true;
3190 bool Bar = false;
3191 // [[p]]
3194 runDataflow(
3195 Code,
3196 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3197 ASTContext &ASTCtx) {
3198 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3199 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3201 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3202 ASSERT_THAT(FooDecl, NotNull());
3204 const auto *FooVal =
3205 dyn_cast_or_null<AtomicBoolValue>(Env.getValue(*FooDecl));
3206 ASSERT_THAT(FooVal, NotNull());
3208 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3209 ASSERT_THAT(BarDecl, NotNull());
3211 const auto *BarVal =
3212 dyn_cast_or_null<AtomicBoolValue>(Env.getValue(*BarDecl));
3213 ASSERT_THAT(BarVal, NotNull());
3215 EXPECT_EQ(FooVal, &Env.getBoolLiteralValue(true));
3216 EXPECT_EQ(BarVal, &Env.getBoolLiteralValue(false));
3220 TEST(TransferTest, AssignFromCompositeBoolExpression) {
3222 std::string Code = R"(
3223 void target(bool Foo, bool Bar, bool Qux) {
3224 bool Baz = (Foo) && (Bar || Qux);
3225 // [[p]]
3228 runDataflow(
3229 Code,
3230 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3231 ASTContext &ASTCtx) {
3232 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3233 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3235 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3236 ASSERT_THAT(FooDecl, NotNull());
3238 const auto *FooVal =
3239 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));
3240 ASSERT_THAT(FooVal, NotNull());
3242 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3243 ASSERT_THAT(BarDecl, NotNull());
3245 const auto *BarVal =
3246 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl));
3247 ASSERT_THAT(BarVal, NotNull());
3249 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
3250 ASSERT_THAT(QuxDecl, NotNull());
3252 const auto *QuxVal =
3253 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl));
3254 ASSERT_THAT(QuxVal, NotNull());
3256 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3257 ASSERT_THAT(BazDecl, NotNull());
3259 const auto *BazVal =
3260 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl));
3261 ASSERT_THAT(BazVal, NotNull());
3262 auto &A = Env.arena();
3263 EXPECT_EQ(&BazVal->formula(),
3264 &A.makeAnd(FooVal->formula(),
3265 A.makeOr(BarVal->formula(), QuxVal->formula())));
3270 std::string Code = R"(
3271 void target(bool Foo, bool Bar, bool Qux) {
3272 bool Baz = (Foo && Qux) || (Bar);
3273 // [[p]]
3276 runDataflow(
3277 Code,
3278 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3279 ASTContext &ASTCtx) {
3280 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3281 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3283 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3284 ASSERT_THAT(FooDecl, NotNull());
3286 const auto *FooVal =
3287 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));
3288 ASSERT_THAT(FooVal, NotNull());
3290 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3291 ASSERT_THAT(BarDecl, NotNull());
3293 const auto *BarVal =
3294 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl));
3295 ASSERT_THAT(BarVal, NotNull());
3297 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
3298 ASSERT_THAT(QuxDecl, NotNull());
3300 const auto *QuxVal =
3301 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl));
3302 ASSERT_THAT(QuxVal, NotNull());
3304 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3305 ASSERT_THAT(BazDecl, NotNull());
3307 const auto *BazVal =
3308 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl));
3309 ASSERT_THAT(BazVal, NotNull());
3310 auto &A = Env.arena();
3311 EXPECT_EQ(&BazVal->formula(),
3312 &A.makeOr(A.makeAnd(FooVal->formula(), QuxVal->formula()),
3313 BarVal->formula()));
3318 std::string Code = R"(
3319 void target(bool A, bool B, bool C, bool D) {
3320 bool Foo = ((A && B) && C) && D;
3321 // [[p]]
3324 runDataflow(
3325 Code,
3326 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3327 ASTContext &ASTCtx) {
3328 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3329 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3331 const ValueDecl *ADecl = findValueDecl(ASTCtx, "A");
3332 ASSERT_THAT(ADecl, NotNull());
3334 const auto *AVal = dyn_cast_or_null<BoolValue>(Env.getValue(*ADecl));
3335 ASSERT_THAT(AVal, NotNull());
3337 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B");
3338 ASSERT_THAT(BDecl, NotNull());
3340 const auto *BVal = dyn_cast_or_null<BoolValue>(Env.getValue(*BDecl));
3341 ASSERT_THAT(BVal, NotNull());
3343 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C");
3344 ASSERT_THAT(CDecl, NotNull());
3346 const auto *CVal = dyn_cast_or_null<BoolValue>(Env.getValue(*CDecl));
3347 ASSERT_THAT(CVal, NotNull());
3349 const ValueDecl *DDecl = findValueDecl(ASTCtx, "D");
3350 ASSERT_THAT(DDecl, NotNull());
3352 const auto *DVal = dyn_cast_or_null<BoolValue>(Env.getValue(*DDecl));
3353 ASSERT_THAT(DVal, NotNull());
3355 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3356 ASSERT_THAT(FooDecl, NotNull());
3358 const auto *FooVal =
3359 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));
3360 ASSERT_THAT(FooVal, NotNull());
3361 auto &A = Env.arena();
3362 EXPECT_EQ(
3363 &FooVal->formula(),
3364 &A.makeAnd(A.makeAnd(A.makeAnd(AVal->formula(), BVal->formula()),
3365 CVal->formula()),
3366 DVal->formula()));
3371 TEST(TransferTest, AssignFromBoolNegation) {
3372 std::string Code = R"(
3373 void target() {
3374 bool Foo = true;
3375 bool Bar = !(Foo);
3376 // [[p]]
3379 runDataflow(
3380 Code,
3381 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3382 ASTContext &ASTCtx) {
3383 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3384 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3386 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3387 ASSERT_THAT(FooDecl, NotNull());
3389 const auto *FooVal =
3390 dyn_cast_or_null<AtomicBoolValue>(Env.getValue(*FooDecl));
3391 ASSERT_THAT(FooVal, NotNull());
3393 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3394 ASSERT_THAT(BarDecl, NotNull());
3396 const auto *BarVal =
3397 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl));
3398 ASSERT_THAT(BarVal, NotNull());
3399 auto &A = Env.arena();
3400 EXPECT_EQ(&BarVal->formula(), &A.makeNot(FooVal->formula()));
3404 TEST(TransferTest, BuiltinExpect) {
3405 std::string Code = R"(
3406 void target(long Foo) {
3407 long Bar = __builtin_expect(Foo, true);
3408 /*[[p]]*/
3411 runDataflow(
3412 Code,
3413 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3414 ASTContext &ASTCtx) {
3415 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3416 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3418 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3419 ASSERT_THAT(FooDecl, NotNull());
3421 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3422 ASSERT_THAT(BarDecl, NotNull());
3424 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
3428 // `__builtin_expect` takes and returns a `long` argument, so other types
3429 // involve casts. This verifies that we identify the input and output in that
3430 // case.
3431 TEST(TransferTest, BuiltinExpectBoolArg) {
3432 std::string Code = R"(
3433 void target(bool Foo) {
3434 bool Bar = __builtin_expect(Foo, true);
3435 /*[[p]]*/
3438 runDataflow(
3439 Code,
3440 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3441 ASTContext &ASTCtx) {
3442 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3443 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3445 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3446 ASSERT_THAT(FooDecl, NotNull());
3448 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3449 ASSERT_THAT(BarDecl, NotNull());
3451 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
3455 TEST(TransferTest, BuiltinUnreachable) {
3456 std::string Code = R"(
3457 void target(bool Foo) {
3458 bool Bar = false;
3459 if (Foo)
3460 Bar = Foo;
3461 else
3462 __builtin_unreachable();
3463 (void)0;
3464 /*[[p]]*/
3467 runDataflow(
3468 Code,
3469 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3470 ASTContext &ASTCtx) {
3471 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3472 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3474 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3475 ASSERT_THAT(FooDecl, NotNull());
3477 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3478 ASSERT_THAT(BarDecl, NotNull());
3480 // `__builtin_unreachable` promises that the code is
3481 // unreachable, so the compiler treats the "then" branch as the
3482 // only possible predecessor of this statement.
3483 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
3487 TEST(TransferTest, BuiltinTrap) {
3488 std::string Code = R"(
3489 void target(bool Foo) {
3490 bool Bar = false;
3491 if (Foo)
3492 Bar = Foo;
3493 else
3494 __builtin_trap();
3495 (void)0;
3496 /*[[p]]*/
3499 runDataflow(
3500 Code,
3501 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3502 ASTContext &ASTCtx) {
3503 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3504 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3506 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3507 ASSERT_THAT(FooDecl, NotNull());
3509 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3510 ASSERT_THAT(BarDecl, NotNull());
3512 // `__builtin_trap` ensures program termination, so only the
3513 // "then" branch is a predecessor of this statement.
3514 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
3518 TEST(TransferTest, BuiltinDebugTrap) {
3519 std::string Code = R"(
3520 void target(bool Foo) {
3521 bool Bar = false;
3522 if (Foo)
3523 Bar = Foo;
3524 else
3525 __builtin_debugtrap();
3526 (void)0;
3527 /*[[p]]*/
3530 runDataflow(
3531 Code,
3532 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3533 ASTContext &ASTCtx) {
3534 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3535 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3537 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3538 ASSERT_THAT(FooDecl, NotNull());
3540 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3541 ASSERT_THAT(BarDecl, NotNull());
3543 // `__builtin_debugtrap` doesn't ensure program termination.
3544 EXPECT_NE(Env.getValue(*FooDecl), Env.getValue(*BarDecl));
3548 TEST(TransferTest, StaticIntSingleVarDecl) {
3549 std::string Code = R"(
3550 void target() {
3551 static int Foo;
3552 // [[p]]
3555 runDataflow(
3556 Code,
3557 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3558 ASTContext &ASTCtx) {
3559 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3560 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3562 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3563 ASSERT_THAT(FooDecl, NotNull());
3565 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
3566 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
3568 const Value *FooVal = Env.getValue(*FooLoc);
3569 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
3573 TEST(TransferTest, StaticIntGroupVarDecl) {
3574 std::string Code = R"(
3575 void target() {
3576 static int Foo, Bar;
3577 (void)0;
3578 // [[p]]
3581 runDataflow(
3582 Code,
3583 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3584 ASTContext &ASTCtx) {
3585 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3586 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3588 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3589 ASSERT_THAT(FooDecl, NotNull());
3591 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3592 ASSERT_THAT(BarDecl, NotNull());
3594 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);
3595 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
3597 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
3598 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
3600 const Value *FooVal = Env.getValue(*FooLoc);
3601 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
3603 const Value *BarVal = Env.getValue(*BarLoc);
3604 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
3606 EXPECT_NE(FooVal, BarVal);
3610 TEST(TransferTest, GlobalIntVarDecl) {
3611 std::string Code = R"(
3612 static int Foo;
3614 void target() {
3615 int Bar = Foo;
3616 int Baz = Foo;
3617 // [[p]]
3620 runDataflow(
3621 Code,
3622 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3623 ASTContext &ASTCtx) {
3624 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3625 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3627 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3628 ASSERT_THAT(BarDecl, NotNull());
3630 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3631 ASSERT_THAT(BazDecl, NotNull());
3633 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));
3634 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl));
3635 EXPECT_EQ(BarVal, BazVal);
3639 TEST(TransferTest, StaticMemberIntVarDecl) {
3640 std::string Code = R"(
3641 struct A {
3642 static int Foo;
3645 void target(A a) {
3646 int Bar = a.Foo;
3647 int Baz = a.Foo;
3648 // [[p]]
3651 runDataflow(
3652 Code,
3653 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3654 ASTContext &ASTCtx) {
3655 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3656 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3658 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3659 ASSERT_THAT(BarDecl, NotNull());
3661 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3662 ASSERT_THAT(BazDecl, NotNull());
3664 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));
3665 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl));
3666 EXPECT_EQ(BarVal, BazVal);
3670 TEST(TransferTest, StaticMemberRefVarDecl) {
3671 std::string Code = R"(
3672 struct A {
3673 static int &Foo;
3676 void target(A a) {
3677 int Bar = a.Foo;
3678 int Baz = a.Foo;
3679 // [[p]]
3682 runDataflow(
3683 Code,
3684 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3685 ASTContext &ASTCtx) {
3686 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3687 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3689 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3690 ASSERT_THAT(BarDecl, NotNull());
3692 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3693 ASSERT_THAT(BazDecl, NotNull());
3695 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));
3696 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl));
3697 EXPECT_EQ(BarVal, BazVal);
3701 TEST(TransferTest, AssignMemberBeforeCopy) {
3702 std::string Code = R"(
3703 struct A {
3704 int Foo;
3707 void target() {
3708 A A1;
3709 A A2;
3710 int Bar;
3711 A1.Foo = Bar;
3712 A2 = A1;
3713 // [[p]]
3716 runDataflow(
3717 Code,
3718 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3719 ASTContext &ASTCtx) {
3720 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3721 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3723 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3724 ASSERT_THAT(FooDecl, NotNull());
3726 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3727 ASSERT_THAT(BarDecl, NotNull());
3729 const ValueDecl *A1Decl = findValueDecl(ASTCtx, "A1");
3730 ASSERT_THAT(A1Decl, NotNull());
3732 const ValueDecl *A2Decl = findValueDecl(ASTCtx, "A2");
3733 ASSERT_THAT(A2Decl, NotNull());
3735 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));
3737 const auto &A2Loc =
3738 *cast<RecordStorageLocation>(Env.getStorageLocation(*A2Decl));
3739 EXPECT_EQ(getFieldValue(&A2Loc, *FooDecl, Env), BarVal);
3743 TEST(TransferTest, BooleanEquality) {
3744 std::string Code = R"(
3745 void target(bool Bar) {
3746 bool Foo = true;
3747 if (Bar == Foo) {
3748 (void)0;
3749 /*[[p-then]]*/
3750 } else {
3751 (void)0;
3752 /*[[p-else]]*/
3756 runDataflow(
3757 Code,
3758 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3759 ASTContext &ASTCtx) {
3760 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else"));
3761 const Environment &EnvThen =
3762 getEnvironmentAtAnnotation(Results, "p-then");
3763 const Environment &EnvElse =
3764 getEnvironmentAtAnnotation(Results, "p-else");
3766 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3767 ASSERT_THAT(BarDecl, NotNull());
3769 auto &BarValThen = getFormula(*BarDecl, EnvThen);
3770 EXPECT_TRUE(EnvThen.flowConditionImplies(BarValThen));
3772 auto &BarValElse = getFormula(*BarDecl, EnvElse);
3773 EXPECT_TRUE(
3774 EnvElse.flowConditionImplies(EnvElse.arena().makeNot(BarValElse)));
3778 TEST(TransferTest, BooleanInequality) {
3779 std::string Code = R"(
3780 void target(bool Bar) {
3781 bool Foo = true;
3782 if (Bar != Foo) {
3783 (void)0;
3784 /*[[p-then]]*/
3785 } else {
3786 (void)0;
3787 /*[[p-else]]*/
3791 runDataflow(
3792 Code,
3793 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3794 ASTContext &ASTCtx) {
3795 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else"));
3796 const Environment &EnvThen =
3797 getEnvironmentAtAnnotation(Results, "p-then");
3798 const Environment &EnvElse =
3799 getEnvironmentAtAnnotation(Results, "p-else");
3801 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3802 ASSERT_THAT(BarDecl, NotNull());
3804 auto &BarValThen = getFormula(*BarDecl, EnvThen);
3805 EXPECT_TRUE(
3806 EnvThen.flowConditionImplies(EnvThen.arena().makeNot(BarValThen)));
3808 auto &BarValElse = getFormula(*BarDecl, EnvElse);
3809 EXPECT_TRUE(EnvElse.flowConditionImplies(BarValElse));
3813 TEST(TransferTest, IntegerLiteralEquality) {
3814 std::string Code = R"(
3815 void target() {
3816 bool equal = (42 == 42);
3817 // [[p]]
3820 runDataflow(
3821 Code,
3822 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3823 ASTContext &ASTCtx) {
3824 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3826 auto &Equal =
3827 getValueForDecl<BoolValue>(ASTCtx, Env, "equal").formula();
3828 EXPECT_TRUE(Env.flowConditionImplies(Equal));
3832 TEST(TransferTest, CorrelatedBranches) {
3833 std::string Code = R"(
3834 void target(bool B, bool C) {
3835 if (B) {
3836 return;
3838 (void)0;
3839 /*[[p0]]*/
3840 if (C) {
3841 B = true;
3842 /*[[p1]]*/
3844 if (B) {
3845 (void)0;
3846 /*[[p2]]*/
3850 runDataflow(
3851 Code,
3852 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3853 ASTContext &ASTCtx) {
3854 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p0", "p1", "p2"));
3856 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C");
3857 ASSERT_THAT(CDecl, NotNull());
3860 const Environment &Env = getEnvironmentAtAnnotation(Results, "p0");
3861 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B");
3862 ASSERT_THAT(BDecl, NotNull());
3863 auto &BVal = getFormula(*BDecl, Env);
3865 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(BVal)));
3869 const Environment &Env = getEnvironmentAtAnnotation(Results, "p1");
3870 auto &CVal = getFormula(*CDecl, Env);
3871 EXPECT_TRUE(Env.flowConditionImplies(CVal));
3875 const Environment &Env = getEnvironmentAtAnnotation(Results, "p2");
3876 auto &CVal = getFormula(*CDecl, Env);
3877 EXPECT_TRUE(Env.flowConditionImplies(CVal));
3882 TEST(TransferTest, LoopWithAssignmentConverges) {
3883 std::string Code = R"(
3884 bool foo();
3886 void target() {
3887 do {
3888 bool Bar = foo();
3889 if (Bar) break;
3890 (void)Bar;
3891 /*[[p]]*/
3892 } while (true);
3895 // The key property that we are verifying is implicit in `runDataflow` --
3896 // namely, that the analysis succeeds, rather than hitting the maximum number
3897 // of iterations.
3898 runDataflow(
3899 Code,
3900 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3901 ASTContext &ASTCtx) {
3902 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3903 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3905 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3906 ASSERT_THAT(BarDecl, NotNull());
3908 auto &BarVal = getFormula(*BarDecl, Env);
3909 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(BarVal)));
3913 TEST(TransferTest, LoopWithStagedAssignments) {
3914 std::string Code = R"(
3915 bool foo();
3917 void target() {
3918 bool Bar = false;
3919 bool Err = false;
3920 while (foo()) {
3921 if (Bar)
3922 Err = true;
3923 Bar = true;
3924 /*[[p]]*/
3928 runDataflow(
3929 Code,
3930 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3931 ASTContext &ASTCtx) {
3932 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3933 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3935 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3936 ASSERT_THAT(BarDecl, NotNull());
3937 const ValueDecl *ErrDecl = findValueDecl(ASTCtx, "Err");
3938 ASSERT_THAT(ErrDecl, NotNull());
3940 auto &BarVal = getFormula(*BarDecl, Env);
3941 auto &ErrVal = getFormula(*ErrDecl, Env);
3942 EXPECT_TRUE(Env.flowConditionImplies(BarVal));
3943 // An unsound analysis, for example only evaluating the loop once, can
3944 // conclude that `Err` is false. So, we test that this conclusion is not
3945 // reached.
3946 EXPECT_FALSE(
3947 Env.flowConditionImplies(Env.arena().makeNot(ErrVal)));
3951 TEST(TransferTest, LoopWithReferenceAssignmentConverges) {
3952 std::string Code = R"(
3953 bool &foo();
3955 void target() {
3956 do {
3957 bool& Bar = foo();
3958 if (Bar) break;
3959 (void)Bar;
3960 /*[[p]]*/
3961 } while (true);
3964 // The key property that we are verifying is that the analysis succeeds,
3965 // rather than hitting the maximum number of iterations.
3966 runDataflow(
3967 Code,
3968 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3969 ASTContext &ASTCtx) {
3970 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
3971 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3973 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3974 ASSERT_THAT(BarDecl, NotNull());
3976 auto &BarVal = getFormula(*BarDecl, Env);
3977 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(BarVal)));
3981 TEST(TransferTest, LoopWithStructReferenceAssignmentConverges) {
3982 std::string Code = R"(
3983 struct Lookup {
3984 int x;
3987 void target(Lookup val, bool b) {
3988 const Lookup* l = nullptr;
3989 while (b) {
3990 l = &val;
3991 /*[[p-inner]]*/
3993 (void)0;
3994 /*[[p-outer]]*/
3997 // The key property that we are verifying is implicit in `runDataflow` --
3998 // namely, that the analysis succeeds, rather than hitting the maximum number
3999 // of iterations.
4000 runDataflow(
4001 Code,
4002 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4003 ASTContext &ASTCtx) {
4004 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-inner", "p-outer"));
4005 const Environment &InnerEnv =
4006 getEnvironmentAtAnnotation(Results, "p-inner");
4007 const Environment &OuterEnv =
4008 getEnvironmentAtAnnotation(Results, "p-outer");
4010 const ValueDecl *ValDecl = findValueDecl(ASTCtx, "val");
4011 ASSERT_THAT(ValDecl, NotNull());
4013 const ValueDecl *LDecl = findValueDecl(ASTCtx, "l");
4014 ASSERT_THAT(LDecl, NotNull());
4016 // Inner.
4017 auto *LVal = dyn_cast<PointerValue>(InnerEnv.getValue(*LDecl));
4018 ASSERT_THAT(LVal, NotNull());
4020 EXPECT_EQ(&LVal->getPointeeLoc(),
4021 InnerEnv.getStorageLocation(*ValDecl));
4023 // Outer.
4024 LVal = dyn_cast<PointerValue>(OuterEnv.getValue(*LDecl));
4025 ASSERT_THAT(LVal, NotNull());
4027 // The loop body may not have been executed, so we should not conclude
4028 // that `l` points to `val`.
4029 EXPECT_NE(&LVal->getPointeeLoc(),
4030 OuterEnv.getStorageLocation(*ValDecl));
4034 TEST(TransferTest, LoopDereferencingChangingPointerConverges) {
4035 std::string Code = R"cc(
4036 bool some_condition();
4038 void target(int i1, int i2) {
4039 int *p = &i1;
4040 while (true) {
4041 (void)*p;
4042 if (some_condition())
4043 p = &i1;
4044 else
4045 p = &i2;
4048 )cc";
4049 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded());
4052 TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) {
4053 std::string Code = R"cc(
4054 struct Lookup {
4055 int x;
4058 bool some_condition();
4060 void target(Lookup l1, Lookup l2) {
4061 Lookup *l = &l1;
4062 while (true) {
4063 (void)l->x;
4064 if (some_condition())
4065 l = &l1;
4066 else
4067 l = &l2;
4070 )cc";
4071 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded());
4074 TEST(TransferTest, DoesNotCrashOnUnionThisExpr) {
4075 std::string Code = R"(
4076 union Union {
4077 int A;
4078 float B;
4081 void foo() {
4082 Union A;
4083 Union B;
4084 A = B;
4087 // This is a crash regression test when calling the transfer function on a
4088 // `CXXThisExpr` that refers to a union.
4089 runDataflow(
4090 Code,
4091 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
4092 ASTContext &) {},
4093 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator=");
4096 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToRefs) {
4097 std::string Code = R"(
4098 struct A {
4099 int Foo;
4100 int Bar;
4103 void target() {
4104 int Qux;
4105 A Baz;
4106 Baz.Foo = Qux;
4107 auto &FooRef = Baz.Foo;
4108 auto &BarRef = Baz.Bar;
4109 auto &[BoundFooRef, BoundBarRef] = Baz;
4110 // [[p]]
4113 runDataflow(
4114 Code,
4115 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4116 ASTContext &ASTCtx) {
4117 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4118 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4120 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef");
4121 ASSERT_THAT(FooRefDecl, NotNull());
4123 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef");
4124 ASSERT_THAT(BarRefDecl, NotNull());
4126 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
4127 ASSERT_THAT(QuxDecl, NotNull());
4129 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef");
4130 ASSERT_THAT(BoundFooRefDecl, NotNull());
4132 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef");
4133 ASSERT_THAT(BoundBarRefDecl, NotNull());
4135 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl);
4136 ASSERT_THAT(FooRefLoc, NotNull());
4138 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl);
4139 ASSERT_THAT(BarRefLoc, NotNull());
4141 const Value *QuxVal = Env.getValue(*QuxDecl);
4142 ASSERT_THAT(QuxVal, NotNull());
4144 const StorageLocation *BoundFooRefLoc =
4145 Env.getStorageLocation(*BoundFooRefDecl);
4146 EXPECT_EQ(BoundFooRefLoc, FooRefLoc);
4148 const StorageLocation *BoundBarRefLoc =
4149 Env.getStorageLocation(*BoundBarRefDecl);
4150 EXPECT_EQ(BoundBarRefLoc, BarRefLoc);
4152 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal);
4156 TEST(TransferTest, StructuredBindingAssignFromStructRefMembersToRefs) {
4157 std::string Code = R"(
4158 struct A {
4159 int &Foo;
4160 int &Bar;
4163 void target(A Baz) {
4164 int Qux;
4165 Baz.Foo = Qux;
4166 auto &FooRef = Baz.Foo;
4167 auto &BarRef = Baz.Bar;
4168 auto &[BoundFooRef, BoundBarRef] = Baz;
4169 // [[p]]
4172 runDataflow(
4173 Code,
4174 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4175 ASTContext &ASTCtx) {
4176 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4177 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4179 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef");
4180 ASSERT_THAT(FooRefDecl, NotNull());
4182 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef");
4183 ASSERT_THAT(BarRefDecl, NotNull());
4185 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
4186 ASSERT_THAT(QuxDecl, NotNull());
4188 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef");
4189 ASSERT_THAT(BoundFooRefDecl, NotNull());
4191 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef");
4192 ASSERT_THAT(BoundBarRefDecl, NotNull());
4194 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl);
4195 ASSERT_THAT(FooRefLoc, NotNull());
4197 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl);
4198 ASSERT_THAT(BarRefLoc, NotNull());
4200 const Value *QuxVal = Env.getValue(*QuxDecl);
4201 ASSERT_THAT(QuxVal, NotNull());
4203 const StorageLocation *BoundFooRefLoc =
4204 Env.getStorageLocation(*BoundFooRefDecl);
4205 EXPECT_EQ(BoundFooRefLoc, FooRefLoc);
4207 const StorageLocation *BoundBarRefLoc =
4208 Env.getStorageLocation(*BoundBarRefDecl);
4209 EXPECT_EQ(BoundBarRefLoc, BarRefLoc);
4211 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal);
4215 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToInts) {
4216 std::string Code = R"(
4217 struct A {
4218 int Foo;
4219 int Bar;
4222 void target() {
4223 int Qux;
4224 A Baz;
4225 Baz.Foo = Qux;
4226 auto &FooRef = Baz.Foo;
4227 auto &BarRef = Baz.Bar;
4228 auto [BoundFoo, BoundBar] = Baz;
4229 // [[p]]
4232 runDataflow(
4233 Code,
4234 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4235 ASTContext &ASTCtx) {
4236 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4237 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4239 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef");
4240 ASSERT_THAT(FooRefDecl, NotNull());
4242 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef");
4243 ASSERT_THAT(BarRefDecl, NotNull());
4245 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo");
4246 ASSERT_THAT(BoundFooDecl, NotNull());
4248 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");
4249 ASSERT_THAT(BoundBarDecl, NotNull());
4251 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
4252 ASSERT_THAT(QuxDecl, NotNull());
4254 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl);
4255 ASSERT_THAT(FooRefLoc, NotNull());
4257 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl);
4258 ASSERT_THAT(BarRefLoc, NotNull());
4260 const Value *QuxVal = Env.getValue(*QuxDecl);
4261 ASSERT_THAT(QuxVal, NotNull());
4263 const StorageLocation *BoundFooLoc =
4264 Env.getStorageLocation(*BoundFooDecl);
4265 EXPECT_NE(BoundFooLoc, FooRefLoc);
4267 const StorageLocation *BoundBarLoc =
4268 Env.getStorageLocation(*BoundBarDecl);
4269 EXPECT_NE(BoundBarLoc, BarRefLoc);
4271 EXPECT_EQ(Env.getValue(*BoundFooDecl), QuxVal);
4275 TEST(TransferTest, StructuredBindingAssignFromTupleLikeType) {
4276 std::string Code = R"(
4277 namespace std {
4278 using size_t = int;
4279 template <class> struct tuple_size;
4280 template <std::size_t, class> struct tuple_element;
4281 template <class...> class tuple;
4283 namespace {
4284 template <class T, T v>
4285 struct size_helper { static const T value = v; };
4286 } // namespace
4288 template <class... T>
4289 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {};
4291 template <std::size_t I, class... T>
4292 struct tuple_element<I, tuple<T...>> {
4293 using type = __type_pack_element<I, T...>;
4296 template <class...> class tuple {};
4298 template <std::size_t I, class... T>
4299 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
4300 } // namespace std
4302 std::tuple<bool, int> makeTuple();
4304 void target(bool B) {
4305 auto [BoundFoo, BoundBar] = makeTuple();
4306 bool Baz;
4307 // Include if-then-else to test interaction of `BindingDecl` with join.
4308 if (B) {
4309 Baz = BoundFoo;
4310 (void)BoundBar;
4311 // [[p1]]
4312 } else {
4313 Baz = BoundFoo;
4315 (void)0;
4316 // [[p2]]
4319 runDataflow(
4320 Code,
4321 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4322 ASTContext &ASTCtx) {
4323 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
4324 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
4326 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo");
4327 ASSERT_THAT(BoundFooDecl, NotNull());
4329 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");
4330 ASSERT_THAT(BoundBarDecl, NotNull());
4332 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
4333 ASSERT_THAT(BazDecl, NotNull());
4335 // BindingDecls always map to references -- either lvalue or rvalue, so
4336 // we still need to skip here.
4337 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl);
4338 ASSERT_THAT(BoundFooValue, NotNull());
4339 EXPECT_TRUE(isa<BoolValue>(BoundFooValue));
4341 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl);
4342 ASSERT_THAT(BoundBarValue, NotNull());
4343 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue));
4345 // Test that a `DeclRefExpr` to a `BindingDecl` works as expected.
4346 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue);
4348 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
4350 // Test that `BoundFooDecl` retains the value we expect, after the join.
4351 BoundFooValue = Env2.getValue(*BoundFooDecl);
4352 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue);
4356 TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) {
4357 std::string Code = R"(
4358 namespace std {
4359 using size_t = int;
4360 template <class> struct tuple_size;
4361 template <std::size_t, class> struct tuple_element;
4362 template <class...> class tuple;
4364 namespace {
4365 template <class T, T v>
4366 struct size_helper { static const T value = v; };
4367 } // namespace
4369 template <class... T>
4370 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {};
4372 template <std::size_t I, class... T>
4373 struct tuple_element<I, tuple<T...>> {
4374 using type = __type_pack_element<I, T...>;
4377 template <class...> class tuple {};
4379 template <std::size_t I, class... T>
4380 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
4381 } // namespace std
4383 std::tuple<bool, int> &getTuple();
4385 void target(bool B) {
4386 auto &[BoundFoo, BoundBar] = getTuple();
4387 bool Baz;
4388 // Include if-then-else to test interaction of `BindingDecl` with join.
4389 if (B) {
4390 Baz = BoundFoo;
4391 (void)BoundBar;
4392 // [[p1]]
4393 } else {
4394 Baz = BoundFoo;
4396 (void)0;
4397 // [[p2]]
4400 runDataflow(
4401 Code,
4402 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4403 ASTContext &ASTCtx) {
4404 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
4405 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
4407 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo");
4408 ASSERT_THAT(BoundFooDecl, NotNull());
4410 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");
4411 ASSERT_THAT(BoundBarDecl, NotNull());
4413 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
4414 ASSERT_THAT(BazDecl, NotNull());
4416 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl);
4417 ASSERT_THAT(BoundFooValue, NotNull());
4418 EXPECT_TRUE(isa<BoolValue>(BoundFooValue));
4420 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl);
4421 ASSERT_THAT(BoundBarValue, NotNull());
4422 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue));
4424 // Test that a `DeclRefExpr` to a `BindingDecl` (with reference type)
4425 // works as expected. We don't test aliasing properties of the
4426 // reference, because we don't model `std::get` and so have no way to
4427 // equate separate references into the tuple.
4428 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue);
4430 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");
4432 // Test that `BoundFooDecl` retains the value we expect, after the join.
4433 BoundFooValue = Env2.getValue(*BoundFooDecl);
4434 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue);
4438 TEST(TransferTest, BinaryOperatorComma) {
4439 std::string Code = R"(
4440 void target(int Foo, int Bar) {
4441 int &Baz = (Foo, Bar);
4442 // [[p]]
4445 runDataflow(
4446 Code,
4447 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4448 ASTContext &ASTCtx) {
4449 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4450 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4452 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
4453 ASSERT_THAT(BarDecl, NotNull());
4455 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
4456 ASSERT_THAT(BazDecl, NotNull());
4458 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);
4459 ASSERT_THAT(BarLoc, NotNull());
4461 const StorageLocation *BazLoc = Env.getStorageLocation(*BazDecl);
4462 EXPECT_EQ(BazLoc, BarLoc);
4466 TEST(TransferTest, IfStmtBranchExtendsFlowCondition) {
4467 std::string Code = R"(
4468 void target(bool Foo) {
4469 if (Foo) {
4470 (void)0;
4471 // [[if_then]]
4472 } else {
4473 (void)0;
4474 // [[if_else]]
4478 runDataflow(
4479 Code,
4480 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4481 ASTContext &ASTCtx) {
4482 ASSERT_THAT(Results.keys(), UnorderedElementsAre("if_then", "if_else"));
4483 const Environment &ThenEnv =
4484 getEnvironmentAtAnnotation(Results, "if_then");
4485 const Environment &ElseEnv =
4486 getEnvironmentAtAnnotation(Results, "if_else");
4488 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4489 ASSERT_THAT(FooDecl, NotNull());
4491 auto &ThenFooVal= getFormula(*FooDecl, ThenEnv);
4492 EXPECT_TRUE(ThenEnv.flowConditionImplies(ThenFooVal));
4494 auto &ElseFooVal = getFormula(*FooDecl, ElseEnv);
4495 EXPECT_TRUE(
4496 ElseEnv.flowConditionImplies(ElseEnv.arena().makeNot(ElseFooVal)));
4500 TEST(TransferTest, WhileStmtBranchExtendsFlowCondition) {
4501 std::string Code = R"(
4502 void target(bool Foo) {
4503 while (Foo) {
4504 (void)0;
4505 // [[loop_body]]
4507 (void)0;
4508 // [[after_loop]]
4511 runDataflow(
4512 Code,
4513 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4514 ASTContext &ASTCtx) {
4515 ASSERT_THAT(Results.keys(),
4516 UnorderedElementsAre("loop_body", "after_loop"));
4517 const Environment &LoopBodyEnv =
4518 getEnvironmentAtAnnotation(Results, "loop_body");
4519 const Environment &AfterLoopEnv =
4520 getEnvironmentAtAnnotation(Results, "after_loop");
4522 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4523 ASSERT_THAT(FooDecl, NotNull());
4525 auto &LoopBodyFooVal = getFormula(*FooDecl, LoopBodyEnv);
4526 EXPECT_TRUE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal));
4528 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv);
4529 EXPECT_TRUE(AfterLoopEnv.flowConditionImplies(
4530 AfterLoopEnv.arena().makeNot(AfterLoopFooVal)));
4534 TEST(TransferTest, DoWhileStmtBranchExtendsFlowCondition) {
4535 std::string Code = R"(
4536 void target(bool Foo) {
4537 bool Bar = true;
4538 do {
4539 (void)0;
4540 // [[loop_body]]
4541 Bar = false;
4542 } while (Foo);
4543 (void)0;
4544 // [[after_loop]]
4547 runDataflow(
4548 Code,
4549 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4550 ASTContext &ASTCtx) {
4551 ASSERT_THAT(Results.keys(),
4552 UnorderedElementsAre("loop_body", "after_loop"));
4553 const Environment &LoopBodyEnv =
4554 getEnvironmentAtAnnotation(Results, "loop_body");
4555 const Environment &AfterLoopEnv =
4556 getEnvironmentAtAnnotation(Results, "after_loop");
4557 auto &A = AfterLoopEnv.arena();
4559 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4560 ASSERT_THAT(FooDecl, NotNull());
4562 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
4563 ASSERT_THAT(BarDecl, NotNull());
4565 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv);
4566 auto &LoopBodyBarVal = getFormula(*BarDecl, LoopBodyEnv);
4567 EXPECT_TRUE(LoopBodyEnv.flowConditionImplies(
4568 A.makeOr(LoopBodyBarVal, LoopBodyFooVal)));
4570 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv);
4571 auto &AfterLoopBarVal = getFormula(*BarDecl, AfterLoopEnv);
4572 EXPECT_TRUE(
4573 AfterLoopEnv.flowConditionImplies(A.makeNot(AfterLoopFooVal)));
4574 EXPECT_TRUE(
4575 AfterLoopEnv.flowConditionImplies(A.makeNot(AfterLoopBarVal)));
4579 TEST(TransferTest, ForStmtBranchExtendsFlowCondition) {
4580 std::string Code = R"(
4581 void target(bool Foo) {
4582 for (; Foo;) {
4583 (void)0;
4584 // [[loop_body]]
4586 (void)0;
4587 // [[after_loop]]
4590 runDataflow(
4591 Code,
4592 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4593 ASTContext &ASTCtx) {
4594 ASSERT_THAT(Results.keys(),
4595 UnorderedElementsAre("loop_body", "after_loop"));
4596 const Environment &LoopBodyEnv =
4597 getEnvironmentAtAnnotation(Results, "loop_body");
4598 const Environment &AfterLoopEnv =
4599 getEnvironmentAtAnnotation(Results, "after_loop");
4601 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4602 ASSERT_THAT(FooDecl, NotNull());
4604 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv);
4605 EXPECT_TRUE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal));
4607 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv);
4608 EXPECT_TRUE(AfterLoopEnv.flowConditionImplies(
4609 AfterLoopEnv.arena().makeNot(AfterLoopFooVal)));
4613 TEST(TransferTest, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition) {
4614 std::string Code = R"(
4615 void target(bool Foo) {
4616 for (;;) {
4617 (void)0;
4618 // [[loop_body]]
4622 runDataflow(
4623 Code,
4624 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4625 ASTContext &ASTCtx) {
4626 ASSERT_THAT(Results.keys(), UnorderedElementsAre("loop_body"));
4627 const Environment &LoopBodyEnv =
4628 getEnvironmentAtAnnotation(Results, "loop_body");
4630 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4631 ASSERT_THAT(FooDecl, NotNull());
4633 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv);
4634 EXPECT_FALSE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal));
4638 TEST(TransferTest, ContextSensitiveOptionDisabled) {
4639 std::string Code = R"(
4640 bool GiveBool();
4641 void SetBool(bool &Var) { Var = true; }
4643 void target() {
4644 bool Foo = GiveBool();
4645 SetBool(Foo);
4646 // [[p]]
4649 runDataflow(
4650 Code,
4651 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4652 ASTContext &ASTCtx) {
4653 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4654 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4656 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4657 ASSERT_THAT(FooDecl, NotNull());
4659 auto &FooVal = getFormula(*FooDecl, Env);
4660 EXPECT_FALSE(Env.flowConditionImplies(FooVal));
4661 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(FooVal)));
4663 {BuiltinOptions{/*.ContextSensitiveOpts=*/std::nullopt}});
4666 TEST(TransferTest, ContextSensitiveReturnReference) {
4667 std::string Code = R"(
4668 class S {};
4669 S& target(bool b, S &s) {
4670 return s;
4671 // [[p]]
4674 runDataflow(
4675 Code,
4676 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4677 ASTContext &ASTCtx) {
4678 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4680 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s");
4681 ASSERT_THAT(SDecl, NotNull());
4683 auto *SLoc = Env.getStorageLocation(*SDecl);
4684 ASSERT_THAT(SLoc, NotNull());
4686 ASSERT_THAT(Env.getReturnStorageLocation(), Eq(SLoc));
4688 {BuiltinOptions{ContextSensitiveOptions{}}});
4691 // This test is a regression test, based on a real crash.
4692 TEST(TransferTest, ContextSensitiveReturnReferenceWithConditionalOperator) {
4693 std::string Code = R"(
4694 class S {};
4695 S& target(bool b, S &s) {
4696 return b ? s : s;
4697 // [[p]]
4700 runDataflow(
4701 Code,
4702 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4703 ASTContext &ASTCtx) {
4704 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4705 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4707 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s");
4708 ASSERT_THAT(SDecl, NotNull());
4710 auto *SLoc = Env.getStorageLocation(*SDecl);
4711 ASSERT_THAT(SLoc, NotNull());
4712 EXPECT_THAT(Env.getValue(*SLoc), NotNull());
4714 auto *Loc = Env.getReturnStorageLocation();
4715 ASSERT_THAT(Loc, NotNull());
4716 EXPECT_THAT(Env.getValue(*Loc), NotNull());
4718 // TODO: We would really like to make this stronger assertion, but that
4719 // doesn't work because we don't propagate values correctly through
4720 // the conditional operator yet.
4721 // ASSERT_THAT(Loc, Eq(SLoc));
4723 {BuiltinOptions{ContextSensitiveOptions{}}});
4726 TEST(TransferTest, ContextSensitiveReturnOneOfTwoReferences) {
4727 std::string Code = R"(
4728 class S {};
4729 S &callee(bool b, S &s1_parm, S &s2_parm) {
4730 if (b)
4731 return s1_parm;
4732 else
4733 return s2_parm;
4735 void target(bool b) {
4736 S s1;
4737 S s2;
4738 S &return_s1 = s1;
4739 S &return_s2 = s2;
4740 S &return_dont_know = callee(b, s1, s2);
4741 // [[p]]
4744 runDataflow(
4745 Code,
4746 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4747 ASTContext &ASTCtx) {
4748 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4750 const ValueDecl *S1 = findValueDecl(ASTCtx, "s1");
4751 ASSERT_THAT(S1, NotNull());
4752 const ValueDecl *S2 = findValueDecl(ASTCtx, "s2");
4753 ASSERT_THAT(S2, NotNull());
4754 const ValueDecl *ReturnS1 = findValueDecl(ASTCtx, "return_s1");
4755 ASSERT_THAT(ReturnS1, NotNull());
4756 const ValueDecl *ReturnS2 = findValueDecl(ASTCtx, "return_s2");
4757 ASSERT_THAT(ReturnS2, NotNull());
4758 const ValueDecl *ReturnDontKnow =
4759 findValueDecl(ASTCtx, "return_dont_know");
4760 ASSERT_THAT(ReturnDontKnow, NotNull());
4762 StorageLocation *S1Loc = Env.getStorageLocation(*S1);
4763 StorageLocation *S2Loc = Env.getStorageLocation(*S2);
4765 EXPECT_THAT(Env.getStorageLocation(*ReturnS1), Eq(S1Loc));
4766 EXPECT_THAT(Env.getStorageLocation(*ReturnS2), Eq(S2Loc));
4768 // In the case where we don't have a consistent storage location for
4769 // the return value, the framework creates a new storage location, which
4770 // should be different from the storage locations of `s1` and `s2`.
4771 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S1Loc));
4772 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S2Loc));
4774 {BuiltinOptions{ContextSensitiveOptions{}}});
4777 TEST(TransferTest, ContextSensitiveDepthZero) {
4778 std::string Code = R"(
4779 bool GiveBool();
4780 void SetBool(bool &Var) { Var = true; }
4782 void target() {
4783 bool Foo = GiveBool();
4784 SetBool(Foo);
4785 // [[p]]
4788 runDataflow(
4789 Code,
4790 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4791 ASTContext &ASTCtx) {
4792 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4793 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4795 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4796 ASSERT_THAT(FooDecl, NotNull());
4798 auto &FooVal = getFormula(*FooDecl, Env);
4799 EXPECT_FALSE(Env.flowConditionImplies(FooVal));
4800 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(FooVal)));
4802 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/0}}});
4805 TEST(TransferTest, ContextSensitiveSetTrue) {
4806 std::string Code = R"(
4807 bool GiveBool();
4808 void SetBool(bool &Var) { Var = true; }
4810 void target() {
4811 bool Foo = GiveBool();
4812 SetBool(Foo);
4813 // [[p]]
4816 runDataflow(
4817 Code,
4818 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4819 ASTContext &ASTCtx) {
4820 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4821 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4823 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4824 ASSERT_THAT(FooDecl, NotNull());
4826 auto &FooVal = getFormula(*FooDecl, Env);
4827 EXPECT_TRUE(Env.flowConditionImplies(FooVal));
4829 {BuiltinOptions{ContextSensitiveOptions{}}});
4832 TEST(TransferTest, ContextSensitiveSetFalse) {
4833 std::string Code = R"(
4834 bool GiveBool();
4835 void SetBool(bool &Var) { Var = false; }
4837 void target() {
4838 bool Foo = GiveBool();
4839 SetBool(Foo);
4840 // [[p]]
4843 runDataflow(
4844 Code,
4845 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4846 ASTContext &ASTCtx) {
4847 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4848 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4850 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4851 ASSERT_THAT(FooDecl, NotNull());
4853 auto &FooVal = getFormula(*FooDecl, Env);
4854 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(FooVal)));
4856 {BuiltinOptions{ContextSensitiveOptions{}}});
4859 TEST(TransferTest, ContextSensitiveSetBothTrueAndFalse) {
4860 std::string Code = R"(
4861 bool GiveBool();
4862 void SetBool(bool &Var, bool Val) { Var = Val; }
4864 void target() {
4865 bool Foo = GiveBool();
4866 bool Bar = GiveBool();
4867 SetBool(Foo, true);
4868 SetBool(Bar, false);
4869 // [[p]]
4872 runDataflow(
4873 Code,
4874 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4875 ASTContext &ASTCtx) {
4876 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4877 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4878 auto &A = Env.arena();
4880 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4881 ASSERT_THAT(FooDecl, NotNull());
4883 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
4884 ASSERT_THAT(BarDecl, NotNull());
4886 auto &FooVal = getFormula(*FooDecl, Env);
4887 EXPECT_TRUE(Env.flowConditionImplies(FooVal));
4888 EXPECT_FALSE(Env.flowConditionImplies(A.makeNot(FooVal)));
4890 auto &BarVal = getFormula(*BarDecl, Env);
4891 EXPECT_FALSE(Env.flowConditionImplies(BarVal));
4892 EXPECT_TRUE(Env.flowConditionImplies(A.makeNot(BarVal)));
4894 {BuiltinOptions{ContextSensitiveOptions{}}});
4897 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthOne) {
4898 std::string Code = R"(
4899 bool GiveBool();
4900 void SetBool1(bool &Var) { Var = true; }
4901 void SetBool2(bool &Var) { SetBool1(Var); }
4903 void target() {
4904 bool Foo = GiveBool();
4905 SetBool2(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_FALSE(Env.flowConditionImplies(FooVal));
4921 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(FooVal)));
4923 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/1}}});
4926 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthTwo) {
4927 std::string Code = R"(
4928 bool GiveBool();
4929 void SetBool1(bool &Var) { Var = true; }
4930 void SetBool2(bool &Var) { SetBool1(Var); }
4932 void target() {
4933 bool Foo = GiveBool();
4934 SetBool2(Foo);
4935 // [[p]]
4938 runDataflow(
4939 Code,
4940 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4941 ASTContext &ASTCtx) {
4942 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4943 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4945 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4946 ASSERT_THAT(FooDecl, NotNull());
4948 auto &FooVal = getFormula(*FooDecl, Env);
4949 EXPECT_TRUE(Env.flowConditionImplies(FooVal));
4951 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}});
4954 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthTwo) {
4955 std::string Code = R"(
4956 bool GiveBool();
4957 void SetBool1(bool &Var) { Var = true; }
4958 void SetBool2(bool &Var) { SetBool1(Var); }
4959 void SetBool3(bool &Var) { SetBool2(Var); }
4961 void target() {
4962 bool Foo = GiveBool();
4963 SetBool3(Foo);
4964 // [[p]]
4967 runDataflow(
4968 Code,
4969 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4970 ASTContext &ASTCtx) {
4971 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
4972 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4974 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
4975 ASSERT_THAT(FooDecl, NotNull());
4977 auto &FooVal = getFormula(*FooDecl, Env);
4978 EXPECT_FALSE(Env.flowConditionImplies(FooVal));
4979 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(FooVal)));
4981 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}});
4984 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthThree) {
4985 std::string Code = R"(
4986 bool GiveBool();
4987 void SetBool1(bool &Var) { Var = true; }
4988 void SetBool2(bool &Var) { SetBool1(Var); }
4989 void SetBool3(bool &Var) { SetBool2(Var); }
4991 void target() {
4992 bool Foo = GiveBool();
4993 SetBool3(Foo);
4994 // [[p]]
4997 runDataflow(
4998 Code,
4999 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5000 ASTContext &ASTCtx) {
5001 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5002 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5004 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5005 ASSERT_THAT(FooDecl, NotNull());
5007 auto &FooVal = getFormula(*FooDecl, Env);
5008 EXPECT_TRUE(Env.flowConditionImplies(FooVal));
5010 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/3}}});
5013 TEST(TransferTest, ContextSensitiveMutualRecursion) {
5014 std::string Code = R"(
5015 bool Pong(bool X, bool Y);
5017 bool Ping(bool X, bool Y) {
5018 if (X) {
5019 return Y;
5020 } else {
5021 return Pong(!X, Y);
5025 bool Pong(bool X, bool Y) {
5026 if (Y) {
5027 return X;
5028 } else {
5029 return Ping(X, !Y);
5033 void target() {
5034 bool Foo = Ping(false, false);
5035 // [[p]]
5038 runDataflow(
5039 Code,
5040 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5041 ASTContext &ASTCtx) {
5042 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5043 // The analysis doesn't crash...
5044 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5046 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5047 ASSERT_THAT(FooDecl, NotNull());
5049 auto &FooVal = getFormula(*FooDecl, Env);
5050 // ... but it also can't prove anything here.
5051 EXPECT_FALSE(Env.flowConditionImplies(FooVal));
5052 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(FooVal)));
5054 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/4}}});
5057 TEST(TransferTest, ContextSensitiveSetMultipleLines) {
5058 std::string Code = R"(
5059 void SetBools(bool &Var1, bool &Var2) {
5060 Var1 = true;
5061 Var2 = false;
5064 void target() {
5065 bool Foo = false;
5066 bool Bar = true;
5067 SetBools(Foo, Bar);
5068 // [[p]]
5071 runDataflow(
5072 Code,
5073 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5074 ASTContext &ASTCtx) {
5075 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5076 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5078 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5079 ASSERT_THAT(FooDecl, NotNull());
5081 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
5082 ASSERT_THAT(BarDecl, NotNull());
5084 auto &FooVal = getFormula(*FooDecl, Env);
5085 EXPECT_TRUE(Env.flowConditionImplies(FooVal));
5086 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(FooVal)));
5088 auto &BarVal = getFormula(*BarDecl, Env);
5089 EXPECT_FALSE(Env.flowConditionImplies(BarVal));
5090 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(BarVal)));
5092 {BuiltinOptions{ContextSensitiveOptions{}}});
5095 TEST(TransferTest, ContextSensitiveSetMultipleBlocks) {
5096 std::string Code = R"(
5097 void IfCond(bool Cond, bool &Then, bool &Else) {
5098 if (Cond) {
5099 Then = true;
5100 } else {
5101 Else = true;
5105 void target() {
5106 bool Foo = false;
5107 bool Bar = false;
5108 bool Baz = false;
5109 IfCond(Foo, Bar, Baz);
5110 // [[p]]
5113 runDataflow(
5114 Code,
5115 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5116 ASTContext &ASTCtx) {
5117 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5118 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5120 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
5121 ASSERT_THAT(BarDecl, NotNull());
5123 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
5124 ASSERT_THAT(BazDecl, NotNull());
5126 auto &BarVal = getFormula(*BarDecl, Env);
5127 EXPECT_FALSE(Env.flowConditionImplies(BarVal));
5128 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(BarVal)));
5130 auto &BazVal = getFormula(*BazDecl, Env);
5131 EXPECT_TRUE(Env.flowConditionImplies(BazVal));
5132 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(BazVal)));
5134 {BuiltinOptions{ContextSensitiveOptions{}}});
5137 TEST(TransferTest, ContextSensitiveReturnVoid) {
5138 std::string Code = R"(
5139 void Noop() { return; }
5141 void target() {
5142 Noop();
5143 // [[p]]
5146 runDataflow(
5147 Code,
5148 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5149 ASTContext &ASTCtx) {
5150 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5151 // This just tests that the analysis doesn't crash.
5153 {BuiltinOptions{ContextSensitiveOptions{}}});
5156 TEST(TransferTest, ContextSensitiveReturnTrue) {
5157 std::string Code = R"(
5158 bool GiveBool() { return true; }
5160 void target() {
5161 bool Foo = GiveBool();
5162 // [[p]]
5165 runDataflow(
5166 Code,
5167 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5168 ASTContext &ASTCtx) {
5169 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5170 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5172 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5173 ASSERT_THAT(FooDecl, NotNull());
5175 auto &FooVal = getFormula(*FooDecl, Env);
5176 EXPECT_TRUE(Env.flowConditionImplies(FooVal));
5178 {BuiltinOptions{ContextSensitiveOptions{}}});
5181 TEST(TransferTest, ContextSensitiveReturnFalse) {
5182 std::string Code = R"(
5183 bool GiveBool() { return false; }
5185 void target() {
5186 bool Foo = GiveBool();
5187 // [[p]]
5190 runDataflow(
5191 Code,
5192 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5193 ASTContext &ASTCtx) {
5194 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5195 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5197 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5198 ASSERT_THAT(FooDecl, NotNull());
5200 auto &FooVal = getFormula(*FooDecl, Env);
5201 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(FooVal)));
5203 {BuiltinOptions{ContextSensitiveOptions{}}});
5206 TEST(TransferTest, ContextSensitiveReturnArg) {
5207 std::string Code = R"(
5208 bool GiveBool();
5209 bool GiveBack(bool Arg) { return Arg; }
5211 void target() {
5212 bool Foo = GiveBool();
5213 bool Bar = GiveBack(Foo);
5214 bool Baz = Foo == Bar;
5215 // [[p]]
5218 runDataflow(
5219 Code,
5220 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5221 ASTContext &ASTCtx) {
5222 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5223 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5225 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
5226 ASSERT_THAT(BazDecl, NotNull());
5228 auto &BazVal = getFormula(*BazDecl, Env);
5229 EXPECT_TRUE(Env.flowConditionImplies(BazVal));
5231 {BuiltinOptions{ContextSensitiveOptions{}}});
5234 TEST(TransferTest, ContextSensitiveReturnInt) {
5235 std::string Code = R"(
5236 int identity(int x) { return x; }
5238 void target() {
5239 int y = identity(42);
5240 // [[p]]
5243 runDataflow(
5244 Code,
5245 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5246 ASTContext &ASTCtx) {
5247 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5248 // This just tests that the analysis doesn't crash.
5250 {BuiltinOptions{ContextSensitiveOptions{}}});
5253 TEST(TransferTest, ContextSensitiveMethodLiteral) {
5254 std::string Code = R"(
5255 class MyClass {
5256 public:
5257 bool giveBool() { return true; }
5260 void target() {
5261 MyClass MyObj;
5262 bool Foo = MyObj.giveBool();
5263 // [[p]]
5266 runDataflow(
5267 Code,
5268 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5269 ASTContext &ASTCtx) {
5270 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5271 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5273 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5274 ASSERT_THAT(FooDecl, NotNull());
5276 auto &FooVal = getFormula(*FooDecl, Env);
5277 EXPECT_TRUE(Env.flowConditionImplies(FooVal));
5279 {BuiltinOptions{ContextSensitiveOptions{}}});
5282 TEST(TransferTest, ContextSensitiveMethodGetter) {
5283 std::string Code = R"(
5284 class MyClass {
5285 public:
5286 bool getField() { return Field; }
5288 bool Field;
5291 void target() {
5292 MyClass MyObj;
5293 MyObj.Field = true;
5294 bool Foo = MyObj.getField();
5295 // [[p]]
5298 runDataflow(
5299 Code,
5300 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5301 ASTContext &ASTCtx) {
5302 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5303 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5305 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5306 ASSERT_THAT(FooDecl, NotNull());
5308 auto &FooVal = getFormula(*FooDecl, Env);
5309 EXPECT_TRUE(Env.flowConditionImplies(FooVal));
5311 {BuiltinOptions{ContextSensitiveOptions{}}});
5314 TEST(TransferTest, ContextSensitiveMethodSetter) {
5315 std::string Code = R"(
5316 class MyClass {
5317 public:
5318 void setField(bool Val) { Field = Val; }
5320 bool Field;
5323 void target() {
5324 MyClass MyObj;
5325 MyObj.setField(true);
5326 bool Foo = MyObj.Field;
5327 // [[p]]
5330 runDataflow(
5331 Code,
5332 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5333 ASTContext &ASTCtx) {
5334 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5335 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5337 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5338 ASSERT_THAT(FooDecl, NotNull());
5340 auto &FooVal = getFormula(*FooDecl, Env);
5341 EXPECT_TRUE(Env.flowConditionImplies(FooVal));
5343 {BuiltinOptions{ContextSensitiveOptions{}}});
5346 TEST(TransferTest, ContextSensitiveMethodGetterAndSetter) {
5347 std::string Code = R"(
5348 class MyClass {
5349 public:
5350 bool getField() { return Field; }
5351 void setField(bool Val) { Field = Val; }
5353 private:
5354 bool Field;
5357 void target() {
5358 MyClass MyObj;
5359 MyObj.setField(true);
5360 bool Foo = MyObj.getField();
5361 // [[p]]
5364 runDataflow(
5365 Code,
5366 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5367 ASTContext &ASTCtx) {
5368 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5369 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5371 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5372 ASSERT_THAT(FooDecl, NotNull());
5374 auto &FooVal = getFormula(*FooDecl, Env);
5375 EXPECT_TRUE(Env.flowConditionImplies(FooVal));
5377 {BuiltinOptions{ContextSensitiveOptions{}}});
5381 TEST(TransferTest, ContextSensitiveMethodTwoLayersVoid) {
5382 std::string Code = R"(
5383 class MyClass {
5384 public:
5385 void Inner() { MyField = true; }
5386 void Outer() { Inner(); }
5388 bool MyField;
5391 void target() {
5392 MyClass MyObj;
5393 MyObj.Outer();
5394 bool Foo = MyObj.MyField;
5395 // [[p]]
5398 runDataflow(
5399 Code,
5400 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5401 ASTContext &ASTCtx) {
5402 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5404 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5406 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5407 ASSERT_THAT(FooDecl, NotNull());
5409 auto &FooVal = getFormula(*FooDecl, Env);
5410 EXPECT_TRUE(Env.flowConditionImplies(FooVal));
5412 {BuiltinOptions{ContextSensitiveOptions{}}});
5415 TEST(TransferTest, ContextSensitiveMethodTwoLayersReturn) {
5416 std::string Code = R"(
5417 class MyClass {
5418 public:
5419 bool Inner() { return MyField; }
5420 bool Outer() { return Inner(); }
5422 bool MyField;
5425 void target() {
5426 MyClass MyObj;
5427 MyObj.MyField = true;
5428 bool Foo = MyObj.Outer();
5429 // [[p]]
5432 runDataflow(
5433 Code,
5434 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5435 ASTContext &ASTCtx) {
5436 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5438 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5440 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5441 ASSERT_THAT(FooDecl, NotNull());
5443 auto &FooVal = getFormula(*FooDecl, Env);
5444 EXPECT_TRUE(Env.flowConditionImplies(FooVal));
5446 {BuiltinOptions{ContextSensitiveOptions{}}});
5449 TEST(TransferTest, ContextSensitiveConstructorBody) {
5450 std::string Code = R"(
5451 class MyClass {
5452 public:
5453 MyClass() { MyField = true; }
5455 bool MyField;
5458 void target() {
5459 MyClass MyObj;
5460 bool Foo = MyObj.MyField;
5461 // [[p]]
5464 runDataflow(
5465 Code,
5466 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5467 ASTContext &ASTCtx) {
5468 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5469 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5471 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5472 ASSERT_THAT(FooDecl, NotNull());
5474 auto &FooVal = getFormula(*FooDecl, Env);
5475 EXPECT_TRUE(Env.flowConditionImplies(FooVal));
5477 {BuiltinOptions{ContextSensitiveOptions{}}});
5480 TEST(TransferTest, ContextSensitiveConstructorInitializer) {
5481 std::string Code = R"(
5482 class MyClass {
5483 public:
5484 MyClass() : MyField(true) {}
5486 bool MyField;
5489 void target() {
5490 MyClass MyObj;
5491 bool Foo = MyObj.MyField;
5492 // [[p]]
5495 runDataflow(
5496 Code,
5497 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5498 ASTContext &ASTCtx) {
5499 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5500 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5502 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
5503 ASSERT_THAT(FooDecl, NotNull());
5505 auto &FooVal = getFormula(*FooDecl, Env);
5506 EXPECT_TRUE(Env.flowConditionImplies(FooVal));
5508 {BuiltinOptions{ContextSensitiveOptions{}}});
5511 TEST(TransferTest, ContextSensitiveConstructorDefault) {
5512 std::string Code = R"(
5513 class MyClass {
5514 public:
5515 MyClass() = default;
5517 bool MyField = true;
5520 void target() {
5521 MyClass MyObj;
5522 bool Foo = MyObj.MyField;
5523 // [[p]]
5526 runDataflow(
5527 Code,
5528 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5529 ASTContext &ASTCtx) {
5530 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.flowConditionImplies(FooVal));
5539 {BuiltinOptions{ContextSensitiveOptions{}}});
5542 TEST(TransferTest, ContextSensitiveSelfReferentialClass) {
5543 // Test that the `this` pointer seen in the constructor has the same value
5544 // as the address of the variable the object is constructed into.
5545 std::string Code = R"(
5546 class MyClass {
5547 public:
5548 MyClass() : Self(this) {}
5549 MyClass *Self;
5552 void target() {
5553 MyClass MyObj;
5554 MyClass *SelfPtr = MyObj.Self;
5555 // [[p]]
5558 runDataflow(
5559 Code,
5560 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5561 ASTContext &ASTCtx) {
5562 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5564 const ValueDecl *MyObjDecl = findValueDecl(ASTCtx, "MyObj");
5565 ASSERT_THAT(MyObjDecl, NotNull());
5567 const ValueDecl *SelfDecl = findValueDecl(ASTCtx, "SelfPtr");
5568 ASSERT_THAT(SelfDecl, NotNull());
5570 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5571 auto &SelfVal = *cast<PointerValue>(Env.getValue(*SelfDecl));
5572 EXPECT_EQ(Env.getStorageLocation(*MyObjDecl), &SelfVal.getPointeeLoc());
5574 {BuiltinOptions{ContextSensitiveOptions{}}});
5577 TEST(TransferTest, UnnamedBitfieldInitializer) {
5578 std::string Code = R"(
5579 struct B {};
5580 struct A {
5581 unsigned a;
5582 unsigned : 4;
5583 unsigned c;
5584 B b;
5586 void target() {
5587 A a = {};
5588 A test = a;
5589 (void)test.c;
5592 runDataflow(
5593 Code,
5594 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5595 ASTContext &ASTCtx) {
5596 // This doesn't need a body because this test was crashing the framework
5597 // before handling correctly Unnamed bitfields in `InitListExpr`.
5601 // Repro for a crash that used to occur with chained short-circuiting logical
5602 // operators.
5603 TEST(TransferTest, ChainedLogicalOps) {
5604 std::string Code = R"(
5605 bool target() {
5606 bool b = true || false || false || false;
5607 // [[p]]
5608 return b;
5611 runDataflow(
5612 Code,
5613 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5614 ASTContext &ASTCtx) {
5615 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5616 auto &B = getValueForDecl<BoolValue>(ASTCtx, Env, "b").formula();
5617 EXPECT_TRUE(Env.flowConditionImplies(B));
5621 // Repro for a crash that used to occur when we call a `noreturn` function
5622 // within one of the operands of a `&&` or `||` operator.
5623 TEST(TransferTest, NoReturnFunctionInsideShortCircuitedBooleanOp) {
5624 std::string Code = R"(
5625 __attribute__((noreturn)) int doesnt_return();
5626 bool some_condition();
5627 void target(bool b1, bool b2) {
5628 // Neither of these should crash. In addition, if we don't terminate the
5629 // program, we know that the operators need to trigger the short-circuit
5630 // logic, so `NoreturnOnRhsOfAnd` will be false and `NoreturnOnRhsOfOr`
5631 // will be true.
5632 bool NoreturnOnRhsOfAnd = b1 && doesnt_return() > 0;
5633 bool NoreturnOnRhsOfOr = b2 || doesnt_return() > 0;
5635 // Calling a `noreturn` function on the LHS of an `&&` or `||` makes the
5636 // entire expression unreachable. So we know that in both of the following
5637 // cases, if `target()` terminates, the `else` branch was taken.
5638 bool NoreturnOnLhsMakesAndUnreachable = false;
5639 if (some_condition())
5640 doesnt_return() > 0 && some_condition();
5641 else
5642 NoreturnOnLhsMakesAndUnreachable = true;
5644 bool NoreturnOnLhsMakesOrUnreachable = false;
5645 if (some_condition())
5646 doesnt_return() > 0 || some_condition();
5647 else
5648 NoreturnOnLhsMakesOrUnreachable = true;
5650 // [[p]]
5653 runDataflow(
5654 Code,
5655 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5656 ASTContext &ASTCtx) {
5657 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
5658 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5659 auto &A = Env.arena();
5661 // Check that [[p]] is reachable with a non-false flow condition.
5662 EXPECT_FALSE(Env.flowConditionImplies(A.makeLiteral(false)));
5664 auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, "b1").formula();
5665 EXPECT_TRUE(Env.flowConditionImplies(A.makeNot(B1)));
5667 auto &NoreturnOnRhsOfAnd =
5668 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfAnd").formula();
5669 EXPECT_TRUE(Env.flowConditionImplies(A.makeNot(NoreturnOnRhsOfAnd)));
5671 auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, "b2").formula();
5672 EXPECT_TRUE(Env.flowConditionImplies(B2));
5674 auto &NoreturnOnRhsOfOr =
5675 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfOr")
5676 .formula();
5677 EXPECT_TRUE(Env.flowConditionImplies(NoreturnOnRhsOfOr));
5679 auto &NoreturnOnLhsMakesAndUnreachable = getValueForDecl<BoolValue>(
5680 ASTCtx, Env, "NoreturnOnLhsMakesAndUnreachable").formula();
5681 EXPECT_TRUE(Env.flowConditionImplies(NoreturnOnLhsMakesAndUnreachable));
5683 auto &NoreturnOnLhsMakesOrUnreachable = getValueForDecl<BoolValue>(
5684 ASTCtx, Env, "NoreturnOnLhsMakesOrUnreachable").formula();
5685 EXPECT_TRUE(Env.flowConditionImplies(NoreturnOnLhsMakesOrUnreachable));
5689 TEST(TransferTest, NewExpressions) {
5690 std::string Code = R"(
5691 void target() {
5692 int *p = new int(42);
5693 // [[after_new]]
5696 runDataflow(
5697 Code,
5698 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5699 ASTContext &ASTCtx) {
5700 const Environment &Env =
5701 getEnvironmentAtAnnotation(Results, "after_new");
5703 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p");
5705 EXPECT_THAT(Env.getValue(P.getPointeeLoc()), NotNull());
5709 TEST(TransferTest, NewExpressions_Structs) {
5710 std::string Code = R"(
5711 struct Inner {
5712 int InnerField;
5715 struct Outer {
5716 Inner OuterField;
5719 void target() {
5720 Outer *p = new Outer;
5721 // Access the fields to make sure the analysis actually generates children
5722 // for them in the `RecordStorageLocation` and `RecordValue`.
5723 p->OuterField.InnerField;
5724 // [[after_new]]
5727 runDataflow(
5728 Code,
5729 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5730 ASTContext &ASTCtx) {
5731 const Environment &Env =
5732 getEnvironmentAtAnnotation(Results, "after_new");
5734 const ValueDecl *OuterField = findValueDecl(ASTCtx, "OuterField");
5735 const ValueDecl *InnerField = findValueDecl(ASTCtx, "InnerField");
5737 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p");
5739 auto &OuterLoc = cast<RecordStorageLocation>(P.getPointeeLoc());
5740 auto &OuterFieldLoc =
5741 *cast<RecordStorageLocation>(OuterLoc.getChild(*OuterField));
5742 auto &InnerFieldLoc = *OuterFieldLoc.getChild(*InnerField);
5744 // Values for the struct and all fields exist after the new.
5745 EXPECT_THAT(Env.getValue(OuterLoc), NotNull());
5746 EXPECT_THAT(Env.getValue(OuterFieldLoc), NotNull());
5747 EXPECT_THAT(Env.getValue(InnerFieldLoc), NotNull());
5751 TEST(TransferTest, FunctionToPointerDecayHasValue) {
5752 std::string Code = R"(
5753 struct A { static void static_member_func(); };
5754 void target() {
5755 // To check that we're treating function-to-pointer decay correctly,
5756 // create two pointers, then verify they refer to the same storage
5757 // location.
5758 // We need to do the test this way because even if an initializer (in this
5759 // case, the function-to-pointer decay) does not create a value, we still
5760 // create a value for the variable.
5761 void (*non_member_p1)() = target;
5762 void (*non_member_p2)() = target;
5764 // Do the same thing but for a static member function.
5765 void (*member_p1)() = A::static_member_func;
5766 void (*member_p2)() = A::static_member_func;
5767 // [[p]]
5770 runDataflow(
5771 Code,
5772 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5773 ASTContext &ASTCtx) {
5774 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5776 auto &NonMemberP1 =
5777 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p1");
5778 auto &NonMemberP2 =
5779 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p2");
5780 EXPECT_EQ(&NonMemberP1.getPointeeLoc(), &NonMemberP2.getPointeeLoc());
5782 auto &MemberP1 =
5783 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p1");
5784 auto &MemberP2 =
5785 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p2");
5786 EXPECT_EQ(&MemberP1.getPointeeLoc(), &MemberP2.getPointeeLoc());
5790 // Check that a builtin function is not associated with a value. (It's only
5791 // possible to call builtin functions directly, not take their address.)
5792 TEST(TransferTest, BuiltinFunctionModeled) {
5793 std::string Code = R"(
5794 void target() {
5795 __builtin_expect(0, 0);
5796 // [[p]]
5799 runDataflow(
5800 Code,
5801 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5802 ASTContext &ASTCtx) {
5803 using ast_matchers::selectFirst;
5804 using ast_matchers::match;
5805 using ast_matchers::traverse;
5806 using ast_matchers::implicitCastExpr;
5807 using ast_matchers::hasCastKind;
5809 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5811 auto *ImplicitCast = selectFirst<ImplicitCastExpr>(
5812 "implicit_cast",
5813 match(traverse(TK_AsIs,
5814 implicitCastExpr(hasCastKind(CK_BuiltinFnToFnPtr))
5815 .bind("implicit_cast")),
5816 ASTCtx));
5818 ASSERT_THAT(ImplicitCast, NotNull());
5819 EXPECT_THAT(Env.getValue(*ImplicitCast), IsNull());
5823 // Check that a callee of a member operator call is modeled as a `PointerValue`.
5824 // Member operator calls are unusual in that their callee is a pointer that
5825 // stems from a `FunctionToPointerDecay`. In calls to non-operator non-static
5826 // member functions, the callee is a `MemberExpr` (which does not have pointer
5827 // type).
5828 // We want to make sure that we produce a pointer value for the callee in this
5829 // specific scenario and that its storage location is durable (for convergence).
5830 TEST(TransferTest, MemberOperatorCallModelsPointerForCallee) {
5831 std::string Code = R"(
5832 struct S {
5833 bool operator!=(S s);
5835 void target() {
5836 S s;
5837 (void)(s != s);
5838 (void)(s != s);
5839 // [[p]]
5842 runDataflow(
5843 Code,
5844 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5845 ASTContext &ASTCtx) {
5846 using ast_matchers::selectFirst;
5847 using ast_matchers::match;
5848 using ast_matchers::traverse;
5849 using ast_matchers::cxxOperatorCallExpr;
5851 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5853 auto Matches = match(
5854 traverse(TK_AsIs, cxxOperatorCallExpr().bind("call")), ASTCtx);
5856 ASSERT_EQ(Matches.size(), 2UL);
5858 auto *Call1 = Matches[0].getNodeAs<CXXOperatorCallExpr>("call");
5859 auto *Call2 = Matches[1].getNodeAs<CXXOperatorCallExpr>("call");
5861 ASSERT_THAT(Call1, NotNull());
5862 ASSERT_THAT(Call2, NotNull());
5864 EXPECT_EQ(cast<ImplicitCastExpr>(Call1->getCallee())->getCastKind(),
5865 CK_FunctionToPointerDecay);
5866 EXPECT_EQ(cast<ImplicitCastExpr>(Call2->getCallee())->getCastKind(),
5867 CK_FunctionToPointerDecay);
5869 auto *Ptr1 = cast<PointerValue>(Env.getValue(*Call1->getCallee()));
5870 auto *Ptr2 = cast<PointerValue>(Env.getValue(*Call2->getCallee()));
5872 ASSERT_EQ(&Ptr1->getPointeeLoc(), &Ptr2->getPointeeLoc());
5876 // Check that fields of anonymous records are modeled.
5877 TEST(TransferTest, AnonymousStruct) {
5878 std::string Code = R"(
5879 struct S {
5880 struct {
5881 bool b;
5884 void target() {
5885 S s;
5886 s.b = true;
5887 // [[p]]
5890 runDataflow(
5891 Code,
5892 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5893 ASTContext &ASTCtx) {
5894 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5895 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s");
5896 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b");
5897 const IndirectFieldDecl *IndirectField =
5898 findIndirectFieldDecl(ASTCtx, "b");
5900 auto *S = cast<RecordStorageLocation>(Env.getStorageLocation(*SDecl));
5901 auto &AnonStruct = *cast<RecordStorageLocation>(
5902 S->getChild(*cast<ValueDecl>(IndirectField->chain().front())));
5904 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env));
5905 ASSERT_TRUE(Env.flowConditionImplies(B->formula()));
5909 TEST(TransferTest, AnonymousStructWithInitializer) {
5910 std::string Code = R"(
5911 struct target {
5912 target() {
5913 (void)0;
5914 // [[p]]
5916 struct {
5917 bool b = true;
5921 runDataflow(
5922 Code,
5923 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5924 ASTContext &ASTCtx) {
5925 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5926 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b");
5927 const IndirectFieldDecl *IndirectField =
5928 findIndirectFieldDecl(ASTCtx, "b");
5930 auto *ThisLoc =
5931 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation());
5932 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild(
5933 *cast<ValueDecl>(IndirectField->chain().front())));
5935 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env));
5936 ASSERT_TRUE(Env.flowConditionImplies(B->formula()));
5940 TEST(TransferTest, AnonymousStructWithReferenceField) {
5941 std::string Code = R"(
5942 int global_i = 0;
5943 struct target {
5944 target() {
5945 (void)0;
5946 // [[p]]
5948 struct {
5949 int &i = global_i;
5953 runDataflow(
5954 Code,
5955 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5956 ASTContext &ASTCtx) {
5957 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
5958 const ValueDecl *GlobalIDecl = findValueDecl(ASTCtx, "global_i");
5959 const ValueDecl *IDecl = findValueDecl(ASTCtx, "i");
5960 const IndirectFieldDecl *IndirectField =
5961 findIndirectFieldDecl(ASTCtx, "i");
5963 auto *ThisLoc =
5964 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation());
5965 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild(
5966 *cast<ValueDecl>(IndirectField->chain().front())));
5968 ASSERT_EQ(AnonStruct.getChild(*IDecl),
5969 Env.getStorageLocation(*GlobalIDecl));
5973 TEST(TransferTest, EvaluateBlockWithUnreachablePreds) {
5974 // This is a crash repro.
5975 // `false` block may not have been processed when we try to evaluate the `||`
5976 // after visiting `true`, because it is not necessary (and therefore the edge
5977 // is marked unreachable). Trying to get the analysis state via
5978 // `getEnvironment` for the subexpression still should not crash.
5979 std::string Code = R"(
5980 int target(int i) {
5981 if ((i < 0 && true) || false) {
5982 return 0;
5984 return 0;
5987 runDataflow(
5988 Code,
5989 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
5990 ASTContext &ASTCtx) {});
5993 } // namespace