1 //===- unittests/Analysis/FlowSensitive/TransferTest.cpp ------------------===//
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
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"
32 using namespace clang
;
33 using namespace dataflow
;
36 using ::testing::IsNull
;
38 using ::testing::NotNull
;
39 using ::testing::UnorderedElementsAre
;
44 void(const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
47 DataflowAnalysisOptions Options
,
48 LangStandard::Kind Std
= LangStandard::lang_cxx17
,
49 llvm::StringRef TargetFun
= "target") {
50 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code
, VerifyResults
, Options
,
58 void(const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
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
>()},
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
"(
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
"(
92 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
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
"(
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
"(
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
"(
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
"(
192 struct A { S &Unmodeled = GlobalS; };
199 A &Foo = Bar.F1.F2.F3;
200 int Zab = Foo.Unmodeled.X;
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
;
222 FAIL() << "Unexpected field: " << Field
->getNameAsString();
225 ASSERT_THAT(UnmodeledDecl
, NotNull());
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
"(
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") {
269 FAIL() << "Unexpected field: " << Field
->getNameAsString();
272 ASSERT_THAT(BarDecl
, NotNull());
275 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
276 EXPECT_TRUE(isa
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
)));
280 TEST(TransferTest
, StructVarDeclWithInit
) {
281 std::string Code
= R
"(
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") {
312 FAIL() << "Unexpected field: " << Field
->getNameAsString();
315 ASSERT_THAT(BarDecl
, NotNull());
318 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
319 EXPECT_TRUE(isa
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
)));
323 TEST(TransferTest
, StructArrayVarDecl
) {
324 std::string Code
= R
"(
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
"(
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") {
376 FAIL() << "Unexpected field: " << Field
->getNameAsString();
379 ASSERT_THAT(BarDecl
, NotNull());
382 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
383 EXPECT_TRUE(isa
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
)));
387 TEST(TransferTest
, ReferenceVarDecl
) {
388 std::string Code
= R
"(
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
"(
437 (void)Foo.Bar.FooRef;
438 (void)Foo.Bar.FooPtr;
439 (void)Foo.Bar.BazRef;
440 (void)Foo.Bar.BazPtr;
444 runDataflow(Code
, [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>>
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") {
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") {
480 } else if (Field
->getNameAsString() == "FooPtr") {
482 } else if (Field
->getNameAsString() == "BazRef") {
484 } else if (Field
->getNameAsString() == "BazPtr") {
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());
496 *cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
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
"(
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
"(
576 (void)Foo->Bar->FooRef;
577 (void)Foo->Bar->FooPtr;
578 (void)Foo->Bar->BazRef;
579 (void)Foo->Bar->BazPtr;
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
>()
597 ->isStructureType());
598 const auto FooFields
= FooDecl
->getType()
599 ->getAs
<PointerType
>()
604 FieldDecl
*BarDecl
= nullptr;
605 for (FieldDecl
*Field
: FooFields
) {
606 if (Field
->getNameAsString() == "Bar") {
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
>()
618 ->isStructureType());
619 const auto BarFields
= BarDecl
->getType()
620 ->getAs
<PointerType
>()
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") {
632 } else if (Field
->getNameAsString() == "FooPtr") {
634 } else if (Field
->getNameAsString() == "BazRef") {
636 } else if (Field
->getNameAsString() == "BazPtr") {
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());
648 *cast
<ScalarStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
649 const auto &FooVal
= *cast
<PointerValue
>(Env
.getValue(FooLoc
));
650 const auto &FooPointeeLoc
=
651 cast
<RecordStorageLocation
>(FooVal
.getPointeeLoc());
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
"(
682 target &self = *this;
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
"(
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) {
748 runDataflow(Code
, [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>>
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
"(
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
"(
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
"(
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
"(
873 int Baz = (Bar = Foo);
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
"(
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
"(
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) {
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
"(
1028 void target(A Foo) {
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") {
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
"(
1066 void target(A &Foo) {
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
"(
1093 void target(A *Foo) {
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
"(
1126 void target(A Foo) {
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") {
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
"(
1170 enum E { ONE, TWO };
1173 void target(A Foo) {
1178 // Minimal expectations -- we're just testing that it doesn't crash, since
1179 // enums aren't interpreted.
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
"(
1200 friend void target();
1203 class B : public A {
1211 friend void target();
1217 (void)Foo.AProtected;
1221 (void)Foo.BProtected;
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
;
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
;
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());
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") {
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
"(
1327 struct B : public A {
1336 runDataflow(Code
, derivedBaseMemberExpectations
);
1339 TEST(TransferTest
, DerivedBaseMemberPrivateFriend
) {
1340 // Include an access to `Foo.Bar` to verify the analysis doesn't crash on that
1342 std::string Code
= R
"(
1345 friend void target();
1348 struct B : public A {
1357 runDataflow(Code
, derivedBaseMemberExpectations
);
1360 TEST(TransferTest
, ClassMember
) {
1361 std::string Code
= R
"(
1367 void target(A Foo) {
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") {
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
"(
1415 A(int I) : Bar(I) {}
1419 class B : public A {
1428 checkDataflow
<NoopAnalysis
>(
1429 AnalysisInputs
<NoopAnalysis
>(
1430 Code
, cxxConstructorDecl(ofClass(hasName("B"))),
1431 [](ASTContext
&C
, Environment
&) { return NoopAnalysis(C
); })
1433 {"-fsyntax-only", "-fno-delayed-template-parsing",
1434 "-std=" + std::string(LangStandard::getLangStandardForKind(
1435 LangStandard::lang_cxx17
)
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
1444 EXPECT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1449 TEST(TransferTest
, StructModeledFieldsWithAccessor
) {
1450 std::string Code
= R
"(
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; }
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.
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
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
"(
1513 struct Intermediate : Base1 {
1521 struct MostDerived : public Intermediate, Base2 {
1529 MD.intermediate_2 = 1;
1531 MD.most_derived_2 = 1;
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
"(
1560 struct Intermediate : Base1 {
1566 struct MostDerived : public Intermediate, Base2 {
1571 MostDerived MD = {};
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
)),
1588 ASSERT_THAT(cast
<IntegerValue
>(
1589 getFieldValue(&MD
, *findValueDecl(ASTCtx
, "intermediate"), Env
)),
1591 ASSERT_THAT(cast
<IntegerValue
>(
1592 getFieldValue(&MD
, *findValueDecl(ASTCtx
, "base2"), Env
)),
1594 ASSERT_THAT(cast
<IntegerValue
>(
1595 getFieldValue(&MD
, *findValueDecl(ASTCtx
, "most_derived"), Env
)),
1600 TEST(TransferTest
, ReferenceMember
) {
1601 std::string Code
= R
"(
1606 void target(A Foo) {
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") {
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
"(
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") {
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
"(
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") {
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
"(
1796 // Mention the fields to ensure they're included in the analysis.
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
"(
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
"(
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
"(
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
"(
1938 target(int Foo) : Bar(Foo) {
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
"(
1971 target(int Foo) : Bar(Foo) {
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
"(
2004 target(int &Foo) : Bar(Foo) {
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
"(
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
"(
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
"(
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
"(
2192 struct Derived : public Base {
2193 using Base::operator=;
2196 void target(Base B, Derived D) {
2205 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2206 ASTContext
&ASTCtx
) {});
2209 TEST(TransferTest
, AssignmentOperatorFromCallResult
) {
2210 std::string Code
= R
"(
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 {};
2238 S1 = S2; // Only Dst has InitListExpr.
2239 S3 = S1; // Only Src has InitListExpr.
2245 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2246 ASTContext
&ASTCtx
) {});
2249 TEST(TransferTest
, CopyConstructor
) {
2250 std::string Code
= R
"(
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());
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
);
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
"(
2328 A(const A& a, bool def = true) { Baz = a.Baz; }
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
"(
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
"(
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
"(
2448 const S &returnsSRef();
2455 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2456 ASTContext
&ASTCtx
) {});
2459 TEST(TransferTest
, MoveConstructor
) {
2460 std::string Code
= R
"(
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);
2484 Foo = std::move(Bar);
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
"(
2537 virtual ~A() = default;
2542 void target(A Foo) {
2543 int Bar = A(Foo).Baz;
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);
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) {
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) {
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) {
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);
2687 int *FooX = nullptr;
2688 int *FooY = nullptr;
2689 bool **Bar = nullptr;
2691 my_nullptr_t Null = 0;
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
"(
2752 int S::*MemberPointer = &S::i;
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
"(
2775 void (S::*MemberPointer)() = &S::Method;
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
"(
2796 int Foo::*MemberPointer = nullptr;
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
"(
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) {
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>
2874 checkDataflowWithNoopAnalysis(Code
),
2875 llvm::FailedWithMessage("Cannot analyze templated declarations"));
2878 TEST(TransferTest
, CannotAnalyzeMethodOfClassTemplate
) {
2879 std::string Code
= R
"(
2880 template <typename T>
2886 checkDataflowWithNoopAnalysis(Code
),
2887 llvm::FailedWithMessage("Cannot analyze templated declarations"));
2890 TEST(TransferTest
, VarDeclInitAssignConditionalOperator
) {
2891 std::string Code
= R
"(
2894 void target(A Foo, A Bar, bool Cond) {
2895 A Baz = Cond ? Foo : Bar;
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) {
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
"(
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
"(
2997 void target(int BarArg, int FooArg, int QuxArg) {
2998 B Quux{BarArg, {FooArg}, QuxArg};
3003 std::string BraceElisionCode
= R
"(
3014 void target(int BarArg, int FooArg, int QuxArg) {
3015 B Quux = {BarArg, FooArg, QuxArg};
3020 for (const std::string
&Code
: {BracesCode
, BraceElisionCode
}) {
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
"(
3082 void target(int i) {
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
"(
3109 void target(int i) {
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");
3127 *cast
<IntegerValue
>(getFieldValue(&SLoc
, *I1FieldDecl
, Env
));
3128 EXPECT_EQ(&I1Value
, &IValue
);
3130 *cast
<IntegerValue
>(getFieldValue(&SLoc
, *I2FieldDecl
, Env
));
3131 EXPECT_NE(&I2Value
, &IValue
);
3135 TEST(TransferTest
, AssignToUnionMember
) {
3136 std::string Code
= R
"(
3141 void target(int Bar) {
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") {
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
"(
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);
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);
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;
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();
3364 &A
.makeAnd(A
.makeAnd(A
.makeAnd(AVal
->formula(), BVal
->formula()),
3371 TEST(TransferTest
, AssignFromBoolNegation
) {
3372 std::string Code
= R
"(
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);
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
3431 TEST(TransferTest
, BuiltinExpectBoolArg
) {
3432 std::string Code
= R
"(
3433 void target(bool Foo) {
3434 bool Bar = __builtin_expect(Foo, true);
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) {
3462 __builtin_unreachable();
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) {
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) {
3525 __builtin_debugtrap();
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
"(
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
"(
3576 static int Foo, Bar;
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
"(
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
"(
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
"(
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
"(
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
));
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) {
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
);
3774 EnvElse
.flowConditionImplies(EnvElse
.arena().makeNot(BarValElse
)));
3778 TEST(TransferTest
, BooleanInequality
) {
3779 std::string Code
= R
"(
3780 void target(bool Bar) {
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
);
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
"(
3816 bool equal = (42 == 42);
3822 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3823 ASTContext
&ASTCtx
) {
3824 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
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) {
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
"(
3895 // The key property that we are verifying is implicit in `runDataflow` --
3896 // namely, that the analysis succeeds, rather than hitting the maximum number
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
"(
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
3947 Env
.flowConditionImplies(Env
.arena().makeNot(ErrVal
)));
3951 TEST(TransferTest
, LoopWithReferenceAssignmentConverges
) {
3952 std::string Code
= R
"(
3964 // The key property that we are verifying is that the analysis succeeds,
3965 // rather than hitting the maximum number of iterations.
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
"(
3987 void target(Lookup val, bool b) {
3988 const Lookup* l = nullptr;
3997 // The key property that we are verifying is implicit in `runDataflow` --
3998 // namely, that the analysis succeeds, rather than hitting the maximum number
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());
4017 auto *LVal
= dyn_cast
<PointerValue
>(InnerEnv
.getValue(*LDecl
));
4018 ASSERT_THAT(LVal
, NotNull());
4020 EXPECT_EQ(&LVal
->getPointeeLoc(),
4021 InnerEnv
.getStorageLocation(*ValDecl
));
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) {
4042 if (some_condition())
4049 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code
), llvm::Succeeded());
4052 TEST(TransferTest
, LoopDereferencingChangingRecordPointerConverges
) {
4053 std::string Code
= R
"cc(
4058 bool some_condition();
4060 void target(Lookup l1, Lookup l2) {
4064 if (some_condition())
4071 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code
), llvm::Succeeded());
4074 TEST(TransferTest
, DoesNotCrashOnUnionThisExpr
) {
4075 std::string Code
= R
"(
4087 // This is a crash regression test when calling the transfer function on a
4088 // `CXXThisExpr` that refers to a union.
4091 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
4093 LangStandard::lang_cxx17
, /*ApplyBuiltinTransfer=*/true, "operator=");
4096 TEST(TransferTest
, StructuredBindingAssignFromStructIntMembersToRefs
) {
4097 std::string Code
= R
"(
4107 auto &FooRef = Baz.Foo;
4108 auto &BarRef = Baz.Bar;
4109 auto &[BoundFooRef, BoundBarRef] = Baz;
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
"(
4163 void target(A Baz) {
4166 auto &FooRef = Baz.Foo;
4167 auto &BarRef = Baz.Bar;
4168 auto &[BoundFooRef, BoundBarRef] = Baz;
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
"(
4226 auto &FooRef = Baz.Foo;
4227 auto &BarRef = Baz.Bar;
4228 auto [BoundFoo, BoundBar] = Baz;
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
"(
4279 template <class> struct tuple_size;
4280 template <std::size_t, class> struct tuple_element;
4281 template <class...> class tuple;
4284 template <class T, T v>
4285 struct size_helper { static const T value = v; };
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...>);
4302 std::tuple<bool, int> makeTuple();
4304 void target(bool B) {
4305 auto [BoundFoo, BoundBar] = makeTuple();
4307 // Include if-then-else to test interaction of `BindingDecl` with join.
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
"(
4360 template <class> struct tuple_size;
4361 template <std::size_t, class> struct tuple_element;
4362 template <class...> class tuple;
4365 template <class T, T v>
4366 struct size_helper { static const T value = v; };
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...>);
4383 std::tuple<bool, int> &getTuple();
4385 void target(bool B) {
4386 auto &[BoundFoo, BoundBar] = getTuple();
4388 // Include if-then-else to test interaction of `BindingDecl` with join.
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);
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) {
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
);
4496 ElseEnv
.flowConditionImplies(ElseEnv
.arena().makeNot(ElseFooVal
)));
4500 TEST(TransferTest
, WhileStmtBranchExtendsFlowCondition
) {
4501 std::string Code
= R
"(
4502 void target(bool Foo) {
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) {
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
);
4573 AfterLoopEnv
.flowConditionImplies(A
.makeNot(AfterLoopFooVal
)));
4575 AfterLoopEnv
.flowConditionImplies(A
.makeNot(AfterLoopBarVal
)));
4579 TEST(TransferTest
, ForStmtBranchExtendsFlowCondition
) {
4580 std::string Code
= R
"(
4581 void target(bool Foo) {
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) {
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
"(
4641 void SetBool(bool &Var) { Var = true; }
4644 bool Foo = GiveBool();
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
"(
4669 S& target(bool b, S &s) {
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
"(
4695 S& target(bool b, S &s) {
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
"(
4729 S &callee(bool b, S &s1_parm, S &s2_parm) {
4735 void target(bool b) {
4740 S &return_dont_know = callee(b, s1, s2);
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
"(
4780 void SetBool(bool &Var) { Var = true; }
4783 bool Foo = GiveBool();
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
"(
4808 void SetBool(bool &Var) { Var = true; }
4811 bool Foo = GiveBool();
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
"(
4835 void SetBool(bool &Var) { Var = false; }
4838 bool Foo = GiveBool();
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
"(
4862 void SetBool(bool &Var, bool Val) { Var = Val; }
4865 bool Foo = GiveBool();
4866 bool Bar = GiveBool();
4868 SetBool(Bar, false);
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
"(
4900 void SetBool1(bool &Var) { Var = true; }
4901 void SetBool2(bool &Var) { SetBool1(Var); }
4904 bool Foo = GiveBool();
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
"(
4929 void SetBool1(bool &Var) { Var = true; }
4930 void SetBool2(bool &Var) { SetBool1(Var); }
4933 bool Foo = GiveBool();
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
"(
4957 void SetBool1(bool &Var) { Var = true; }
4958 void SetBool2(bool &Var) { SetBool1(Var); }
4959 void SetBool3(bool &Var) { SetBool2(Var); }
4962 bool Foo = GiveBool();
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
"(
4987 void SetBool1(bool &Var) { Var = true; }
4988 void SetBool2(bool &Var) { SetBool1(Var); }
4989 void SetBool3(bool &Var) { SetBool2(Var); }
4992 bool Foo = GiveBool();
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) {
5025 bool Pong(bool X, bool Y) {
5034 bool Foo = Ping(false, false);
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) {
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) {
5109 IfCond(Foo, Bar, Baz);
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; }
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; }
5161 bool Foo = GiveBool();
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; }
5186 bool Foo = GiveBool();
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
"(
5209 bool GiveBack(bool Arg) { return Arg; }
5212 bool Foo = GiveBool();
5213 bool Bar = GiveBack(Foo);
5214 bool Baz = Foo == Bar;
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; }
5239 int y = identity(42);
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
"(
5257 bool giveBool() { return true; }
5262 bool Foo = MyObj.giveBool();
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
"(
5286 bool getField() { return Field; }
5294 bool Foo = MyObj.getField();
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
"(
5318 void setField(bool Val) { Field = Val; }
5325 MyObj.setField(true);
5326 bool Foo = MyObj.Field;
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
"(
5350 bool getField() { return Field; }
5351 void setField(bool Val) { Field = Val; }
5359 MyObj.setField(true);
5360 bool Foo = MyObj.getField();
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
"(
5385 void Inner() { MyField = true; }
5386 void Outer() { Inner(); }
5394 bool Foo = MyObj.MyField;
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
"(
5419 bool Inner() { return MyField; }
5420 bool Outer() { return Inner(); }
5427 MyObj.MyField = true;
5428 bool Foo = MyObj.Outer();
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
"(
5453 MyClass() { MyField = true; }
5460 bool Foo = MyObj.MyField;
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
"(
5484 MyClass() : MyField(true) {}
5491 bool Foo = MyObj.MyField;
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
"(
5515 MyClass() = default;
5517 bool MyField = true;
5522 bool Foo = MyObj.MyField;
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
"(
5548 MyClass() : Self(this) {}
5554 MyClass *SelfPtr = MyObj.Self;
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
"(
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
5603 TEST(TransferTest
, ChainedLogicalOps
) {
5604 std::string Code
= R
"(
5606 bool b = true || false || false || false;
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`
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();
5642 NoreturnOnLhsMakesAndUnreachable = true;
5644 bool NoreturnOnLhsMakesOrUnreachable = false;
5645 if (some_condition())
5646 doesnt_return() > 0 || some_condition();
5648 NoreturnOnLhsMakesOrUnreachable = true;
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")
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
"(
5692 int *p = new int(42);
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
"(
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;
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(); };
5755 // To check that we're treating function-to-pointer decay correctly,
5756 // create two pointers, then verify they refer to the same storage
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;
5772 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5773 ASTContext
&ASTCtx
) {
5774 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5777 getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "non_member_p1");
5779 getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "non_member_p2");
5780 EXPECT_EQ(&NonMemberP1
.getPointeeLoc(), &NonMemberP2
.getPointeeLoc());
5783 getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "member_p1");
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
"(
5795 __builtin_expect(0, 0);
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
>(
5813 match(traverse(TK_AsIs
,
5814 implicitCastExpr(hasCastKind(CK_BuiltinFnToFnPtr
))
5815 .bind("implicit_cast")),
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
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
"(
5833 bool operator!=(S s);
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
"(
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
"(
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");
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
"(
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");
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
"(
5981 if ((i < 0 && true) || false) {
5989 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5990 ASTContext
&ASTCtx
) {});