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 void runDataflowOnLambda(
72 void(const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
75 DataflowAnalysisOptions Options
,
76 LangStandard::Kind Std
= LangStandard::lang_cxx17
) {
78 checkDataflowWithNoopAnalysis(
80 ast_matchers::hasDeclContext(
81 ast_matchers::cxxRecordDecl(ast_matchers::isLambda())),
82 VerifyResults
, Options
, Std
),
86 void runDataflowOnLambda(
89 void(const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
92 LangStandard::Kind Std
= LangStandard::lang_cxx17
,
93 bool ApplyBuiltinTransfer
= true) {
94 runDataflowOnLambda(Code
, std::move(VerifyResults
),
95 {ApplyBuiltinTransfer
? BuiltinOptions
{}
96 : std::optional
<BuiltinOptions
>()},
100 const Formula
&getFormula(const ValueDecl
&D
, const Environment
&Env
) {
101 return cast
<BoolValue
>(Env
.getValue(D
))->formula();
104 TEST(TransferTest
, CNotSupported
) {
105 std::string Code
= R
"(
108 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(
109 Code
, [](const auto &, auto &) {}, {BuiltinOptions
{}},
110 LangStandard::lang_c89
),
111 llvm::FailedWithMessage("Can only analyze C++"));
114 TEST(TransferTest
, IntVarDeclNotTrackedWhenTransferDisabled
) {
115 std::string Code
= R
"(
123 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
124 ASTContext
&ASTCtx
) {
125 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
126 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
128 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
129 ASSERT_THAT(FooDecl
, NotNull());
131 EXPECT_EQ(Env
.getStorageLocation(*FooDecl
), nullptr);
133 LangStandard::lang_cxx17
,
134 /*ApplyBuiltinTransfer=*/false);
137 TEST(TransferTest
, BoolVarDecl
) {
138 std::string Code
= R
"(
146 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
147 ASTContext
&ASTCtx
) {
148 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
149 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
151 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
152 ASSERT_THAT(FooDecl
, NotNull());
154 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
155 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
157 const Value
*FooVal
= Env
.getValue(*FooLoc
);
158 EXPECT_TRUE(isa_and_nonnull
<BoolValue
>(FooVal
));
162 TEST(TransferTest
, IntVarDecl
) {
163 std::string Code
= R
"(
171 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
172 ASTContext
&ASTCtx
) {
173 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
174 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
176 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
177 ASSERT_THAT(FooDecl
, NotNull());
179 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
180 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
182 const Value
*FooVal
= Env
.getValue(*FooLoc
);
183 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
187 TEST(TransferTest
, StructIncomplete
) {
188 std::string Code
= R
"(
198 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
199 ASTContext
&ASTCtx
) {
200 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
201 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
203 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
204 ASSERT_THAT(FooDecl
, NotNull());
205 auto *FooValue
= dyn_cast_or_null
<PointerValue
>(Env
.getValue(*FooDecl
));
206 ASSERT_THAT(FooValue
, NotNull());
208 EXPECT_TRUE(isa
<RecordStorageLocation
>(FooValue
->getPointeeLoc()));
209 auto *FooPointeeValue
= Env
.getValue(FooValue
->getPointeeLoc());
210 ASSERT_THAT(FooPointeeValue
, NotNull());
211 EXPECT_TRUE(isa
<RecordValue
>(FooPointeeValue
));
215 // As a memory optimization, we prevent modeling fields nested below a certain
216 // level (currently, depth 3). This test verifies this lack of modeling. We also
217 // include a regression test for the case that the unmodeled field is a
218 // reference to a struct; previously, we crashed when accessing such a field.
219 TEST(TransferTest
, StructFieldUnmodeled
) {
220 std::string Code
= R
"(
223 struct A { S &Unmodeled = GlobalS; };
230 A &Foo = Bar.F1.F2.F3;
231 int Zab = Foo.Unmodeled.X;
237 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
238 ASTContext
&ASTCtx
) {
239 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
240 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
242 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
243 ASSERT_THAT(FooDecl
, NotNull());
244 QualType FooReferentType
= FooDecl
->getType()->getPointeeType();
245 ASSERT_TRUE(FooReferentType
->isStructureType());
246 auto FooFields
= FooReferentType
->getAsRecordDecl()->fields();
248 FieldDecl
*UnmodeledDecl
= nullptr;
249 for (FieldDecl
*Field
: FooFields
) {
250 if (Field
->getNameAsString() == "Unmodeled") {
251 UnmodeledDecl
= Field
;
253 FAIL() << "Unexpected field: " << Field
->getNameAsString();
256 ASSERT_THAT(UnmodeledDecl
, NotNull());
259 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
260 const auto *UnmodeledLoc
= FooLoc
->getChild(*UnmodeledDecl
);
261 ASSERT_TRUE(isa
<RecordStorageLocation
>(UnmodeledLoc
));
262 EXPECT_THAT(Env
.getValue(*UnmodeledLoc
), IsNull());
264 const ValueDecl
*ZabDecl
= findValueDecl(ASTCtx
, "Zab");
265 ASSERT_THAT(ZabDecl
, NotNull());
266 EXPECT_THAT(Env
.getValue(*ZabDecl
), NotNull());
270 TEST(TransferTest
, StructVarDecl
) {
271 std::string Code
= R
"(
284 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
285 ASTContext
&ASTCtx
) {
286 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
287 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
289 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
290 ASSERT_THAT(FooDecl
, NotNull());
292 ASSERT_TRUE(FooDecl
->getType()->isStructureType());
293 auto FooFields
= FooDecl
->getType()->getAsRecordDecl()->fields();
295 FieldDecl
*BarDecl
= nullptr;
296 for (FieldDecl
*Field
: FooFields
) {
297 if (Field
->getNameAsString() == "Bar") {
300 FAIL() << "Unexpected field: " << Field
->getNameAsString();
303 ASSERT_THAT(BarDecl
, NotNull());
306 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
307 EXPECT_TRUE(isa
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
)));
311 TEST(TransferTest
, StructVarDeclWithInit
) {
312 std::string Code
= R
"(
327 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
328 ASTContext
&ASTCtx
) {
329 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
330 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
332 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
333 ASSERT_THAT(FooDecl
, NotNull());
335 ASSERT_TRUE(FooDecl
->getType()->isStructureType());
336 auto FooFields
= FooDecl
->getType()->getAsRecordDecl()->fields();
338 FieldDecl
*BarDecl
= nullptr;
339 for (FieldDecl
*Field
: FooFields
) {
340 if (Field
->getNameAsString() == "Bar") {
343 FAIL() << "Unexpected field: " << Field
->getNameAsString();
346 ASSERT_THAT(BarDecl
, NotNull());
349 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
350 EXPECT_TRUE(isa
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
)));
354 TEST(TransferTest
, StructArrayVarDecl
) {
355 std::string Code
= R
"(
365 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
366 ASTContext
&ASTCtx
) {
367 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
369 const ValueDecl
*ArrayDecl
= findValueDecl(ASTCtx
, "Array");
371 // We currently don't create values for arrays.
372 ASSERT_THAT(Env
.getValue(*ArrayDecl
), IsNull());
376 TEST(TransferTest
, ClassVarDecl
) {
377 std::string Code
= R
"(
391 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
392 ASTContext
&ASTCtx
) {
393 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
394 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
396 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
397 ASSERT_THAT(FooDecl
, NotNull());
399 ASSERT_TRUE(FooDecl
->getType()->isClassType());
400 auto FooFields
= FooDecl
->getType()->getAsRecordDecl()->fields();
402 FieldDecl
*BarDecl
= nullptr;
403 for (FieldDecl
*Field
: FooFields
) {
404 if (Field
->getNameAsString() == "Bar") {
407 FAIL() << "Unexpected field: " << Field
->getNameAsString();
410 ASSERT_THAT(BarDecl
, NotNull());
413 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
414 EXPECT_TRUE(isa
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
)));
418 TEST(TransferTest
, ReferenceVarDecl
) {
419 std::string Code
= R
"(
431 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
432 ASTContext
&ASTCtx
) {
433 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
434 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
436 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
437 ASSERT_THAT(FooDecl
, NotNull());
439 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
440 ASSERT_TRUE(isa_and_nonnull
<RecordStorageLocation
>(FooLoc
));
442 const Value
*FooReferentVal
= Env
.getValue(*FooLoc
);
443 EXPECT_TRUE(isa_and_nonnull
<RecordValue
>(FooReferentVal
));
447 TEST(TransferTest
, SelfReferentialReferenceVarDecl
) {
448 std::string Code
= R
"(
468 (void)Foo.Bar.FooRef;
469 (void)Foo.Bar.FooPtr;
470 (void)Foo.Bar.BazRef;
471 (void)Foo.Bar.BazPtr;
475 runDataflow(Code
, [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>>
477 ASTContext
&ASTCtx
) {
478 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
479 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
481 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
482 ASSERT_THAT(FooDecl
, NotNull());
484 ASSERT_TRUE(FooDecl
->getType()->isReferenceType());
485 ASSERT_TRUE(FooDecl
->getType().getNonReferenceType()->isStructureType());
486 const auto FooFields
=
487 FooDecl
->getType().getNonReferenceType()->getAsRecordDecl()->fields();
489 FieldDecl
*BarDecl
= nullptr;
490 for (FieldDecl
*Field
: FooFields
) {
491 if (Field
->getNameAsString() == "Bar") {
494 FAIL() << "Unexpected field: " << Field
->getNameAsString();
497 ASSERT_THAT(BarDecl
, NotNull());
499 ASSERT_TRUE(BarDecl
->getType()->isReferenceType());
500 ASSERT_TRUE(BarDecl
->getType().getNonReferenceType()->isStructureType());
501 const auto BarFields
=
502 BarDecl
->getType().getNonReferenceType()->getAsRecordDecl()->fields();
504 FieldDecl
*FooRefDecl
= nullptr;
505 FieldDecl
*FooPtrDecl
= nullptr;
506 FieldDecl
*BazRefDecl
= nullptr;
507 FieldDecl
*BazPtrDecl
= nullptr;
508 for (FieldDecl
*Field
: BarFields
) {
509 if (Field
->getNameAsString() == "FooRef") {
511 } else if (Field
->getNameAsString() == "FooPtr") {
513 } else if (Field
->getNameAsString() == "BazRef") {
515 } else if (Field
->getNameAsString() == "BazPtr") {
518 FAIL() << "Unexpected field: " << Field
->getNameAsString();
521 ASSERT_THAT(FooRefDecl
, NotNull());
522 ASSERT_THAT(FooPtrDecl
, NotNull());
523 ASSERT_THAT(BazRefDecl
, NotNull());
524 ASSERT_THAT(BazPtrDecl
, NotNull());
527 *cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
530 *cast
<RecordStorageLocation
>(FooLoc
.getChild(*BarDecl
));
532 const auto &FooReferentLoc
=
533 *cast
<RecordStorageLocation
>(BarLoc
.getChild(*FooRefDecl
));
534 EXPECT_THAT(Env
.getValue(FooReferentLoc
), NotNull());
535 EXPECT_THAT(getFieldValue(&FooReferentLoc
, *BarDecl
, Env
), IsNull());
537 const auto &FooPtrVal
=
538 *cast
<PointerValue
>(getFieldValue(&BarLoc
, *FooPtrDecl
, Env
));
539 const auto &FooPtrPointeeLoc
=
540 cast
<RecordStorageLocation
>(FooPtrVal
.getPointeeLoc());
541 EXPECT_THAT(Env
.getValue(FooPtrPointeeLoc
), NotNull());
542 EXPECT_THAT(getFieldValue(&FooPtrPointeeLoc
, *BarDecl
, Env
), IsNull());
544 EXPECT_THAT(getFieldValue(&BarLoc
, *BazRefDecl
, Env
), NotNull());
546 const auto &BazPtrVal
=
547 *cast
<PointerValue
>(getFieldValue(&BarLoc
, *BazPtrDecl
, Env
));
548 const StorageLocation
&BazPtrPointeeLoc
= BazPtrVal
.getPointeeLoc();
549 EXPECT_THAT(Env
.getValue(BazPtrPointeeLoc
), NotNull());
553 TEST(TransferTest
, PointerVarDecl
) {
554 std::string Code
= R
"(
566 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
567 ASTContext
&ASTCtx
) {
568 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
569 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
571 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
572 ASSERT_THAT(FooDecl
, NotNull());
574 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
575 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
577 const PointerValue
*FooVal
= cast
<PointerValue
>(Env
.getValue(*FooLoc
));
578 const StorageLocation
&FooPointeeLoc
= FooVal
->getPointeeLoc();
579 EXPECT_TRUE(isa
<RecordStorageLocation
>(&FooPointeeLoc
));
581 const Value
*FooPointeeVal
= Env
.getValue(FooPointeeLoc
);
582 EXPECT_TRUE(isa_and_nonnull
<RecordValue
>(FooPointeeVal
));
586 TEST(TransferTest
, SelfReferentialPointerVarDecl
) {
587 std::string Code
= R
"(
607 (void)Foo->Bar->FooRef;
608 (void)Foo->Bar->FooPtr;
609 (void)Foo->Bar->BazRef;
610 (void)Foo->Bar->BazPtr;
616 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
617 ASTContext
&ASTCtx
) {
618 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
619 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
621 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
622 ASSERT_THAT(FooDecl
, NotNull());
624 ASSERT_TRUE(FooDecl
->getType()->isPointerType());
625 ASSERT_TRUE(FooDecl
->getType()
626 ->getAs
<PointerType
>()
628 ->isStructureType());
629 const auto FooFields
= FooDecl
->getType()
630 ->getAs
<PointerType
>()
635 FieldDecl
*BarDecl
= nullptr;
636 for (FieldDecl
*Field
: FooFields
) {
637 if (Field
->getNameAsString() == "Bar") {
640 FAIL() << "Unexpected field: " << Field
->getNameAsString();
643 ASSERT_THAT(BarDecl
, NotNull());
645 ASSERT_TRUE(BarDecl
->getType()->isPointerType());
646 ASSERT_TRUE(BarDecl
->getType()
647 ->getAs
<PointerType
>()
649 ->isStructureType());
650 const auto BarFields
= BarDecl
->getType()
651 ->getAs
<PointerType
>()
656 FieldDecl
*FooRefDecl
= nullptr;
657 FieldDecl
*FooPtrDecl
= nullptr;
658 FieldDecl
*BazRefDecl
= nullptr;
659 FieldDecl
*BazPtrDecl
= nullptr;
660 for (FieldDecl
*Field
: BarFields
) {
661 if (Field
->getNameAsString() == "FooRef") {
663 } else if (Field
->getNameAsString() == "FooPtr") {
665 } else if (Field
->getNameAsString() == "BazRef") {
667 } else if (Field
->getNameAsString() == "BazPtr") {
670 FAIL() << "Unexpected field: " << Field
->getNameAsString();
673 ASSERT_THAT(FooRefDecl
, NotNull());
674 ASSERT_THAT(FooPtrDecl
, NotNull());
675 ASSERT_THAT(BazRefDecl
, NotNull());
676 ASSERT_THAT(BazPtrDecl
, NotNull());
679 *cast
<ScalarStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
680 const auto &FooVal
= *cast
<PointerValue
>(Env
.getValue(FooLoc
));
681 const auto &FooPointeeLoc
=
682 cast
<RecordStorageLocation
>(FooVal
.getPointeeLoc());
685 *cast
<PointerValue
>(getFieldValue(&FooPointeeLoc
, *BarDecl
, Env
));
686 const auto &BarPointeeLoc
=
687 cast
<RecordStorageLocation
>(BarVal
.getPointeeLoc());
689 EXPECT_THAT(getFieldValue(&BarPointeeLoc
, *FooRefDecl
, Env
), NotNull());
691 const auto &FooPtrVal
= *cast
<PointerValue
>(
692 getFieldValue(&BarPointeeLoc
, *FooPtrDecl
, Env
));
693 const auto &FooPtrPointeeLoc
=
694 cast
<RecordStorageLocation
>(FooPtrVal
.getPointeeLoc());
695 EXPECT_THAT(Env
.getValue(FooPtrPointeeLoc
), IsNull());
697 EXPECT_THAT(getFieldValue(&BarPointeeLoc
, *BazRefDecl
, Env
), NotNull());
699 const auto &BazPtrVal
= *cast
<PointerValue
>(
700 getFieldValue(&BarPointeeLoc
, *BazPtrDecl
, Env
));
701 const StorageLocation
&BazPtrPointeeLoc
= BazPtrVal
.getPointeeLoc();
702 EXPECT_THAT(Env
.getValue(BazPtrPointeeLoc
), NotNull());
706 TEST(TransferTest
, DirectlySelfReferentialReference
) {
707 std::string Code
= R
"(
713 target &self = *this;
718 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
719 ASTContext
&ASTCtx
) {
720 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
721 const ValueDecl
*SelfDecl
= findValueDecl(ASTCtx
, "self");
723 auto *ThisLoc
= Env
.getThisPointeeStorageLocation();
724 ASSERT_EQ(ThisLoc
->getChild(*SelfDecl
), ThisLoc
);
728 TEST(TransferTest
, MultipleVarsDecl
) {
729 std::string Code
= R
"(
738 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
739 ASTContext
&ASTCtx
) {
740 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
741 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
743 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
744 ASSERT_THAT(FooDecl
, NotNull());
746 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
747 ASSERT_THAT(BarDecl
, NotNull());
749 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
750 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
752 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
753 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
755 const Value
*FooVal
= Env
.getValue(*FooLoc
);
756 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
758 const Value
*BarVal
= Env
.getValue(*BarLoc
);
759 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
763 TEST(TransferTest
, JoinVarDecl
) {
764 std::string Code
= R
"(
765 void target(bool B) {
779 runDataflow(Code
, [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>>
781 ASTContext
&ASTCtx
) {
782 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p1", "p2", "p3", "p4"));
784 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
785 ASSERT_THAT(FooDecl
, NotNull());
787 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
788 ASSERT_THAT(BarDecl
, NotNull());
790 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
791 ASSERT_THAT(BazDecl
, NotNull());
793 const Environment
&Env1
= getEnvironmentAtAnnotation(Results
, "p1");
795 const StorageLocation
*FooLoc
= Env1
.getStorageLocation(*FooDecl
);
796 EXPECT_THAT(FooLoc
, NotNull());
797 EXPECT_THAT(Env1
.getStorageLocation(*BarDecl
), IsNull());
798 EXPECT_THAT(Env1
.getStorageLocation(*BazDecl
), IsNull());
800 const Environment
&Env2
= getEnvironmentAtAnnotation(Results
, "p2");
801 EXPECT_EQ(Env2
.getStorageLocation(*FooDecl
), FooLoc
);
802 EXPECT_THAT(Env2
.getStorageLocation(*BarDecl
), NotNull());
803 EXPECT_THAT(Env2
.getStorageLocation(*BazDecl
), IsNull());
805 const Environment
&Env3
= getEnvironmentAtAnnotation(Results
, "p3");
806 EXPECT_EQ(Env3
.getStorageLocation(*FooDecl
), FooLoc
);
807 EXPECT_THAT(Env3
.getStorageLocation(*BarDecl
), IsNull());
808 EXPECT_THAT(Env3
.getStorageLocation(*BazDecl
), NotNull());
810 const Environment
&Env4
= getEnvironmentAtAnnotation(Results
, "p4");
811 EXPECT_EQ(Env4
.getStorageLocation(*FooDecl
), FooLoc
);
812 EXPECT_THAT(Env4
.getStorageLocation(*BarDecl
), IsNull());
813 EXPECT_THAT(Env4
.getStorageLocation(*BazDecl
), IsNull());
817 TEST(TransferTest
, BinaryOperatorAssign
) {
818 std::string Code
= R
"(
828 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
829 ASTContext
&ASTCtx
) {
830 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
831 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
833 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
834 ASSERT_THAT(FooDecl
, NotNull());
836 const Value
*FooVal
= Env
.getValue(*FooDecl
);
837 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
839 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
840 ASSERT_THAT(BarDecl
, NotNull());
842 EXPECT_EQ(Env
.getValue(*BarDecl
), FooVal
);
846 TEST(TransferTest
, BinaryOperatorAssignIntegerLiteral
) {
847 std::string Code
= R
"(
857 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
858 ASTContext
&ASTCtx
) {
859 const Environment
&Before
=
860 getEnvironmentAtAnnotation(Results
, "before");
861 const Environment
&After
= getEnvironmentAtAnnotation(Results
, "after");
863 const auto &ValBefore
=
864 getValueForDecl
<IntegerValue
>(ASTCtx
, Before
, "Foo");
865 const auto &ValAfter
=
866 getValueForDecl
<IntegerValue
>(ASTCtx
, After
, "Foo");
867 EXPECT_NE(&ValBefore
, &ValAfter
);
871 TEST(TransferTest
, VarDeclInitAssign
) {
872 std::string Code
= R
"(
881 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
882 ASTContext
&ASTCtx
) {
883 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
884 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
886 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
887 ASSERT_THAT(FooDecl
, NotNull());
889 const Value
*FooVal
= Env
.getValue(*FooDecl
);
890 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
892 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
893 ASSERT_THAT(BarDecl
, NotNull());
895 EXPECT_EQ(Env
.getValue(*BarDecl
), FooVal
);
899 TEST(TransferTest
, VarDeclInitAssignChained
) {
900 std::string Code
= R
"(
904 int Baz = (Bar = Foo);
910 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
911 ASTContext
&ASTCtx
) {
912 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
913 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
915 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
916 ASSERT_THAT(FooDecl
, NotNull());
918 const Value
*FooVal
= Env
.getValue(*FooDecl
);
919 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
921 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
922 ASSERT_THAT(BarDecl
, NotNull());
924 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
925 ASSERT_THAT(BazDecl
, NotNull());
927 EXPECT_EQ(Env
.getValue(*BarDecl
), FooVal
);
928 EXPECT_EQ(Env
.getValue(*BazDecl
), FooVal
);
932 TEST(TransferTest
, VarDeclInitAssignPtrDeref
) {
933 std::string Code
= R
"(
944 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
945 ASTContext
&ASTCtx
) {
946 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
947 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
949 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
950 ASSERT_THAT(FooDecl
, NotNull());
952 const Value
*FooVal
= Env
.getValue(*FooDecl
);
953 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
955 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
956 ASSERT_THAT(BarDecl
, NotNull());
958 const auto *BarVal
= cast
<PointerValue
>(Env
.getValue(*BarDecl
));
959 EXPECT_EQ(Env
.getValue(BarVal
->getPointeeLoc()), FooVal
);
961 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
962 ASSERT_THAT(BazDecl
, NotNull());
964 EXPECT_EQ(Env
.getValue(*BazDecl
), FooVal
);
968 TEST(TransferTest
, AssignToAndFromReference
) {
969 std::string Code
= R
"(
983 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
984 ASTContext
&ASTCtx
) {
985 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p1", "p2"));
986 const Environment
&Env1
= getEnvironmentAtAnnotation(Results
, "p1");
987 const Environment
&Env2
= getEnvironmentAtAnnotation(Results
, "p2");
989 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
990 ASSERT_THAT(FooDecl
, NotNull());
992 const Value
*FooVal
= Env1
.getValue(*FooDecl
);
993 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
995 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
996 ASSERT_THAT(BarDecl
, NotNull());
998 const Value
*BarVal
= Env1
.getValue(*BarDecl
);
999 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
1001 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
1002 ASSERT_THAT(BazDecl
, NotNull());
1004 EXPECT_EQ(Env1
.getValue(*BazDecl
), FooVal
);
1006 EXPECT_EQ(Env2
.getValue(*BazDecl
), BarVal
);
1007 EXPECT_EQ(Env2
.getValue(*FooDecl
), BarVal
);
1009 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
1010 ASSERT_THAT(QuxDecl
, NotNull());
1011 EXPECT_EQ(Env2
.getValue(*QuxDecl
), BarVal
);
1013 const ValueDecl
*QuuxDecl
= findValueDecl(ASTCtx
, "Quux");
1014 ASSERT_THAT(QuuxDecl
, NotNull());
1015 EXPECT_EQ(Env2
.getValue(*QuuxDecl
), BarVal
);
1019 TEST(TransferTest
, MultipleParamDecls
) {
1020 std::string Code
= R
"(
1021 void target(int Foo, int Bar) {
1028 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1029 ASTContext
&ASTCtx
) {
1030 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1031 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1033 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1034 ASSERT_THAT(FooDecl
, NotNull());
1036 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
1037 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
1039 const Value
*FooVal
= Env
.getValue(*FooLoc
);
1040 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
1042 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
1043 ASSERT_THAT(BarDecl
, NotNull());
1045 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
1046 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
1048 const Value
*BarVal
= Env
.getValue(*BarLoc
);
1049 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
1053 TEST(TransferTest
, StructParamDecl
) {
1054 std::string Code
= R
"(
1059 void target(A Foo) {
1066 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1067 ASTContext
&ASTCtx
) {
1068 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1069 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1071 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1072 ASSERT_THAT(FooDecl
, NotNull());
1074 ASSERT_TRUE(FooDecl
->getType()->isStructureType());
1075 auto FooFields
= FooDecl
->getType()->getAsRecordDecl()->fields();
1077 FieldDecl
*BarDecl
= nullptr;
1078 for (FieldDecl
*Field
: FooFields
) {
1079 if (Field
->getNameAsString() == "Bar") {
1082 FAIL() << "Unexpected field: " << Field
->getNameAsString();
1085 ASSERT_THAT(BarDecl
, NotNull());
1087 const auto *FooLoc
=
1088 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
1089 EXPECT_TRUE(isa
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
)));
1093 TEST(TransferTest
, ReferenceParamDecl
) {
1094 std::string Code
= R
"(
1097 void target(A &Foo) {
1104 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1105 ASTContext
&ASTCtx
) {
1106 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1107 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1109 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1110 ASSERT_THAT(FooDecl
, NotNull());
1112 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
1113 ASSERT_TRUE(isa_and_nonnull
<RecordStorageLocation
>(FooLoc
));
1115 const Value
*FooReferentVal
= Env
.getValue(*FooLoc
);
1116 EXPECT_TRUE(isa_and_nonnull
<RecordValue
>(FooReferentVal
));
1120 TEST(TransferTest
, PointerParamDecl
) {
1121 std::string Code
= R
"(
1124 void target(A *Foo) {
1131 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1132 ASTContext
&ASTCtx
) {
1133 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1134 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1136 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1137 ASSERT_THAT(FooDecl
, NotNull());
1139 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
1140 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
1142 const PointerValue
*FooVal
= cast
<PointerValue
>(Env
.getValue(*FooLoc
));
1143 const StorageLocation
&FooPointeeLoc
= FooVal
->getPointeeLoc();
1144 EXPECT_TRUE(isa
<RecordStorageLocation
>(&FooPointeeLoc
));
1146 const Value
*FooPointeeVal
= Env
.getValue(FooPointeeLoc
);
1147 EXPECT_TRUE(isa_and_nonnull
<RecordValue
>(FooPointeeVal
));
1151 TEST(TransferTest
, StructMember
) {
1152 std::string Code
= R
"(
1157 void target(A Foo) {
1164 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1165 ASTContext
&ASTCtx
) {
1166 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1167 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1169 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1170 ASSERT_THAT(FooDecl
, NotNull());
1172 ASSERT_TRUE(FooDecl
->getType()->isStructureType());
1173 auto FooFields
= FooDecl
->getType()->getAsRecordDecl()->fields();
1175 FieldDecl
*BarDecl
= nullptr;
1176 for (FieldDecl
*Field
: FooFields
) {
1177 if (Field
->getNameAsString() == "Bar") {
1180 FAIL() << "Unexpected field: " << Field
->getNameAsString();
1183 ASSERT_THAT(BarDecl
, NotNull());
1185 const auto *FooLoc
=
1186 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
1187 const auto *BarVal
=
1188 cast
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
));
1190 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
1191 ASSERT_THAT(BazDecl
, NotNull());
1193 EXPECT_EQ(Env
.getValue(*BazDecl
), BarVal
);
1197 TEST(TransferTest
, StructMemberEnum
) {
1198 std::string Code
= R
"(
1201 enum E { ONE, TWO };
1204 void target(A Foo) {
1209 // Minimal expectations -- we're just testing that it doesn't crash, since
1210 // enums aren't interpreted.
1213 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1214 ASTContext
&ASTCtx
) {
1215 EXPECT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1219 TEST(TransferTest
, DerivedBaseMemberClass
) {
1220 std::string Code
= R
"(
1231 friend void target();
1234 class B : public A {
1242 friend void target();
1248 (void)Foo.AProtected;
1252 (void)Foo.BProtected;
1259 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1260 ASTContext
&ASTCtx
) {
1261 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1262 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1264 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1265 ASSERT_THAT(FooDecl
, NotNull());
1266 ASSERT_TRUE(FooDecl
->getType()->isRecordType());
1268 // Derived-class fields.
1269 const FieldDecl
*BDefaultDecl
= nullptr;
1270 const FieldDecl
*BProtectedDecl
= nullptr;
1271 const FieldDecl
*BPrivateDecl
= nullptr;
1272 for (const FieldDecl
*Field
:
1273 FooDecl
->getType()->getAsRecordDecl()->fields()) {
1274 if (Field
->getNameAsString() == "BDefault") {
1275 BDefaultDecl
= Field
;
1276 } else if (Field
->getNameAsString() == "BProtected") {
1277 BProtectedDecl
= Field
;
1278 } else if (Field
->getNameAsString() == "BPrivate") {
1279 BPrivateDecl
= Field
;
1281 FAIL() << "Unexpected field: " << Field
->getNameAsString();
1284 ASSERT_THAT(BDefaultDecl
, NotNull());
1285 ASSERT_THAT(BProtectedDecl
, NotNull());
1286 ASSERT_THAT(BPrivateDecl
, NotNull());
1288 // Base-class fields.
1289 const FieldDecl
*ADefaultDecl
= nullptr;
1290 const FieldDecl
*APrivateDecl
= nullptr;
1291 const FieldDecl
*AProtectedDecl
= nullptr;
1292 const FieldDecl
*APublicDecl
= nullptr;
1293 for (const clang::CXXBaseSpecifier
&Base
:
1294 FooDecl
->getType()->getAsCXXRecordDecl()->bases()) {
1295 QualType BaseType
= Base
.getType();
1296 ASSERT_TRUE(BaseType
->isRecordType());
1297 for (const FieldDecl
*Field
: BaseType
->getAsRecordDecl()->fields()) {
1298 if (Field
->getNameAsString() == "ADefault") {
1299 ADefaultDecl
= Field
;
1300 } else if (Field
->getNameAsString() == "AProtected") {
1301 AProtectedDecl
= Field
;
1302 } else if (Field
->getNameAsString() == "APrivate") {
1303 APrivateDecl
= Field
;
1304 } else if (Field
->getNameAsString() == "APublic") {
1305 APublicDecl
= Field
;
1307 FAIL() << "Unexpected field: " << Field
->getNameAsString();
1311 ASSERT_THAT(ADefaultDecl
, NotNull());
1312 ASSERT_THAT(AProtectedDecl
, NotNull());
1313 ASSERT_THAT(APrivateDecl
, NotNull());
1314 ASSERT_THAT(APublicDecl
, NotNull());
1317 isa
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
)));
1321 static void derivedBaseMemberExpectations(
1322 const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1323 ASTContext
&ASTCtx
) {
1324 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1325 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1327 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1328 ASSERT_THAT(FooDecl
, NotNull());
1330 ASSERT_TRUE(FooDecl
->getType()->isRecordType());
1331 const FieldDecl
*BarDecl
= nullptr;
1332 for (const clang::CXXBaseSpecifier
&Base
:
1333 FooDecl
->getType()->getAsCXXRecordDecl()->bases()) {
1334 QualType BaseType
= Base
.getType();
1335 ASSERT_TRUE(BaseType
->isStructureType());
1337 for (const FieldDecl
*Field
: BaseType
->getAsRecordDecl()->fields()) {
1338 if (Field
->getNameAsString() == "Bar") {
1341 FAIL() << "Unexpected field: " << Field
->getNameAsString();
1345 ASSERT_THAT(BarDecl
, NotNull());
1347 const auto &FooLoc
=
1348 *cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
1349 const auto &FooVal
= *cast
<RecordValue
>(Env
.getValue(FooLoc
));
1350 EXPECT_EQ(&FooVal
.getLoc(), &FooLoc
);
1353 TEST(TransferTest
, DerivedBaseMemberStructDefault
) {
1354 std::string Code
= R
"(
1358 struct B : public A {
1367 runDataflow(Code
, derivedBaseMemberExpectations
);
1370 TEST(TransferTest
, DerivedBaseMemberPrivateFriend
) {
1371 // Include an access to `Foo.Bar` to verify the analysis doesn't crash on that
1373 std::string Code
= R
"(
1376 friend void target();
1379 struct B : public A {
1388 runDataflow(Code
, derivedBaseMemberExpectations
);
1391 TEST(TransferTest
, ClassMember
) {
1392 std::string Code
= R
"(
1398 void target(A Foo) {
1405 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1406 ASTContext
&ASTCtx
) {
1407 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1408 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1410 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1411 ASSERT_THAT(FooDecl
, NotNull());
1413 ASSERT_TRUE(FooDecl
->getType()->isClassType());
1414 auto FooFields
= FooDecl
->getType()->getAsRecordDecl()->fields();
1416 FieldDecl
*BarDecl
= nullptr;
1417 for (FieldDecl
*Field
: FooFields
) {
1418 if (Field
->getNameAsString() == "Bar") {
1421 FAIL() << "Unexpected field: " << Field
->getNameAsString();
1424 ASSERT_THAT(BarDecl
, NotNull());
1426 const auto *FooLoc
=
1427 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
1428 const auto *BarVal
=
1429 cast
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
));
1431 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
1432 ASSERT_THAT(BazDecl
, NotNull());
1434 EXPECT_EQ(Env
.getValue(*BazDecl
), BarVal
);
1438 TEST(TransferTest
, BaseClassInitializer
) {
1439 using ast_matchers::cxxConstructorDecl
;
1440 using ast_matchers::hasName
;
1441 using ast_matchers::ofClass
;
1443 std::string Code
= R
"(
1446 A(int I) : Bar(I) {}
1450 class B : public A {
1459 checkDataflow
<NoopAnalysis
>(
1460 AnalysisInputs
<NoopAnalysis
>(
1461 Code
, cxxConstructorDecl(ofClass(hasName("B"))),
1462 [](ASTContext
&C
, Environment
&) { return NoopAnalysis(C
); })
1464 {"-fsyntax-only", "-fno-delayed-template-parsing",
1465 "-std=" + std::string(LangStandard::getLangStandardForKind(
1466 LangStandard::lang_cxx17
)
1469 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1470 const AnalysisOutputs
&) {
1471 // Regression test to verify that base-class initializers do not
1472 // trigger an assertion. If we add support for such initializers in
1473 // the future, we can expand this test to check more specific
1475 EXPECT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1480 TEST(TransferTest
, StructModeledFieldsWithAccessor
) {
1481 std::string Code
= R
"(
1490 int *getPtr() const { return Ptr; }
1491 int *getPtrNonConst() { return PtrNonConst; }
1492 int getInt(int i) const { return Int; }
1493 int getWithInc(int i) { IntWithInc += i; return IntWithInc; }
1494 int getIntNotAccessed() const { return IntNotAccessed; }
1495 int getIntNoDefinition() const;
1496 int &getIntRef() { return IntRef; }
1497 void returnVoid() const { return; }
1502 int *p1 = s.getPtr();
1503 int *p2 = s.getPtrNonConst();
1504 int i1 = s.getInt(1);
1505 int i2 = s.getWithInc(1);
1506 int i3 = s.getIntNoDefinition();
1507 int &iref = s.getIntRef();
1509 // Regression test: Don't crash on an indirect call (which doesn't have
1510 // an associated `CXXMethodDecl`).
1511 auto ptr_to_member_fn = &S::getPtr;
1512 p1 = (s.*ptr_to_member_fn)();
1514 // Regression test: Don't crash on a return statement without a value.
1521 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1522 ASTContext
&ASTCtx
) {
1523 const Environment
&Env
=
1524 getEnvironmentAtAnnotation(Results
, "p");
1525 auto &SLoc
= getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "s");
1526 std::vector
<const ValueDecl
*> Fields
;
1527 for (auto [Field
, _
] : SLoc
.children())
1528 Fields
.push_back(Field
);
1529 // Only the fields that have simple accessor methods (that have a
1530 // single statement body that returns the member variable) should be
1532 ASSERT_THAT(Fields
, UnorderedElementsAre(
1533 findValueDecl(ASTCtx
, "Ptr"), findValueDecl(ASTCtx
, "PtrNonConst"),
1534 findValueDecl(ASTCtx
, "Int"), findValueDecl(ASTCtx
, "IntRef")));
1538 TEST(TransferTest
, StructModeledFieldsWithComplicatedInheritance
) {
1539 std::string Code
= R
"(
1544 struct Intermediate : Base1 {
1552 struct MostDerived : public Intermediate, Base2 {
1560 MD.intermediate_2 = 1;
1562 MD.most_derived_2 = 1;
1568 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1569 ASTContext
&ASTCtx
) {
1570 const Environment
&Env
=
1571 getEnvironmentAtAnnotation(Results
, "p");
1573 // Only the accessed fields should exist in the model.
1574 auto &MDLoc
= getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "MD");
1575 std::vector
<const ValueDecl
*> Fields
;
1576 for (auto [Field
, _
] : MDLoc
.children())
1577 Fields
.push_back(Field
);
1578 ASSERT_THAT(Fields
, UnorderedElementsAre(
1579 findValueDecl(ASTCtx
, "base1_2"),
1580 findValueDecl(ASTCtx
, "intermediate_2"),
1581 findValueDecl(ASTCtx
, "base2_2"),
1582 findValueDecl(ASTCtx
, "most_derived_2")));
1586 TEST(TransferTest
, StructInitializerListWithComplicatedInheritance
) {
1587 std::string Code
= R
"(
1591 struct Intermediate : Base1 {
1597 struct MostDerived : public Intermediate, Base2 {
1602 MostDerived MD = {};
1608 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1609 ASTContext
&ASTCtx
) {
1610 const Environment
&Env
=
1611 getEnvironmentAtAnnotation(Results
, "p");
1613 // When a struct is initialized with a initializer list, all the
1614 // fields are considered "accessed", and therefore do exist.
1615 auto &MD
= getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "MD");
1616 ASSERT_THAT(cast
<IntegerValue
>(
1617 getFieldValue(&MD
, *findValueDecl(ASTCtx
, "base1"), Env
)),
1619 ASSERT_THAT(cast
<IntegerValue
>(
1620 getFieldValue(&MD
, *findValueDecl(ASTCtx
, "intermediate"), Env
)),
1622 ASSERT_THAT(cast
<IntegerValue
>(
1623 getFieldValue(&MD
, *findValueDecl(ASTCtx
, "base2"), Env
)),
1625 ASSERT_THAT(cast
<IntegerValue
>(
1626 getFieldValue(&MD
, *findValueDecl(ASTCtx
, "most_derived"), Env
)),
1631 TEST(TransferTest
, ReferenceMember
) {
1632 std::string Code
= R
"(
1637 void target(A Foo) {
1644 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1645 ASTContext
&ASTCtx
) {
1646 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1647 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1649 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1650 ASSERT_THAT(FooDecl
, NotNull());
1652 ASSERT_TRUE(FooDecl
->getType()->isStructureType());
1653 auto FooFields
= FooDecl
->getType()->getAsRecordDecl()->fields();
1655 FieldDecl
*BarDecl
= nullptr;
1656 for (FieldDecl
*Field
: FooFields
) {
1657 if (Field
->getNameAsString() == "Bar") {
1660 FAIL() << "Unexpected field: " << Field
->getNameAsString();
1663 ASSERT_THAT(BarDecl
, NotNull());
1665 const auto *FooLoc
=
1666 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
1667 const auto *BarReferentVal
=
1668 cast
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
));
1670 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
1671 ASSERT_THAT(BazDecl
, NotNull());
1673 EXPECT_EQ(Env
.getValue(*BazDecl
), BarReferentVal
);
1677 TEST(TransferTest
, StructThisMember
) {
1678 std::string Code
= R
"(
1697 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1698 ASTContext
&ASTCtx
) {
1699 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1700 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1702 const auto *ThisLoc
= Env
.getThisPointeeStorageLocation();
1703 ASSERT_THAT(ThisLoc
, NotNull());
1705 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
1706 ASSERT_THAT(BarDecl
, NotNull());
1708 const auto *BarLoc
=
1709 cast
<ScalarStorageLocation
>(ThisLoc
->getChild(*BarDecl
));
1710 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
1712 const Value
*BarVal
= Env
.getValue(*BarLoc
);
1713 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
1715 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1716 ASSERT_THAT(FooDecl
, NotNull());
1717 EXPECT_EQ(Env
.getValue(*FooDecl
), BarVal
);
1719 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
1720 ASSERT_THAT(QuxDecl
, NotNull());
1722 ASSERT_TRUE(QuxDecl
->getType()->isStructureType());
1723 auto QuxFields
= QuxDecl
->getType()->getAsRecordDecl()->fields();
1725 FieldDecl
*BazDecl
= nullptr;
1726 for (FieldDecl
*Field
: QuxFields
) {
1727 if (Field
->getNameAsString() == "Baz") {
1730 FAIL() << "Unexpected field: " << Field
->getNameAsString();
1733 ASSERT_THAT(BazDecl
, NotNull());
1735 const auto *QuxLoc
=
1736 cast
<RecordStorageLocation
>(ThisLoc
->getChild(*QuxDecl
));
1737 EXPECT_THAT(dyn_cast
<RecordValue
>(Env
.getValue(*QuxLoc
)), NotNull());
1739 const auto *BazVal
=
1740 cast
<IntegerValue
>(getFieldValue(QuxLoc
, *BazDecl
, Env
));
1742 const ValueDecl
*QuuxDecl
= findValueDecl(ASTCtx
, "Quux");
1743 ASSERT_THAT(QuuxDecl
, NotNull());
1744 EXPECT_EQ(Env
.getValue(*QuuxDecl
), BazVal
);
1748 TEST(TransferTest
, ClassThisMember
) {
1749 std::string Code
= R
"(
1769 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1770 ASTContext
&ASTCtx
) {
1771 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1772 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1774 const auto *ThisLoc
= Env
.getThisPointeeStorageLocation();
1776 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
1777 ASSERT_THAT(BarDecl
, NotNull());
1779 const auto *BarLoc
=
1780 cast
<ScalarStorageLocation
>(ThisLoc
->getChild(*BarDecl
));
1781 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
1783 const Value
*BarVal
= Env
.getValue(*BarLoc
);
1784 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
1786 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1787 ASSERT_THAT(FooDecl
, NotNull());
1788 EXPECT_EQ(Env
.getValue(*FooDecl
), BarVal
);
1790 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
1791 ASSERT_THAT(QuxDecl
, NotNull());
1793 ASSERT_TRUE(QuxDecl
->getType()->isClassType());
1794 auto QuxFields
= QuxDecl
->getType()->getAsRecordDecl()->fields();
1796 FieldDecl
*BazDecl
= nullptr;
1797 for (FieldDecl
*Field
: QuxFields
) {
1798 if (Field
->getNameAsString() == "Baz") {
1801 FAIL() << "Unexpected field: " << Field
->getNameAsString();
1804 ASSERT_THAT(BazDecl
, NotNull());
1806 const auto *QuxLoc
=
1807 cast
<RecordStorageLocation
>(ThisLoc
->getChild(*QuxDecl
));
1808 EXPECT_THAT(dyn_cast
<RecordValue
>(Env
.getValue(*QuxLoc
)), NotNull());
1810 const auto *BazVal
=
1811 cast
<IntegerValue
>(getFieldValue(QuxLoc
, *BazDecl
, Env
));
1813 const ValueDecl
*QuuxDecl
= findValueDecl(ASTCtx
, "Quux");
1814 ASSERT_THAT(QuuxDecl
, NotNull());
1815 EXPECT_EQ(Env
.getValue(*QuuxDecl
), BazVal
);
1819 TEST(TransferTest
, UnionThisMember
) {
1820 std::string Code
= R
"(
1827 // Mention the fields to ensure they're included in the analysis.
1836 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1837 ASTContext
&ASTCtx
) {
1838 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1839 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1841 const auto *ThisLoc
= Env
.getThisPointeeStorageLocation();
1842 ASSERT_THAT(ThisLoc
, NotNull());
1844 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1845 ASSERT_THAT(FooDecl
, NotNull());
1847 const auto *FooLoc
=
1848 cast
<ScalarStorageLocation
>(ThisLoc
->getChild(*FooDecl
));
1849 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
1851 const Value
*FooVal
= Env
.getValue(*FooLoc
);
1852 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
1854 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
1855 ASSERT_THAT(BarDecl
, NotNull());
1857 const auto *BarLoc
=
1858 cast
<ScalarStorageLocation
>(ThisLoc
->getChild(*BarDecl
));
1859 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
1861 const Value
*BarVal
= Env
.getValue(*BarLoc
);
1862 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
1866 TEST(TransferTest
, StructThisInLambda
) {
1867 std::string ThisCaptureCode
= R
"(
1881 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1882 ASTContext
&ASTCtx
) {
1883 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p1"));
1884 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p1");
1886 const auto *ThisLoc
= Env
.getThisPointeeStorageLocation();
1887 ASSERT_THAT(ThisLoc
, NotNull());
1889 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
1890 ASSERT_THAT(BarDecl
, NotNull());
1892 const auto *BarLoc
=
1893 cast
<ScalarStorageLocation
>(ThisLoc
->getChild(*BarDecl
));
1894 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
1896 const Value
*BarVal
= Env
.getValue(*BarLoc
);
1897 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
1899 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1900 ASSERT_THAT(FooDecl
, NotNull());
1901 EXPECT_EQ(Env
.getValue(*FooDecl
), BarVal
);
1903 LangStandard::lang_cxx17
, /*ApplyBuiltinTransfer=*/true, "operator()");
1905 std::string RefCaptureDefaultCode
= R
"(
1918 RefCaptureDefaultCode
,
1919 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1920 ASTContext
&ASTCtx
) {
1921 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p2"));
1922 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p2");
1924 const auto *ThisLoc
= Env
.getThisPointeeStorageLocation();
1925 ASSERT_THAT(ThisLoc
, NotNull());
1927 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
1928 ASSERT_THAT(BarDecl
, NotNull());
1930 const auto *BarLoc
=
1931 cast
<ScalarStorageLocation
>(ThisLoc
->getChild(*BarDecl
));
1932 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
1934 const Value
*BarVal
= Env
.getValue(*BarLoc
);
1935 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
1937 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1938 ASSERT_THAT(FooDecl
, NotNull());
1939 EXPECT_EQ(Env
.getValue(*FooDecl
), BarVal
);
1941 LangStandard::lang_cxx17
, /*ApplyBuiltinTransfer=*/true, "operator()");
1943 std::string FreeFunctionLambdaCode
= R
"(
1953 FreeFunctionLambdaCode
,
1954 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1955 ASTContext
&ASTCtx
) {
1956 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p3"));
1957 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p3");
1959 EXPECT_THAT(Env
.getThisPointeeStorageLocation(), IsNull());
1961 LangStandard::lang_cxx17
, /*ApplyBuiltinTransfer=*/true, "operator()");
1964 TEST(TransferTest
, ConstructorInitializer
) {
1965 std::string Code
= R
"(
1969 target(int Foo) : Bar(Foo) {
1977 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1978 ASTContext
&ASTCtx
) {
1979 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1980 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1982 const auto *ThisLoc
= Env
.getThisPointeeStorageLocation();
1983 ASSERT_THAT(ThisLoc
, NotNull());
1985 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1986 ASSERT_THAT(FooDecl
, NotNull());
1988 const auto *FooVal
= cast
<IntegerValue
>(Env
.getValue(*FooDecl
));
1990 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
1991 ASSERT_THAT(QuxDecl
, NotNull());
1992 EXPECT_EQ(Env
.getValue(*QuxDecl
), FooVal
);
1996 TEST(TransferTest
, DefaultInitializer
) {
1997 std::string Code
= R
"(
2002 target(int Foo) : Bar(Foo) {
2010 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2011 ASTContext
&ASTCtx
) {
2012 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2013 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2015 const auto *ThisLoc
= Env
.getThisPointeeStorageLocation();
2016 ASSERT_THAT(ThisLoc
, NotNull());
2018 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2019 ASSERT_THAT(FooDecl
, NotNull());
2021 const auto *FooVal
= cast
<IntegerValue
>(Env
.getValue(*FooDecl
));
2023 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
2024 ASSERT_THAT(QuxDecl
, NotNull());
2025 EXPECT_EQ(Env
.getValue(*QuxDecl
), FooVal
);
2029 TEST(TransferTest
, DefaultInitializerReference
) {
2030 std::string Code
= R
"(
2035 target(int &Foo) : Bar(Foo) {
2043 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2044 ASTContext
&ASTCtx
) {
2045 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2046 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2048 const auto *ThisLoc
= Env
.getThisPointeeStorageLocation();
2049 ASSERT_THAT(ThisLoc
, NotNull());
2051 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2052 ASSERT_THAT(FooDecl
, NotNull());
2054 const auto *FooLoc
= Env
.getStorageLocation(*FooDecl
);
2056 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
2057 ASSERT_THAT(QuxDecl
, NotNull());
2059 const auto *QuxLoc
= Env
.getStorageLocation(*QuxDecl
);
2060 EXPECT_EQ(QuxLoc
, FooLoc
);
2064 TEST(TransferTest
, TemporaryObject
) {
2065 std::string Code
= R
"(
2078 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2079 ASTContext
&ASTCtx
) {
2080 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2081 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2083 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2084 ASSERT_THAT(FooDecl
, NotNull());
2086 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2087 ASSERT_THAT(BarDecl
, NotNull());
2089 const auto *FooLoc
=
2090 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2091 EXPECT_TRUE(isa
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
)));
2095 TEST(TransferTest
, ElidableConstructor
) {
2096 // This test is effectively the same as TransferTest.TemporaryObject, but
2097 // the code is compiled as C++ 14.
2098 std::string Code
= R
"(
2111 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2112 ASTContext
&ASTCtx
) {
2113 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2114 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2116 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2117 ASSERT_THAT(FooDecl
, NotNull());
2119 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2120 ASSERT_THAT(BarDecl
, NotNull());
2122 const auto *FooLoc
=
2123 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2124 EXPECT_TRUE(isa
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
)));
2126 LangStandard::lang_cxx14
);
2129 TEST(TransferTest
, AssignmentOperator
) {
2130 std::string Code
= R
"(
2147 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2148 ASTContext
&ASTCtx
) {
2149 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2150 ASSERT_THAT(FooDecl
, NotNull());
2152 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2153 ASSERT_THAT(BarDecl
, NotNull());
2155 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2156 ASSERT_THAT(BazDecl
, NotNull());
2158 // Before copy assignment.
2160 const Environment
&Env1
= getEnvironmentAtAnnotation(Results
, "p1");
2162 const auto *FooLoc1
=
2163 cast
<RecordStorageLocation
>(Env1
.getStorageLocation(*FooDecl
));
2164 const auto *BarLoc1
=
2165 cast
<RecordStorageLocation
>(Env1
.getStorageLocation(*BarDecl
));
2166 EXPECT_FALSE(recordsEqual(*FooLoc1
, *BarLoc1
, Env1
));
2168 const auto *FooBazVal1
=
2169 cast
<IntegerValue
>(getFieldValue(FooLoc1
, *BazDecl
, Env1
));
2170 const auto *BarBazVal1
=
2171 cast
<IntegerValue
>(getFieldValue(BarLoc1
, *BazDecl
, Env1
));
2172 EXPECT_NE(FooBazVal1
, BarBazVal1
);
2175 // After copy assignment.
2177 const Environment
&Env2
= getEnvironmentAtAnnotation(Results
, "p2");
2179 const auto *FooLoc2
=
2180 cast
<RecordStorageLocation
>(Env2
.getStorageLocation(*FooDecl
));
2181 const auto *BarLoc2
=
2182 cast
<RecordStorageLocation
>(Env2
.getStorageLocation(*BarDecl
));
2184 const auto *FooVal2
= cast
<RecordValue
>(Env2
.getValue(*FooLoc2
));
2185 const auto *BarVal2
= cast
<RecordValue
>(Env2
.getValue(*BarLoc2
));
2186 EXPECT_NE(FooVal2
, BarVal2
);
2188 EXPECT_TRUE(recordsEqual(*FooLoc2
, *BarLoc2
, Env2
));
2190 const auto *FooBazVal2
=
2191 cast
<IntegerValue
>(getFieldValue(FooLoc2
, *BazDecl
, Env2
));
2192 const auto *BarBazVal2
=
2193 cast
<IntegerValue
>(getFieldValue(BarLoc2
, *BazDecl
, Env2
));
2194 EXPECT_EQ(FooBazVal2
, BarBazVal2
);
2197 // After value update.
2199 const Environment
&Env3
= getEnvironmentAtAnnotation(Results
, "p3");
2201 const auto *FooLoc3
=
2202 cast
<RecordStorageLocation
>(Env3
.getStorageLocation(*FooDecl
));
2203 const auto *BarLoc3
=
2204 cast
<RecordStorageLocation
>(Env3
.getStorageLocation(*BarDecl
));
2205 EXPECT_FALSE(recordsEqual(*FooLoc3
, *BarLoc3
, Env3
));
2207 const auto *FooBazVal3
=
2208 cast
<IntegerValue
>(getFieldValue(FooLoc3
, *BazDecl
, Env3
));
2209 const auto *BarBazVal3
=
2210 cast
<IntegerValue
>(getFieldValue(BarLoc3
, *BazDecl
, Env3
));
2211 EXPECT_NE(FooBazVal3
, BarBazVal3
);
2216 TEST(TransferTest
, AssignmentOperatorFromBase
) {
2217 // This is a crash repro. We don't model the copy this case, so no
2218 // expectations on the copied field of the base class are checked.
2219 std::string Code
= R
"(
2223 struct Derived : public Base {
2224 using Base::operator=;
2227 void target(Base B, Derived D) {
2236 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2237 ASTContext
&ASTCtx
) {});
2240 TEST(TransferTest
, AssignmentOperatorFromCallResult
) {
2241 std::string Code
= R
"(
2252 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2253 ASTContext
&ASTCtx
) {
2254 // As of this writing, we don't produce a `Value` for the call
2255 // `ReturnA()`. The only condition we're testing for is that the
2256 // analysis should not crash in this case.
2260 TEST(TransferTest
, AssignmentOperatorWithInitAndInheritance
) {
2261 // This is a crash repro.
2262 std::string Code
= R
"(
2263 struct B { int Foo; };
2264 struct S : public B {};
2269 S1 = S2; // Only Dst has InitListExpr.
2270 S3 = S1; // Only Src has InitListExpr.
2276 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2277 ASTContext
&ASTCtx
) {});
2280 TEST(TransferTest
, CopyConstructor
) {
2281 std::string Code
= R
"(
2296 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2297 ASTContext
&ASTCtx
) {
2298 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2299 ASSERT_THAT(FooDecl
, NotNull());
2301 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2302 ASSERT_THAT(BarDecl
, NotNull());
2304 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2305 ASSERT_THAT(BazDecl
, NotNull());
2309 const Environment
&Env
=
2310 getEnvironmentAtAnnotation(Results
, "after_copy");
2312 const auto *FooLoc
=
2313 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2314 const auto *BarLoc
=
2315 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*BarDecl
));
2317 // `Foo` and `Bar` have different `RecordValue`s associated with them.
2318 const auto *FooVal
= cast
<RecordValue
>(Env
.getValue(*FooLoc
));
2319 const auto *BarVal
= cast
<RecordValue
>(Env
.getValue(*BarLoc
));
2320 EXPECT_NE(FooVal
, BarVal
);
2322 // But the records compare equal.
2323 EXPECT_TRUE(recordsEqual(*FooLoc
, *BarLoc
, Env
));
2325 // In particular, the value of `Baz` in both records is the same.
2326 const auto *FooBazVal
=
2327 cast
<IntegerValue
>(getFieldValue(FooLoc
, *BazDecl
, Env
));
2328 const auto *BarBazVal
=
2329 cast
<IntegerValue
>(getFieldValue(BarLoc
, *BazDecl
, Env
));
2330 EXPECT_EQ(FooBazVal
, BarBazVal
);
2335 const Environment
&Env
=
2336 getEnvironmentAtAnnotation(Results
, "after_update");
2338 const auto *FooLoc
=
2339 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2340 const auto *BarLoc
=
2341 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*BarDecl
));
2343 EXPECT_FALSE(recordsEqual(*FooLoc
, *BarLoc
, Env
));
2345 const auto *FooBazVal
=
2346 cast
<IntegerValue
>(getFieldValue(FooLoc
, *BazDecl
, Env
));
2347 const auto *BarBazVal
=
2348 cast
<IntegerValue
>(getFieldValue(BarLoc
, *BazDecl
, Env
));
2349 EXPECT_NE(FooBazVal
, BarBazVal
);
2354 TEST(TransferTest
, CopyConstructorWithDefaultArgument
) {
2355 std::string Code
= R
"(
2359 A(const A& a, bool def = true) { Baz = a.Baz; }
2371 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2372 ASTContext
&ASTCtx
) {
2373 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2374 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2376 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2377 ASSERT_THAT(FooDecl
, NotNull());
2379 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2380 ASSERT_THAT(BarDecl
, NotNull());
2382 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2383 ASSERT_THAT(BazDecl
, NotNull());
2385 const auto *FooLoc
=
2386 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2387 const auto *BarLoc
=
2388 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*BarDecl
));
2389 EXPECT_TRUE(recordsEqual(*FooLoc
, *BarLoc
, Env
));
2391 const auto *FooBazVal
=
2392 cast
<IntegerValue
>(getFieldValue(FooLoc
, *BazDecl
, Env
));
2393 const auto *BarBazVal
=
2394 cast
<IntegerValue
>(getFieldValue(BarLoc
, *BazDecl
, Env
));
2395 EXPECT_EQ(FooBazVal
, BarBazVal
);
2399 TEST(TransferTest
, CopyConstructorWithParens
) {
2400 std::string Code
= R
"(
2414 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2415 ASTContext
&ASTCtx
) {
2416 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2417 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2419 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2420 ASSERT_THAT(FooDecl
, NotNull());
2422 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2423 ASSERT_THAT(BarDecl
, NotNull());
2425 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2426 ASSERT_THAT(BazDecl
, NotNull());
2428 const auto *FooLoc
=
2429 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2430 const auto *BarLoc
=
2431 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*BarDecl
));
2432 EXPECT_TRUE(recordsEqual(*FooLoc
, *BarLoc
, Env
));
2434 const auto *FooBazVal
=
2435 cast
<IntegerValue
>(getFieldValue(FooLoc
, *BazDecl
, Env
));
2436 const auto *BarBazVal
=
2437 cast
<IntegerValue
>(getFieldValue(BarLoc
, *BazDecl
, Env
));
2438 EXPECT_EQ(FooBazVal
, BarBazVal
);
2442 TEST(TransferTest
, CopyConstructorWithInitializerListAsSyntacticSugar
) {
2443 std::string Code
= R
"(
2456 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2457 ASTContext
&ASTCtx
) {
2458 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2460 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2462 const auto &FooLoc
=
2463 getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "Foo");
2464 const auto &BarLoc
=
2465 getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "Bar");
2467 const auto *FooBazVal
=
2468 cast
<IntegerValue
>(getFieldValue(&FooLoc
, *BazDecl
, Env
));
2469 const auto *BarBazVal
=
2470 cast
<IntegerValue
>(getFieldValue(&BarLoc
, *BazDecl
, Env
));
2471 EXPECT_EQ(FooBazVal
, BarBazVal
);
2475 TEST(TransferTest
, CopyConstructorArgIsRefReturnedByFunction
) {
2476 // This is a crash repro.
2477 std::string Code
= R
"(
2479 const S &returnsSRef();
2486 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2487 ASTContext
&ASTCtx
) {});
2490 TEST(TransferTest
, MoveConstructor
) {
2491 std::string Code
= R
"(
2494 template <typename T> struct remove_reference { using type = T; };
2495 template <typename T> struct remove_reference<T&> { using type = T; };
2496 template <typename T> struct remove_reference<T&&> { using type = T; };
2498 template <typename T>
2499 using remove_reference_t = typename remove_reference<T>::type;
2501 template <typename T>
2502 std::remove_reference_t<T>&& move(T&& x);
2515 Foo = std::move(Bar);
2521 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2522 ASTContext
&ASTCtx
) {
2523 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p1", "p2"));
2524 const Environment
&Env1
= getEnvironmentAtAnnotation(Results
, "p1");
2525 const Environment
&Env2
= getEnvironmentAtAnnotation(Results
, "p2");
2527 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2528 ASSERT_THAT(FooDecl
, NotNull());
2530 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2531 ASSERT_THAT(BarDecl
, NotNull());
2533 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2534 ASSERT_THAT(BazDecl
, NotNull());
2536 const auto *FooLoc1
=
2537 cast
<RecordStorageLocation
>(Env1
.getStorageLocation(*FooDecl
));
2538 const auto *BarLoc1
=
2539 cast
<RecordStorageLocation
>(Env1
.getStorageLocation(*BarDecl
));
2541 EXPECT_FALSE(recordsEqual(*FooLoc1
, *BarLoc1
, Env1
));
2543 const auto *FooVal1
= cast
<RecordValue
>(Env1
.getValue(*FooLoc1
));
2544 const auto *BarVal1
= cast
<RecordValue
>(Env1
.getValue(*BarLoc1
));
2545 EXPECT_NE(FooVal1
, BarVal1
);
2547 const auto *FooBazVal1
=
2548 cast
<IntegerValue
>(getFieldValue(FooLoc1
, *BazDecl
, Env1
));
2549 const auto *BarBazVal1
=
2550 cast
<IntegerValue
>(getFieldValue(BarLoc1
, *BazDecl
, Env1
));
2551 EXPECT_NE(FooBazVal1
, BarBazVal1
);
2553 const auto *FooLoc2
=
2554 cast
<RecordStorageLocation
>(Env2
.getStorageLocation(*FooDecl
));
2555 const auto *FooVal2
= cast
<RecordValue
>(Env2
.getValue(*FooLoc2
));
2556 EXPECT_NE(FooVal2
, BarVal1
);
2557 EXPECT_TRUE(recordsEqual(*FooLoc2
, Env2
, *BarLoc1
, Env1
));
2559 const auto *FooBazVal2
=
2560 cast
<IntegerValue
>(getFieldValue(FooLoc1
, *BazDecl
, Env2
));
2561 EXPECT_EQ(FooBazVal2
, BarBazVal1
);
2565 TEST(TransferTest
, BindTemporary
) {
2566 std::string Code
= R
"(
2568 virtual ~A() = default;
2573 void target(A Foo) {
2574 int Bar = A(Foo).Baz;
2580 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2581 ASTContext
&ASTCtx
) {
2582 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2583 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2585 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2586 ASSERT_THAT(FooDecl
, NotNull());
2588 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2589 ASSERT_THAT(BarDecl
, NotNull());
2591 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2592 ASSERT_THAT(BazDecl
, NotNull());
2594 const auto &FooLoc
=
2595 *cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2596 const auto *BarVal
= cast
<IntegerValue
>(Env
.getValue(*BarDecl
));
2597 EXPECT_EQ(BarVal
, getFieldValue(&FooLoc
, *BazDecl
, Env
));
2601 TEST(TransferTest
, StaticCast
) {
2602 std::string Code
= R
"(
2603 void target(int Foo) {
2604 int Bar = static_cast<int>(Foo);
2610 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2611 ASTContext
&ASTCtx
) {
2612 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2613 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2615 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2616 ASSERT_THAT(FooDecl
, NotNull());
2618 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2619 ASSERT_THAT(BarDecl
, NotNull());
2621 const auto *FooVal
= Env
.getValue(*FooDecl
);
2622 const auto *BarVal
= Env
.getValue(*BarDecl
);
2623 EXPECT_TRUE(isa
<IntegerValue
>(FooVal
));
2624 EXPECT_TRUE(isa
<IntegerValue
>(BarVal
));
2625 EXPECT_EQ(FooVal
, BarVal
);
2629 TEST(TransferTest
, IntegralCast
) {
2630 std::string Code
= R
"(
2631 void target(int Foo) {
2638 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2639 ASTContext
&ASTCtx
) {
2640 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2641 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2643 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2644 ASSERT_THAT(FooDecl
, NotNull());
2646 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2647 ASSERT_THAT(BarDecl
, NotNull());
2649 const auto *FooVal
= Env
.getValue(*FooDecl
);
2650 const auto *BarVal
= Env
.getValue(*BarDecl
);
2651 EXPECT_TRUE(isa
<IntegerValue
>(FooVal
));
2652 EXPECT_TRUE(isa
<IntegerValue
>(BarVal
));
2653 EXPECT_EQ(FooVal
, BarVal
);
2657 TEST(TransferTest
, IntegraltoBooleanCast
) {
2658 std::string Code
= R
"(
2659 void target(int Foo) {
2666 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2667 ASTContext
&ASTCtx
) {
2668 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2669 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2671 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2672 ASSERT_THAT(FooDecl
, NotNull());
2674 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2675 ASSERT_THAT(BarDecl
, NotNull());
2677 const auto *FooVal
= Env
.getValue(*FooDecl
);
2678 const auto *BarVal
= Env
.getValue(*BarDecl
);
2679 EXPECT_TRUE(isa
<IntegerValue
>(FooVal
));
2680 EXPECT_TRUE(isa
<BoolValue
>(BarVal
));
2684 TEST(TransferTest
, IntegralToBooleanCastFromBool
) {
2685 std::string Code
= R
"(
2686 void target(bool Foo) {
2694 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2695 ASTContext
&ASTCtx
) {
2696 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2697 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2699 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2700 ASSERT_THAT(FooDecl
, NotNull());
2702 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2703 ASSERT_THAT(BarDecl
, NotNull());
2705 const auto *FooVal
= Env
.getValue(*FooDecl
);
2706 const auto *BarVal
= Env
.getValue(*BarDecl
);
2707 EXPECT_TRUE(isa
<BoolValue
>(FooVal
));
2708 EXPECT_TRUE(isa
<BoolValue
>(BarVal
));
2709 EXPECT_EQ(FooVal
, BarVal
);
2713 TEST(TransferTest
, NullToPointerCast
) {
2714 std::string Code
= R
"(
2715 using my_nullptr_t = decltype(nullptr);
2718 int *FooX = nullptr;
2719 int *FooY = nullptr;
2720 bool **Bar = nullptr;
2722 my_nullptr_t Null = 0;
2728 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2729 ASTContext
&ASTCtx
) {
2730 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2731 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2733 const ValueDecl
*FooXDecl
= findValueDecl(ASTCtx
, "FooX");
2734 ASSERT_THAT(FooXDecl
, NotNull());
2736 const ValueDecl
*FooYDecl
= findValueDecl(ASTCtx
, "FooY");
2737 ASSERT_THAT(FooYDecl
, NotNull());
2739 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2740 ASSERT_THAT(BarDecl
, NotNull());
2742 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2743 ASSERT_THAT(BazDecl
, NotNull());
2745 const ValueDecl
*NullDecl
= findValueDecl(ASTCtx
, "Null");
2746 ASSERT_THAT(NullDecl
, NotNull());
2748 const auto *FooXVal
= cast
<PointerValue
>(Env
.getValue(*FooXDecl
));
2749 const auto *FooYVal
= cast
<PointerValue
>(Env
.getValue(*FooYDecl
));
2750 const auto *BarVal
= cast
<PointerValue
>(Env
.getValue(*BarDecl
));
2751 const auto *BazVal
= cast
<PointerValue
>(Env
.getValue(*BazDecl
));
2752 const auto *NullVal
= cast
<PointerValue
>(Env
.getValue(*NullDecl
));
2754 EXPECT_EQ(FooXVal
, FooYVal
);
2755 EXPECT_NE(FooXVal
, BarVal
);
2756 EXPECT_NE(FooXVal
, BazVal
);
2757 EXPECT_NE(BarVal
, BazVal
);
2759 const StorageLocation
&FooPointeeLoc
= FooXVal
->getPointeeLoc();
2760 EXPECT_TRUE(isa
<ScalarStorageLocation
>(FooPointeeLoc
));
2761 EXPECT_THAT(Env
.getValue(FooPointeeLoc
), IsNull());
2763 const StorageLocation
&BarPointeeLoc
= BarVal
->getPointeeLoc();
2764 EXPECT_TRUE(isa
<ScalarStorageLocation
>(BarPointeeLoc
));
2765 EXPECT_THAT(Env
.getValue(BarPointeeLoc
), IsNull());
2767 const StorageLocation
&BazPointeeLoc
= BazVal
->getPointeeLoc();
2768 EXPECT_TRUE(isa
<RecordStorageLocation
>(BazPointeeLoc
));
2769 EXPECT_THAT(Env
.getValue(BazPointeeLoc
), IsNull());
2771 const StorageLocation
&NullPointeeLoc
= NullVal
->getPointeeLoc();
2772 EXPECT_TRUE(isa
<ScalarStorageLocation
>(NullPointeeLoc
));
2773 EXPECT_THAT(Env
.getValue(NullPointeeLoc
), IsNull());
2777 TEST(TransferTest
, PointerToMemberVariable
) {
2778 std::string Code
= R
"(
2783 int S::*MemberPointer = &S::i;
2789 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2790 ASTContext
&ASTCtx
) {
2791 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2793 const ValueDecl
*MemberPointerDecl
=
2794 findValueDecl(ASTCtx
, "MemberPointer");
2795 ASSERT_THAT(MemberPointerDecl
, NotNull());
2796 ASSERT_THAT(Env
.getValue(*MemberPointerDecl
), IsNull());
2800 TEST(TransferTest
, PointerToMemberFunction
) {
2801 std::string Code
= R
"(
2806 void (S::*MemberPointer)() = &S::Method;
2812 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2813 ASTContext
&ASTCtx
) {
2814 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2816 const ValueDecl
*MemberPointerDecl
=
2817 findValueDecl(ASTCtx
, "MemberPointer");
2818 ASSERT_THAT(MemberPointerDecl
, NotNull());
2819 ASSERT_THAT(Env
.getValue(*MemberPointerDecl
), IsNull());
2823 TEST(TransferTest
, NullToMemberPointerCast
) {
2824 std::string Code
= R
"(
2827 int Foo::*MemberPointer = nullptr;
2833 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2834 ASTContext
&ASTCtx
) {
2835 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2836 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2838 const ValueDecl
*MemberPointerDecl
=
2839 findValueDecl(ASTCtx
, "MemberPointer");
2840 ASSERT_THAT(MemberPointerDecl
, NotNull());
2841 ASSERT_THAT(Env
.getValue(*MemberPointerDecl
), IsNull());
2845 TEST(TransferTest
, AddrOfValue
) {
2846 std::string Code
= R
"(
2855 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2856 ASTContext
&ASTCtx
) {
2857 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2858 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2860 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2861 ASSERT_THAT(FooDecl
, NotNull());
2863 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2864 ASSERT_THAT(BarDecl
, NotNull());
2866 const auto *FooLoc
=
2867 cast
<ScalarStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2868 const auto *BarVal
= cast
<PointerValue
>(Env
.getValue(*BarDecl
));
2869 EXPECT_EQ(&BarVal
->getPointeeLoc(), FooLoc
);
2873 TEST(TransferTest
, AddrOfReference
) {
2874 std::string Code
= R
"(
2875 void target(int *Foo) {
2882 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2883 ASTContext
&ASTCtx
) {
2884 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2885 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2887 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2888 ASSERT_THAT(FooDecl
, NotNull());
2890 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2891 ASSERT_THAT(BarDecl
, NotNull());
2893 const auto *FooVal
= cast
<PointerValue
>(Env
.getValue(*FooDecl
));
2894 const auto *BarVal
= cast
<PointerValue
>(Env
.getValue(*BarDecl
));
2895 EXPECT_EQ(&BarVal
->getPointeeLoc(), &FooVal
->getPointeeLoc());
2899 TEST(TransferTest
, CannotAnalyzeFunctionTemplate
) {
2900 std::string Code
= R
"(
2901 template <typename T>
2905 checkDataflowWithNoopAnalysis(Code
),
2906 llvm::FailedWithMessage("Cannot analyze templated declarations"));
2909 TEST(TransferTest
, CannotAnalyzeMethodOfClassTemplate
) {
2910 std::string Code
= R
"(
2911 template <typename T>
2917 checkDataflowWithNoopAnalysis(Code
),
2918 llvm::FailedWithMessage("Cannot analyze templated declarations"));
2921 TEST(TransferTest
, VarDeclInitAssignConditionalOperator
) {
2922 std::string Code
= R
"(
2925 void target(A Foo, A Bar, bool Cond) {
2926 A Baz = Cond ? Foo : Bar;
2932 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2933 ASTContext
&ASTCtx
) {
2934 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2935 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2937 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2938 ASSERT_THAT(FooDecl
, NotNull());
2940 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2941 ASSERT_THAT(BarDecl
, NotNull());
2943 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2944 ASSERT_THAT(BazDecl
, NotNull());
2946 const auto *FooVal
= cast
<RecordValue
>(Env
.getValue(*FooDecl
));
2947 const auto *BarVal
= cast
<RecordValue
>(Env
.getValue(*BarDecl
));
2949 const auto *BazVal
= dyn_cast
<RecordValue
>(Env
.getValue(*BazDecl
));
2950 ASSERT_THAT(BazVal
, NotNull());
2952 EXPECT_NE(BazVal
, FooVal
);
2953 EXPECT_NE(BazVal
, BarVal
);
2957 TEST(TransferTest
, VarDeclInDoWhile
) {
2958 std::string Code
= R
"(
2959 void target(int *Foo) {
2970 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2971 ASTContext
&ASTCtx
) {
2972 const Environment
&EnvInLoop
=
2973 getEnvironmentAtAnnotation(Results
, "in_loop");
2974 const Environment
&EnvAfterLoop
=
2975 getEnvironmentAtAnnotation(Results
, "after_loop");
2977 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2978 ASSERT_THAT(FooDecl
, NotNull());
2980 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2981 ASSERT_THAT(BarDecl
, NotNull());
2983 const auto *FooVal
=
2984 cast
<PointerValue
>(EnvAfterLoop
.getValue(*FooDecl
));
2985 const auto *FooPointeeVal
=
2986 cast
<IntegerValue
>(EnvAfterLoop
.getValue(FooVal
->getPointeeLoc()));
2988 const auto *BarVal
= cast
<IntegerValue
>(EnvInLoop
.getValue(*BarDecl
));
2989 EXPECT_EQ(BarVal
, FooPointeeVal
);
2991 ASSERT_THAT(EnvAfterLoop
.getValue(*BarDecl
), IsNull());
2995 TEST(TransferTest
, UnreachableAfterWhileTrue
) {
2996 std::string Code
= R
"(
3005 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3006 ASTContext
&ASTCtx
) {
3007 // The node after the while-true is pruned because it is trivially
3008 // known to be unreachable.
3009 ASSERT_TRUE(Results
.empty());
3013 TEST(TransferTest
, AggregateInitialization
) {
3014 std::string BracesCode
= R
"(
3025 void target(int BarArg, int FooArg, int QuxArg) {
3026 B Quux{BarArg, {FooArg}, QuxArg};
3031 std::string BraceElisionCode
= R
"(
3042 void target(int BarArg, int FooArg, int QuxArg) {
3043 B Quux = {BarArg, FooArg, QuxArg};
3048 for (const std::string
&Code
: {BracesCode
, BraceElisionCode
}) {
3051 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3052 ASTContext
&ASTCtx
) {
3053 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3054 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3056 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3057 ASSERT_THAT(FooDecl
, NotNull());
3059 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3060 ASSERT_THAT(BarDecl
, NotNull());
3062 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
3063 ASSERT_THAT(BazDecl
, NotNull());
3065 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
3066 ASSERT_THAT(QuxDecl
, NotNull());
3068 const ValueDecl
*FooArgDecl
= findValueDecl(ASTCtx
, "FooArg");
3069 ASSERT_THAT(FooArgDecl
, NotNull());
3071 const ValueDecl
*BarArgDecl
= findValueDecl(ASTCtx
, "BarArg");
3072 ASSERT_THAT(BarArgDecl
, NotNull());
3074 const ValueDecl
*QuxArgDecl
= findValueDecl(ASTCtx
, "QuxArg");
3075 ASSERT_THAT(QuxArgDecl
, NotNull());
3077 const ValueDecl
*QuuxDecl
= findValueDecl(ASTCtx
, "Quux");
3078 ASSERT_THAT(QuuxDecl
, NotNull());
3080 const auto *FooArgVal
= cast
<IntegerValue
>(Env
.getValue(*FooArgDecl
));
3081 const auto *BarArgVal
= cast
<IntegerValue
>(Env
.getValue(*BarArgDecl
));
3082 const auto *QuxArgVal
= cast
<IntegerValue
>(Env
.getValue(*QuxArgDecl
));
3084 const auto &QuuxLoc
=
3085 *cast
<RecordStorageLocation
>(Env
.getStorageLocation(*QuuxDecl
));
3086 const auto &BazLoc
=
3087 *cast
<RecordStorageLocation
>(QuuxLoc
.getChild(*BazDecl
));
3089 EXPECT_EQ(getFieldValue(&QuuxLoc
, *BarDecl
, Env
), BarArgVal
);
3090 EXPECT_EQ(getFieldValue(&BazLoc
, *FooDecl
, Env
), FooArgVal
);
3091 EXPECT_EQ(getFieldValue(&QuuxLoc
, *QuxDecl
, Env
), QuxArgVal
);
3093 // Check that fields initialized in an initializer list are always
3094 // modeled in other instances of the same type.
3095 const auto &OtherBLoc
=
3096 getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "OtherB");
3097 EXPECT_THAT(OtherBLoc
.getChild(*BarDecl
), NotNull());
3098 EXPECT_THAT(OtherBLoc
.getChild(*BazDecl
), NotNull());
3099 EXPECT_THAT(OtherBLoc
.getChild(*QuxDecl
), NotNull());
3104 TEST(TransferTest
, AggregateInitializationReferenceField
) {
3105 std::string Code
= R
"(
3110 void target(int i) {
3117 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3118 ASTContext
&ASTCtx
) {
3119 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3121 const ValueDecl
*RefFieldDecl
= findValueDecl(ASTCtx
, "RefField");
3123 auto &ILoc
= getLocForDecl
<StorageLocation
>(ASTCtx
, Env
, "i");
3124 auto &SLoc
= getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "s");
3126 EXPECT_EQ(SLoc
.getChild(*RefFieldDecl
), &ILoc
);
3130 TEST(TransferTest
, AggregateInitialization_NotExplicitlyInitializedField
) {
3131 std::string Code
= R
"(
3137 void target(int i) {
3144 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3145 ASTContext
&ASTCtx
) {
3146 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3148 const ValueDecl
*I1FieldDecl
= findValueDecl(ASTCtx
, "i1");
3149 const ValueDecl
*I2FieldDecl
= findValueDecl(ASTCtx
, "i2");
3151 auto &SLoc
= getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "s");
3153 auto &IValue
= getValueForDecl
<IntegerValue
>(ASTCtx
, Env
, "i");
3155 *cast
<IntegerValue
>(getFieldValue(&SLoc
, *I1FieldDecl
, Env
));
3156 EXPECT_EQ(&I1Value
, &IValue
);
3158 *cast
<IntegerValue
>(getFieldValue(&SLoc
, *I2FieldDecl
, Env
));
3159 EXPECT_NE(&I2Value
, &IValue
);
3163 TEST(TransferTest
, AssignToUnionMember
) {
3164 std::string Code
= R
"(
3169 void target(int Bar) {
3177 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3178 ASTContext
&ASTCtx
) {
3179 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3180 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3182 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
3183 ASSERT_THAT(BazDecl
, NotNull());
3184 ASSERT_TRUE(BazDecl
->getType()->isUnionType());
3186 auto BazFields
= BazDecl
->getType()->getAsRecordDecl()->fields();
3187 FieldDecl
*FooDecl
= nullptr;
3188 for (FieldDecl
*Field
: BazFields
) {
3189 if (Field
->getNameAsString() == "Foo") {
3192 FAIL() << "Unexpected field: " << Field
->getNameAsString();
3195 ASSERT_THAT(FooDecl
, NotNull());
3197 const auto *BazLoc
= dyn_cast_or_null
<RecordStorageLocation
>(
3198 Env
.getStorageLocation(*BazDecl
));
3199 ASSERT_THAT(BazLoc
, NotNull());
3200 ASSERT_THAT(Env
.getValue(*BazLoc
), NotNull());
3202 const auto *FooVal
=
3203 cast
<IntegerValue
>(getFieldValue(BazLoc
, *FooDecl
, Env
));
3205 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3206 ASSERT_THAT(BarDecl
, NotNull());
3207 const auto *BarLoc
= Env
.getStorageLocation(*BarDecl
);
3208 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
3210 EXPECT_EQ(Env
.getValue(*BarLoc
), FooVal
);
3214 TEST(TransferTest
, AssignFromBoolLiteral
) {
3215 std::string Code
= R
"(
3224 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3225 ASTContext
&ASTCtx
) {
3226 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3227 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3229 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3230 ASSERT_THAT(FooDecl
, NotNull());
3232 const auto *FooVal
=
3233 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*FooDecl
));
3234 ASSERT_THAT(FooVal
, NotNull());
3236 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3237 ASSERT_THAT(BarDecl
, NotNull());
3239 const auto *BarVal
=
3240 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BarDecl
));
3241 ASSERT_THAT(BarVal
, NotNull());
3243 EXPECT_EQ(FooVal
, &Env
.getBoolLiteralValue(true));
3244 EXPECT_EQ(BarVal
, &Env
.getBoolLiteralValue(false));
3248 TEST(TransferTest
, AssignFromCompositeBoolExpression
) {
3250 std::string Code
= R
"(
3251 void target(bool Foo, bool Bar, bool Qux) {
3252 bool Baz = (Foo) && (Bar || Qux);
3258 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3259 ASTContext
&ASTCtx
) {
3260 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3261 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3263 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3264 ASSERT_THAT(FooDecl
, NotNull());
3266 const auto *FooVal
=
3267 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*FooDecl
));
3268 ASSERT_THAT(FooVal
, NotNull());
3270 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3271 ASSERT_THAT(BarDecl
, NotNull());
3273 const auto *BarVal
=
3274 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BarDecl
));
3275 ASSERT_THAT(BarVal
, NotNull());
3277 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
3278 ASSERT_THAT(QuxDecl
, NotNull());
3280 const auto *QuxVal
=
3281 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*QuxDecl
));
3282 ASSERT_THAT(QuxVal
, NotNull());
3284 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
3285 ASSERT_THAT(BazDecl
, NotNull());
3287 const auto *BazVal
=
3288 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BazDecl
));
3289 ASSERT_THAT(BazVal
, NotNull());
3290 auto &A
= Env
.arena();
3291 EXPECT_EQ(&BazVal
->formula(),
3292 &A
.makeAnd(FooVal
->formula(),
3293 A
.makeOr(BarVal
->formula(), QuxVal
->formula())));
3298 std::string Code
= R
"(
3299 void target(bool Foo, bool Bar, bool Qux) {
3300 bool Baz = (Foo && Qux) || (Bar);
3306 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3307 ASTContext
&ASTCtx
) {
3308 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3309 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3311 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3312 ASSERT_THAT(FooDecl
, NotNull());
3314 const auto *FooVal
=
3315 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*FooDecl
));
3316 ASSERT_THAT(FooVal
, NotNull());
3318 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3319 ASSERT_THAT(BarDecl
, NotNull());
3321 const auto *BarVal
=
3322 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BarDecl
));
3323 ASSERT_THAT(BarVal
, NotNull());
3325 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
3326 ASSERT_THAT(QuxDecl
, NotNull());
3328 const auto *QuxVal
=
3329 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*QuxDecl
));
3330 ASSERT_THAT(QuxVal
, NotNull());
3332 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
3333 ASSERT_THAT(BazDecl
, NotNull());
3335 const auto *BazVal
=
3336 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BazDecl
));
3337 ASSERT_THAT(BazVal
, NotNull());
3338 auto &A
= Env
.arena();
3339 EXPECT_EQ(&BazVal
->formula(),
3340 &A
.makeOr(A
.makeAnd(FooVal
->formula(), QuxVal
->formula()),
3341 BarVal
->formula()));
3346 std::string Code
= R
"(
3347 void target(bool A, bool B, bool C, bool D) {
3348 bool Foo = ((A && B) && C) && D;
3354 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3355 ASTContext
&ASTCtx
) {
3356 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3357 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3359 const ValueDecl
*ADecl
= findValueDecl(ASTCtx
, "A");
3360 ASSERT_THAT(ADecl
, NotNull());
3362 const auto *AVal
= dyn_cast_or_null
<BoolValue
>(Env
.getValue(*ADecl
));
3363 ASSERT_THAT(AVal
, NotNull());
3365 const ValueDecl
*BDecl
= findValueDecl(ASTCtx
, "B");
3366 ASSERT_THAT(BDecl
, NotNull());
3368 const auto *BVal
= dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BDecl
));
3369 ASSERT_THAT(BVal
, NotNull());
3371 const ValueDecl
*CDecl
= findValueDecl(ASTCtx
, "C");
3372 ASSERT_THAT(CDecl
, NotNull());
3374 const auto *CVal
= dyn_cast_or_null
<BoolValue
>(Env
.getValue(*CDecl
));
3375 ASSERT_THAT(CVal
, NotNull());
3377 const ValueDecl
*DDecl
= findValueDecl(ASTCtx
, "D");
3378 ASSERT_THAT(DDecl
, NotNull());
3380 const auto *DVal
= dyn_cast_or_null
<BoolValue
>(Env
.getValue(*DDecl
));
3381 ASSERT_THAT(DVal
, NotNull());
3383 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3384 ASSERT_THAT(FooDecl
, NotNull());
3386 const auto *FooVal
=
3387 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*FooDecl
));
3388 ASSERT_THAT(FooVal
, NotNull());
3389 auto &A
= Env
.arena();
3392 &A
.makeAnd(A
.makeAnd(A
.makeAnd(AVal
->formula(), BVal
->formula()),
3399 TEST(TransferTest
, AssignFromBoolNegation
) {
3400 std::string Code
= R
"(
3409 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3410 ASTContext
&ASTCtx
) {
3411 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3412 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3414 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3415 ASSERT_THAT(FooDecl
, NotNull());
3417 const auto *FooVal
=
3418 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*FooDecl
));
3419 ASSERT_THAT(FooVal
, NotNull());
3421 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3422 ASSERT_THAT(BarDecl
, NotNull());
3424 const auto *BarVal
=
3425 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BarDecl
));
3426 ASSERT_THAT(BarVal
, NotNull());
3427 auto &A
= Env
.arena();
3428 EXPECT_EQ(&BarVal
->formula(), &A
.makeNot(FooVal
->formula()));
3432 TEST(TransferTest
, BuiltinExpect
) {
3433 std::string Code
= R
"(
3434 void target(long Foo) {
3435 long Bar = __builtin_expect(Foo, true);
3441 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3442 ASTContext
&ASTCtx
) {
3443 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3444 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3446 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3447 ASSERT_THAT(FooDecl
, NotNull());
3449 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3450 ASSERT_THAT(BarDecl
, NotNull());
3452 EXPECT_EQ(Env
.getValue(*FooDecl
), Env
.getValue(*BarDecl
));
3456 // `__builtin_expect` takes and returns a `long` argument, so other types
3457 // involve casts. This verifies that we identify the input and output in that
3459 TEST(TransferTest
, BuiltinExpectBoolArg
) {
3460 std::string Code
= R
"(
3461 void target(bool Foo) {
3462 bool Bar = __builtin_expect(Foo, true);
3468 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3469 ASTContext
&ASTCtx
) {
3470 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3471 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3473 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3474 ASSERT_THAT(FooDecl
, NotNull());
3476 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3477 ASSERT_THAT(BarDecl
, NotNull());
3479 EXPECT_EQ(Env
.getValue(*FooDecl
), Env
.getValue(*BarDecl
));
3483 TEST(TransferTest
, BuiltinUnreachable
) {
3484 std::string Code
= R
"(
3485 void target(bool Foo) {
3490 __builtin_unreachable();
3497 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3498 ASTContext
&ASTCtx
) {
3499 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3500 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3502 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3503 ASSERT_THAT(FooDecl
, NotNull());
3505 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3506 ASSERT_THAT(BarDecl
, NotNull());
3508 // `__builtin_unreachable` promises that the code is
3509 // unreachable, so the compiler treats the "then" branch as the
3510 // only possible predecessor of this statement.
3511 EXPECT_EQ(Env
.getValue(*FooDecl
), Env
.getValue(*BarDecl
));
3515 TEST(TransferTest
, BuiltinTrap
) {
3516 std::string Code
= R
"(
3517 void target(bool Foo) {
3529 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3530 ASTContext
&ASTCtx
) {
3531 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3532 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3534 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3535 ASSERT_THAT(FooDecl
, NotNull());
3537 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3538 ASSERT_THAT(BarDecl
, NotNull());
3540 // `__builtin_trap` ensures program termination, so only the
3541 // "then" branch is a predecessor of this statement.
3542 EXPECT_EQ(Env
.getValue(*FooDecl
), Env
.getValue(*BarDecl
));
3546 TEST(TransferTest
, BuiltinDebugTrap
) {
3547 std::string Code
= R
"(
3548 void target(bool Foo) {
3553 __builtin_debugtrap();
3560 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3561 ASTContext
&ASTCtx
) {
3562 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3563 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3565 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3566 ASSERT_THAT(FooDecl
, NotNull());
3568 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3569 ASSERT_THAT(BarDecl
, NotNull());
3571 // `__builtin_debugtrap` doesn't ensure program termination.
3572 EXPECT_NE(Env
.getValue(*FooDecl
), Env
.getValue(*BarDecl
));
3576 TEST(TransferTest
, StaticIntSingleVarDecl
) {
3577 std::string Code
= R
"(
3585 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3586 ASTContext
&ASTCtx
) {
3587 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3588 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3590 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3591 ASSERT_THAT(FooDecl
, NotNull());
3593 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
3594 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
3596 const Value
*FooVal
= Env
.getValue(*FooLoc
);
3597 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
3601 TEST(TransferTest
, StaticIntGroupVarDecl
) {
3602 std::string Code
= R
"(
3604 static int Foo, Bar;
3611 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3612 ASTContext
&ASTCtx
) {
3613 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3614 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3616 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3617 ASSERT_THAT(FooDecl
, NotNull());
3619 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3620 ASSERT_THAT(BarDecl
, NotNull());
3622 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
3623 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
3625 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
3626 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
3628 const Value
*FooVal
= Env
.getValue(*FooLoc
);
3629 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
3631 const Value
*BarVal
= Env
.getValue(*BarLoc
);
3632 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
3634 EXPECT_NE(FooVal
, BarVal
);
3638 TEST(TransferTest
, GlobalIntVarDecl
) {
3639 std::string Code
= R
"(
3650 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3651 ASTContext
&ASTCtx
) {
3652 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3653 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3655 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3656 ASSERT_THAT(BarDecl
, NotNull());
3658 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
3659 ASSERT_THAT(BazDecl
, NotNull());
3661 const Value
*BarVal
= cast
<IntegerValue
>(Env
.getValue(*BarDecl
));
3662 const Value
*BazVal
= cast
<IntegerValue
>(Env
.getValue(*BazDecl
));
3663 EXPECT_EQ(BarVal
, BazVal
);
3667 TEST(TransferTest
, StaticMemberIntVarDecl
) {
3668 std::string Code
= R
"(
3681 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3682 ASTContext
&ASTCtx
) {
3683 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3684 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3686 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3687 ASSERT_THAT(BarDecl
, NotNull());
3689 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
3690 ASSERT_THAT(BazDecl
, NotNull());
3692 const Value
*BarVal
= cast
<IntegerValue
>(Env
.getValue(*BarDecl
));
3693 const Value
*BazVal
= cast
<IntegerValue
>(Env
.getValue(*BazDecl
));
3694 EXPECT_EQ(BarVal
, BazVal
);
3698 TEST(TransferTest
, StaticMemberRefVarDecl
) {
3699 std::string Code
= R
"(
3712 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3713 ASTContext
&ASTCtx
) {
3714 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3715 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3717 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3718 ASSERT_THAT(BarDecl
, NotNull());
3720 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
3721 ASSERT_THAT(BazDecl
, NotNull());
3723 const Value
*BarVal
= cast
<IntegerValue
>(Env
.getValue(*BarDecl
));
3724 const Value
*BazVal
= cast
<IntegerValue
>(Env
.getValue(*BazDecl
));
3725 EXPECT_EQ(BarVal
, BazVal
);
3729 TEST(TransferTest
, AssignMemberBeforeCopy
) {
3730 std::string Code
= R
"(
3746 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3747 ASTContext
&ASTCtx
) {
3748 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3749 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3751 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3752 ASSERT_THAT(FooDecl
, NotNull());
3754 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3755 ASSERT_THAT(BarDecl
, NotNull());
3757 const ValueDecl
*A1Decl
= findValueDecl(ASTCtx
, "A1");
3758 ASSERT_THAT(A1Decl
, NotNull());
3760 const ValueDecl
*A2Decl
= findValueDecl(ASTCtx
, "A2");
3761 ASSERT_THAT(A2Decl
, NotNull());
3763 const auto *BarVal
= cast
<IntegerValue
>(Env
.getValue(*BarDecl
));
3766 *cast
<RecordStorageLocation
>(Env
.getStorageLocation(*A2Decl
));
3767 EXPECT_EQ(getFieldValue(&A2Loc
, *FooDecl
, Env
), BarVal
);
3771 TEST(TransferTest
, BooleanEquality
) {
3772 std::string Code
= R
"(
3773 void target(bool Bar) {
3786 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3787 ASTContext
&ASTCtx
) {
3788 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p-then", "p-else"));
3789 const Environment
&EnvThen
=
3790 getEnvironmentAtAnnotation(Results
, "p-then");
3791 const Environment
&EnvElse
=
3792 getEnvironmentAtAnnotation(Results
, "p-else");
3794 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3795 ASSERT_THAT(BarDecl
, NotNull());
3797 auto &BarValThen
= getFormula(*BarDecl
, EnvThen
);
3798 EXPECT_TRUE(EnvThen
.proves(BarValThen
));
3800 auto &BarValElse
= getFormula(*BarDecl
, EnvElse
);
3801 EXPECT_TRUE(EnvElse
.proves(EnvElse
.arena().makeNot(BarValElse
)));
3805 TEST(TransferTest
, BooleanInequality
) {
3806 std::string Code
= R
"(
3807 void target(bool Bar) {
3820 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3821 ASTContext
&ASTCtx
) {
3822 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p-then", "p-else"));
3823 const Environment
&EnvThen
=
3824 getEnvironmentAtAnnotation(Results
, "p-then");
3825 const Environment
&EnvElse
=
3826 getEnvironmentAtAnnotation(Results
, "p-else");
3828 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3829 ASSERT_THAT(BarDecl
, NotNull());
3831 auto &BarValThen
= getFormula(*BarDecl
, EnvThen
);
3832 EXPECT_TRUE(EnvThen
.proves(EnvThen
.arena().makeNot(BarValThen
)));
3834 auto &BarValElse
= getFormula(*BarDecl
, EnvElse
);
3835 EXPECT_TRUE(EnvElse
.proves(BarValElse
));
3839 TEST(TransferTest
, IntegerLiteralEquality
) {
3840 std::string Code
= R
"(
3842 bool equal = (42 == 42);
3848 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3849 ASTContext
&ASTCtx
) {
3850 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3853 getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "equal").formula();
3854 EXPECT_TRUE(Env
.proves(Equal
));
3858 TEST(TransferTest
, CorrelatedBranches
) {
3859 std::string Code
= R
"(
3860 void target(bool B, bool C) {
3878 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3879 ASTContext
&ASTCtx
) {
3880 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p0", "p1", "p2"));
3882 const ValueDecl
*CDecl
= findValueDecl(ASTCtx
, "C");
3883 ASSERT_THAT(CDecl
, NotNull());
3886 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p0");
3887 const ValueDecl
*BDecl
= findValueDecl(ASTCtx
, "B");
3888 ASSERT_THAT(BDecl
, NotNull());
3889 auto &BVal
= getFormula(*BDecl
, Env
);
3891 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(BVal
)));
3895 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p1");
3896 auto &CVal
= getFormula(*CDecl
, Env
);
3897 EXPECT_TRUE(Env
.proves(CVal
));
3901 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p2");
3902 auto &CVal
= getFormula(*CDecl
, Env
);
3903 EXPECT_TRUE(Env
.proves(CVal
));
3908 TEST(TransferTest
, LoopWithAssignmentConverges
) {
3909 std::string Code
= R
"(
3921 // The key property that we are verifying is implicit in `runDataflow` --
3922 // namely, that the analysis succeeds, rather than hitting the maximum number
3926 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3927 ASTContext
&ASTCtx
) {
3928 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3929 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3931 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3932 ASSERT_THAT(BarDecl
, NotNull());
3934 auto &BarVal
= getFormula(*BarDecl
, Env
);
3935 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(BarVal
)));
3939 TEST(TransferTest
, LoopWithStagedAssignments
) {
3940 std::string Code
= R
"(
3956 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3957 ASTContext
&ASTCtx
) {
3958 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3959 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3961 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3962 ASSERT_THAT(BarDecl
, NotNull());
3963 const ValueDecl
*ErrDecl
= findValueDecl(ASTCtx
, "Err");
3964 ASSERT_THAT(ErrDecl
, NotNull());
3966 auto &BarVal
= getFormula(*BarDecl
, Env
);
3967 auto &ErrVal
= getFormula(*ErrDecl
, Env
);
3968 EXPECT_TRUE(Env
.proves(BarVal
));
3969 // An unsound analysis, for example only evaluating the loop once, can
3970 // conclude that `Err` is false. So, we test that this conclusion is not
3972 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(ErrVal
)));
3976 TEST(TransferTest
, LoopWithReferenceAssignmentConverges
) {
3977 std::string Code
= R
"(
3989 // The key property that we are verifying is that the analysis succeeds,
3990 // rather than hitting the maximum number of iterations.
3993 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3994 ASTContext
&ASTCtx
) {
3995 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3996 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3998 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3999 ASSERT_THAT(BarDecl
, NotNull());
4001 auto &BarVal
= getFormula(*BarDecl
, Env
);
4002 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(BarVal
)));
4006 TEST(TransferTest
, LoopWithStructReferenceAssignmentConverges
) {
4007 std::string Code
= R
"(
4012 void target(Lookup val, bool b) {
4013 const Lookup* l = nullptr;
4022 // The key property that we are verifying is implicit in `runDataflow` --
4023 // namely, that the analysis succeeds, rather than hitting the maximum number
4027 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4028 ASTContext
&ASTCtx
) {
4029 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p-inner", "p-outer"));
4030 const Environment
&InnerEnv
=
4031 getEnvironmentAtAnnotation(Results
, "p-inner");
4032 const Environment
&OuterEnv
=
4033 getEnvironmentAtAnnotation(Results
, "p-outer");
4035 const ValueDecl
*ValDecl
= findValueDecl(ASTCtx
, "val");
4036 ASSERT_THAT(ValDecl
, NotNull());
4038 const ValueDecl
*LDecl
= findValueDecl(ASTCtx
, "l");
4039 ASSERT_THAT(LDecl
, NotNull());
4042 auto *LVal
= dyn_cast
<PointerValue
>(InnerEnv
.getValue(*LDecl
));
4043 ASSERT_THAT(LVal
, NotNull());
4045 EXPECT_EQ(&LVal
->getPointeeLoc(),
4046 InnerEnv
.getStorageLocation(*ValDecl
));
4049 LVal
= dyn_cast
<PointerValue
>(OuterEnv
.getValue(*LDecl
));
4050 ASSERT_THAT(LVal
, NotNull());
4052 // The loop body may not have been executed, so we should not conclude
4053 // that `l` points to `val`.
4054 EXPECT_NE(&LVal
->getPointeeLoc(),
4055 OuterEnv
.getStorageLocation(*ValDecl
));
4059 TEST(TransferTest
, LoopDereferencingChangingPointerConverges
) {
4060 std::string Code
= R
"cc(
4061 bool some_condition();
4063 void target(int i1, int i2) {
4067 if (some_condition())
4074 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code
), llvm::Succeeded());
4077 TEST(TransferTest
, LoopDereferencingChangingRecordPointerConverges
) {
4078 std::string Code
= R
"cc(
4083 bool some_condition();
4085 void target(Lookup l1, Lookup l2) {
4089 if (some_condition())
4096 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code
), llvm::Succeeded());
4099 TEST(TransferTest
, LoopWithShortCircuitedConditionConverges
) {
4100 std::string Code
= R
"cc(
4105 while (foo() || foo()) {
4110 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code
), llvm::Succeeded());
4113 TEST(TransferTest
, DoesNotCrashOnUnionThisExpr
) {
4114 std::string Code
= R
"(
4126 // This is a crash regression test when calling the transfer function on a
4127 // `CXXThisExpr` that refers to a union.
4130 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
4132 LangStandard::lang_cxx17
, /*ApplyBuiltinTransfer=*/true, "operator=");
4135 TEST(TransferTest
, StructuredBindingAssignFromStructIntMembersToRefs
) {
4136 std::string Code
= R
"(
4146 auto &FooRef = Baz.Foo;
4147 auto &BarRef = Baz.Bar;
4148 auto &[BoundFooRef, BoundBarRef] = Baz;
4154 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4155 ASTContext
&ASTCtx
) {
4156 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4157 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4159 const ValueDecl
*FooRefDecl
= findValueDecl(ASTCtx
, "FooRef");
4160 ASSERT_THAT(FooRefDecl
, NotNull());
4162 const ValueDecl
*BarRefDecl
= findValueDecl(ASTCtx
, "BarRef");
4163 ASSERT_THAT(BarRefDecl
, NotNull());
4165 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
4166 ASSERT_THAT(QuxDecl
, NotNull());
4168 const ValueDecl
*BoundFooRefDecl
= findValueDecl(ASTCtx
, "BoundFooRef");
4169 ASSERT_THAT(BoundFooRefDecl
, NotNull());
4171 const ValueDecl
*BoundBarRefDecl
= findValueDecl(ASTCtx
, "BoundBarRef");
4172 ASSERT_THAT(BoundBarRefDecl
, NotNull());
4174 const StorageLocation
*FooRefLoc
= Env
.getStorageLocation(*FooRefDecl
);
4175 ASSERT_THAT(FooRefLoc
, NotNull());
4177 const StorageLocation
*BarRefLoc
= Env
.getStorageLocation(*BarRefDecl
);
4178 ASSERT_THAT(BarRefLoc
, NotNull());
4180 const Value
*QuxVal
= Env
.getValue(*QuxDecl
);
4181 ASSERT_THAT(QuxVal
, NotNull());
4183 const StorageLocation
*BoundFooRefLoc
=
4184 Env
.getStorageLocation(*BoundFooRefDecl
);
4185 EXPECT_EQ(BoundFooRefLoc
, FooRefLoc
);
4187 const StorageLocation
*BoundBarRefLoc
=
4188 Env
.getStorageLocation(*BoundBarRefDecl
);
4189 EXPECT_EQ(BoundBarRefLoc
, BarRefLoc
);
4191 EXPECT_EQ(Env
.getValue(*BoundFooRefDecl
), QuxVal
);
4195 TEST(TransferTest
, StructuredBindingAssignFromStructRefMembersToRefs
) {
4196 std::string Code
= R
"(
4202 void target(A Baz) {
4205 auto &FooRef = Baz.Foo;
4206 auto &BarRef = Baz.Bar;
4207 auto &[BoundFooRef, BoundBarRef] = Baz;
4213 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4214 ASTContext
&ASTCtx
) {
4215 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4216 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4218 const ValueDecl
*FooRefDecl
= findValueDecl(ASTCtx
, "FooRef");
4219 ASSERT_THAT(FooRefDecl
, NotNull());
4221 const ValueDecl
*BarRefDecl
= findValueDecl(ASTCtx
, "BarRef");
4222 ASSERT_THAT(BarRefDecl
, NotNull());
4224 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
4225 ASSERT_THAT(QuxDecl
, NotNull());
4227 const ValueDecl
*BoundFooRefDecl
= findValueDecl(ASTCtx
, "BoundFooRef");
4228 ASSERT_THAT(BoundFooRefDecl
, NotNull());
4230 const ValueDecl
*BoundBarRefDecl
= findValueDecl(ASTCtx
, "BoundBarRef");
4231 ASSERT_THAT(BoundBarRefDecl
, NotNull());
4233 const StorageLocation
*FooRefLoc
= Env
.getStorageLocation(*FooRefDecl
);
4234 ASSERT_THAT(FooRefLoc
, NotNull());
4236 const StorageLocation
*BarRefLoc
= Env
.getStorageLocation(*BarRefDecl
);
4237 ASSERT_THAT(BarRefLoc
, NotNull());
4239 const Value
*QuxVal
= Env
.getValue(*QuxDecl
);
4240 ASSERT_THAT(QuxVal
, NotNull());
4242 const StorageLocation
*BoundFooRefLoc
=
4243 Env
.getStorageLocation(*BoundFooRefDecl
);
4244 EXPECT_EQ(BoundFooRefLoc
, FooRefLoc
);
4246 const StorageLocation
*BoundBarRefLoc
=
4247 Env
.getStorageLocation(*BoundBarRefDecl
);
4248 EXPECT_EQ(BoundBarRefLoc
, BarRefLoc
);
4250 EXPECT_EQ(Env
.getValue(*BoundFooRefDecl
), QuxVal
);
4254 TEST(TransferTest
, StructuredBindingAssignFromStructIntMembersToInts
) {
4255 std::string Code
= R
"(
4265 auto &FooRef = Baz.Foo;
4266 auto &BarRef = Baz.Bar;
4267 auto [BoundFoo, BoundBar] = Baz;
4273 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4274 ASTContext
&ASTCtx
) {
4275 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4276 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4278 const ValueDecl
*FooRefDecl
= findValueDecl(ASTCtx
, "FooRef");
4279 ASSERT_THAT(FooRefDecl
, NotNull());
4281 const ValueDecl
*BarRefDecl
= findValueDecl(ASTCtx
, "BarRef");
4282 ASSERT_THAT(BarRefDecl
, NotNull());
4284 const ValueDecl
*BoundFooDecl
= findValueDecl(ASTCtx
, "BoundFoo");
4285 ASSERT_THAT(BoundFooDecl
, NotNull());
4287 const ValueDecl
*BoundBarDecl
= findValueDecl(ASTCtx
, "BoundBar");
4288 ASSERT_THAT(BoundBarDecl
, NotNull());
4290 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
4291 ASSERT_THAT(QuxDecl
, NotNull());
4293 const StorageLocation
*FooRefLoc
= Env
.getStorageLocation(*FooRefDecl
);
4294 ASSERT_THAT(FooRefLoc
, NotNull());
4296 const StorageLocation
*BarRefLoc
= Env
.getStorageLocation(*BarRefDecl
);
4297 ASSERT_THAT(BarRefLoc
, NotNull());
4299 const Value
*QuxVal
= Env
.getValue(*QuxDecl
);
4300 ASSERT_THAT(QuxVal
, NotNull());
4302 const StorageLocation
*BoundFooLoc
=
4303 Env
.getStorageLocation(*BoundFooDecl
);
4304 EXPECT_NE(BoundFooLoc
, FooRefLoc
);
4306 const StorageLocation
*BoundBarLoc
=
4307 Env
.getStorageLocation(*BoundBarDecl
);
4308 EXPECT_NE(BoundBarLoc
, BarRefLoc
);
4310 EXPECT_EQ(Env
.getValue(*BoundFooDecl
), QuxVal
);
4314 TEST(TransferTest
, StructuredBindingAssignFromTupleLikeType
) {
4315 std::string Code
= R
"(
4318 template <class> struct tuple_size;
4319 template <std::size_t, class> struct tuple_element;
4320 template <class...> class tuple;
4323 template <class T, T v>
4324 struct size_helper { static const T value = v; };
4327 template <class... T>
4328 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {};
4330 template <std::size_t I, class... T>
4331 struct tuple_element<I, tuple<T...>> {
4332 using type = __type_pack_element<I, T...>;
4335 template <class...> class tuple {};
4337 template <std::size_t I, class... T>
4338 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
4341 std::tuple<bool, int> makeTuple();
4343 void target(bool B) {
4344 auto [BoundFoo, BoundBar] = makeTuple();
4346 // Include if-then-else to test interaction of `BindingDecl` with join.
4360 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4361 ASTContext
&ASTCtx
) {
4362 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p1", "p2"));
4363 const Environment
&Env1
= getEnvironmentAtAnnotation(Results
, "p1");
4365 const ValueDecl
*BoundFooDecl
= findValueDecl(ASTCtx
, "BoundFoo");
4366 ASSERT_THAT(BoundFooDecl
, NotNull());
4368 const ValueDecl
*BoundBarDecl
= findValueDecl(ASTCtx
, "BoundBar");
4369 ASSERT_THAT(BoundBarDecl
, NotNull());
4371 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
4372 ASSERT_THAT(BazDecl
, NotNull());
4374 // BindingDecls always map to references -- either lvalue or rvalue, so
4375 // we still need to skip here.
4376 const Value
*BoundFooValue
= Env1
.getValue(*BoundFooDecl
);
4377 ASSERT_THAT(BoundFooValue
, NotNull());
4378 EXPECT_TRUE(isa
<BoolValue
>(BoundFooValue
));
4380 const Value
*BoundBarValue
= Env1
.getValue(*BoundBarDecl
);
4381 ASSERT_THAT(BoundBarValue
, NotNull());
4382 EXPECT_TRUE(isa
<IntegerValue
>(BoundBarValue
));
4384 // Test that a `DeclRefExpr` to a `BindingDecl` works as expected.
4385 EXPECT_EQ(Env1
.getValue(*BazDecl
), BoundFooValue
);
4387 const Environment
&Env2
= getEnvironmentAtAnnotation(Results
, "p2");
4389 // Test that `BoundFooDecl` retains the value we expect, after the join.
4390 BoundFooValue
= Env2
.getValue(*BoundFooDecl
);
4391 EXPECT_EQ(Env2
.getValue(*BazDecl
), BoundFooValue
);
4395 TEST(TransferTest
, StructuredBindingAssignRefFromTupleLikeType
) {
4396 std::string Code
= R
"(
4399 template <class> struct tuple_size;
4400 template <std::size_t, class> struct tuple_element;
4401 template <class...> class tuple;
4404 template <class T, T v>
4405 struct size_helper { static const T value = v; };
4408 template <class... T>
4409 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {};
4411 template <std::size_t I, class... T>
4412 struct tuple_element<I, tuple<T...>> {
4413 using type = __type_pack_element<I, T...>;
4416 template <class...> class tuple {};
4418 template <std::size_t I, class... T>
4419 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
4422 std::tuple<bool, int> &getTuple();
4424 void target(bool B) {
4425 auto &[BoundFoo, BoundBar] = getTuple();
4427 // Include if-then-else to test interaction of `BindingDecl` with join.
4441 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4442 ASTContext
&ASTCtx
) {
4443 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p1", "p2"));
4444 const Environment
&Env1
= getEnvironmentAtAnnotation(Results
, "p1");
4446 const ValueDecl
*BoundFooDecl
= findValueDecl(ASTCtx
, "BoundFoo");
4447 ASSERT_THAT(BoundFooDecl
, NotNull());
4449 const ValueDecl
*BoundBarDecl
= findValueDecl(ASTCtx
, "BoundBar");
4450 ASSERT_THAT(BoundBarDecl
, NotNull());
4452 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
4453 ASSERT_THAT(BazDecl
, NotNull());
4455 const Value
*BoundFooValue
= Env1
.getValue(*BoundFooDecl
);
4456 ASSERT_THAT(BoundFooValue
, NotNull());
4457 EXPECT_TRUE(isa
<BoolValue
>(BoundFooValue
));
4459 const Value
*BoundBarValue
= Env1
.getValue(*BoundBarDecl
);
4460 ASSERT_THAT(BoundBarValue
, NotNull());
4461 EXPECT_TRUE(isa
<IntegerValue
>(BoundBarValue
));
4463 // Test that a `DeclRefExpr` to a `BindingDecl` (with reference type)
4464 // works as expected. We don't test aliasing properties of the
4465 // reference, because we don't model `std::get` and so have no way to
4466 // equate separate references into the tuple.
4467 EXPECT_EQ(Env1
.getValue(*BazDecl
), BoundFooValue
);
4469 const Environment
&Env2
= getEnvironmentAtAnnotation(Results
, "p2");
4471 // Test that `BoundFooDecl` retains the value we expect, after the join.
4472 BoundFooValue
= Env2
.getValue(*BoundFooDecl
);
4473 EXPECT_EQ(Env2
.getValue(*BazDecl
), BoundFooValue
);
4477 TEST(TransferTest
, BinaryOperatorComma
) {
4478 std::string Code
= R
"(
4479 void target(int Foo, int Bar) {
4480 int &Baz = (Foo, Bar);
4486 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4487 ASTContext
&ASTCtx
) {
4488 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4489 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4491 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4492 ASSERT_THAT(BarDecl
, NotNull());
4494 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
4495 ASSERT_THAT(BazDecl
, NotNull());
4497 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
4498 ASSERT_THAT(BarLoc
, NotNull());
4500 const StorageLocation
*BazLoc
= Env
.getStorageLocation(*BazDecl
);
4501 EXPECT_EQ(BazLoc
, BarLoc
);
4505 TEST(TransferTest
, IfStmtBranchExtendsFlowCondition
) {
4506 std::string Code
= R
"(
4507 void target(bool Foo) {
4519 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4520 ASTContext
&ASTCtx
) {
4521 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("if_then", "if_else"));
4522 const Environment
&ThenEnv
=
4523 getEnvironmentAtAnnotation(Results
, "if_then");
4524 const Environment
&ElseEnv
=
4525 getEnvironmentAtAnnotation(Results
, "if_else");
4527 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4528 ASSERT_THAT(FooDecl
, NotNull());
4530 auto &ThenFooVal
= getFormula(*FooDecl
, ThenEnv
);
4531 EXPECT_TRUE(ThenEnv
.proves(ThenFooVal
));
4533 auto &ElseFooVal
= getFormula(*FooDecl
, ElseEnv
);
4534 EXPECT_TRUE(ElseEnv
.proves(ElseEnv
.arena().makeNot(ElseFooVal
)));
4538 TEST(TransferTest
, WhileStmtBranchExtendsFlowCondition
) {
4539 std::string Code
= R
"(
4540 void target(bool Foo) {
4551 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4552 ASTContext
&ASTCtx
) {
4553 ASSERT_THAT(Results
.keys(),
4554 UnorderedElementsAre("loop_body", "after_loop"));
4555 const Environment
&LoopBodyEnv
=
4556 getEnvironmentAtAnnotation(Results
, "loop_body");
4557 const Environment
&AfterLoopEnv
=
4558 getEnvironmentAtAnnotation(Results
, "after_loop");
4560 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4561 ASSERT_THAT(FooDecl
, NotNull());
4563 auto &LoopBodyFooVal
= getFormula(*FooDecl
, LoopBodyEnv
);
4564 EXPECT_TRUE(LoopBodyEnv
.proves(LoopBodyFooVal
));
4566 auto &AfterLoopFooVal
= getFormula(*FooDecl
, AfterLoopEnv
);
4568 AfterLoopEnv
.proves(AfterLoopEnv
.arena().makeNot(AfterLoopFooVal
)));
4572 TEST(TransferTest
, DoWhileStmtBranchExtendsFlowCondition
) {
4573 std::string Code
= R
"(
4574 void target(bool Foo) {
4587 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4588 ASTContext
&ASTCtx
) {
4589 ASSERT_THAT(Results
.keys(),
4590 UnorderedElementsAre("loop_body", "after_loop"));
4591 const Environment
&LoopBodyEnv
=
4592 getEnvironmentAtAnnotation(Results
, "loop_body");
4593 const Environment
&AfterLoopEnv
=
4594 getEnvironmentAtAnnotation(Results
, "after_loop");
4595 auto &A
= AfterLoopEnv
.arena();
4597 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4598 ASSERT_THAT(FooDecl
, NotNull());
4600 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4601 ASSERT_THAT(BarDecl
, NotNull());
4603 auto &LoopBodyFooVal
= getFormula(*FooDecl
, LoopBodyEnv
);
4604 auto &LoopBodyBarVal
= getFormula(*BarDecl
, LoopBodyEnv
);
4606 LoopBodyEnv
.proves(A
.makeOr(LoopBodyBarVal
, LoopBodyFooVal
)));
4608 auto &AfterLoopFooVal
= getFormula(*FooDecl
, AfterLoopEnv
);
4609 auto &AfterLoopBarVal
= getFormula(*BarDecl
, AfterLoopEnv
);
4610 EXPECT_TRUE(AfterLoopEnv
.proves(A
.makeNot(AfterLoopFooVal
)));
4611 EXPECT_TRUE(AfterLoopEnv
.proves(A
.makeNot(AfterLoopBarVal
)));
4615 TEST(TransferTest
, ForStmtBranchExtendsFlowCondition
) {
4616 std::string Code
= R
"(
4617 void target(bool Foo) {
4628 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4629 ASTContext
&ASTCtx
) {
4630 ASSERT_THAT(Results
.keys(),
4631 UnorderedElementsAre("loop_body", "after_loop"));
4632 const Environment
&LoopBodyEnv
=
4633 getEnvironmentAtAnnotation(Results
, "loop_body");
4634 const Environment
&AfterLoopEnv
=
4635 getEnvironmentAtAnnotation(Results
, "after_loop");
4637 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4638 ASSERT_THAT(FooDecl
, NotNull());
4640 auto &LoopBodyFooVal
= getFormula(*FooDecl
, LoopBodyEnv
);
4641 EXPECT_TRUE(LoopBodyEnv
.proves(LoopBodyFooVal
));
4643 auto &AfterLoopFooVal
= getFormula(*FooDecl
, AfterLoopEnv
);
4645 AfterLoopEnv
.proves(AfterLoopEnv
.arena().makeNot(AfterLoopFooVal
)));
4649 TEST(TransferTest
, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition
) {
4650 std::string Code
= R
"(
4651 void target(bool Foo) {
4660 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4661 ASTContext
&ASTCtx
) {
4662 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("loop_body"));
4663 const Environment
&LoopBodyEnv
=
4664 getEnvironmentAtAnnotation(Results
, "loop_body");
4666 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4667 ASSERT_THAT(FooDecl
, NotNull());
4669 auto &LoopBodyFooVal
= getFormula(*FooDecl
, LoopBodyEnv
);
4670 EXPECT_FALSE(LoopBodyEnv
.proves(LoopBodyFooVal
));
4674 TEST(TransferTest
, ContextSensitiveOptionDisabled
) {
4675 std::string Code
= R
"(
4677 void SetBool(bool &Var) { Var = true; }
4680 bool Foo = GiveBool();
4687 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4688 ASTContext
&ASTCtx
) {
4689 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4690 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4692 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4693 ASSERT_THAT(FooDecl
, NotNull());
4695 auto &FooVal
= getFormula(*FooDecl
, Env
);
4696 EXPECT_FALSE(Env
.proves(FooVal
));
4697 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(FooVal
)));
4699 {BuiltinOptions
{/*.ContextSensitiveOpts=*/std::nullopt
}});
4702 TEST(TransferTest
, ContextSensitiveReturnReference
) {
4703 std::string Code
= R
"(
4705 S& target(bool b, S &s) {
4712 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4713 ASTContext
&ASTCtx
) {
4714 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4716 const ValueDecl
*SDecl
= findValueDecl(ASTCtx
, "s");
4717 ASSERT_THAT(SDecl
, NotNull());
4719 auto *SLoc
= Env
.getStorageLocation(*SDecl
);
4720 ASSERT_THAT(SLoc
, NotNull());
4722 ASSERT_THAT(Env
.getReturnStorageLocation(), Eq(SLoc
));
4724 {BuiltinOptions
{ContextSensitiveOptions
{}}});
4727 // This test is a regression test, based on a real crash.
4728 TEST(TransferTest
, ContextSensitiveReturnReferenceWithConditionalOperator
) {
4729 std::string Code
= R
"(
4731 S& target(bool b, S &s) {
4738 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4739 ASTContext
&ASTCtx
) {
4740 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4741 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4743 const ValueDecl
*SDecl
= findValueDecl(ASTCtx
, "s");
4744 ASSERT_THAT(SDecl
, NotNull());
4746 auto *SLoc
= Env
.getStorageLocation(*SDecl
);
4747 ASSERT_THAT(SLoc
, NotNull());
4748 EXPECT_THAT(Env
.getValue(*SLoc
), NotNull());
4750 auto *Loc
= Env
.getReturnStorageLocation();
4751 ASSERT_THAT(Loc
, NotNull());
4752 EXPECT_THAT(Env
.getValue(*Loc
), NotNull());
4754 // TODO: We would really like to make this stronger assertion, but that
4755 // doesn't work because we don't propagate values correctly through
4756 // the conditional operator yet.
4757 // ASSERT_THAT(Loc, Eq(SLoc));
4759 {BuiltinOptions
{ContextSensitiveOptions
{}}});
4762 TEST(TransferTest
, ContextSensitiveReturnOneOfTwoReferences
) {
4763 std::string Code
= R
"(
4765 S &callee(bool b, S &s1_parm, S &s2_parm) {
4771 void target(bool b) {
4776 S &return_dont_know = callee(b, s1, s2);
4782 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4783 ASTContext
&ASTCtx
) {
4784 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4786 const ValueDecl
*S1
= findValueDecl(ASTCtx
, "s1");
4787 ASSERT_THAT(S1
, NotNull());
4788 const ValueDecl
*S2
= findValueDecl(ASTCtx
, "s2");
4789 ASSERT_THAT(S2
, NotNull());
4790 const ValueDecl
*ReturnS1
= findValueDecl(ASTCtx
, "return_s1");
4791 ASSERT_THAT(ReturnS1
, NotNull());
4792 const ValueDecl
*ReturnS2
= findValueDecl(ASTCtx
, "return_s2");
4793 ASSERT_THAT(ReturnS2
, NotNull());
4794 const ValueDecl
*ReturnDontKnow
=
4795 findValueDecl(ASTCtx
, "return_dont_know");
4796 ASSERT_THAT(ReturnDontKnow
, NotNull());
4798 StorageLocation
*S1Loc
= Env
.getStorageLocation(*S1
);
4799 StorageLocation
*S2Loc
= Env
.getStorageLocation(*S2
);
4801 EXPECT_THAT(Env
.getStorageLocation(*ReturnS1
), Eq(S1Loc
));
4802 EXPECT_THAT(Env
.getStorageLocation(*ReturnS2
), Eq(S2Loc
));
4804 // In the case where we don't have a consistent storage location for
4805 // the return value, the framework creates a new storage location, which
4806 // should be different from the storage locations of `s1` and `s2`.
4807 EXPECT_THAT(Env
.getStorageLocation(*ReturnDontKnow
), Ne(S1Loc
));
4808 EXPECT_THAT(Env
.getStorageLocation(*ReturnDontKnow
), Ne(S2Loc
));
4810 {BuiltinOptions
{ContextSensitiveOptions
{}}});
4813 TEST(TransferTest
, ContextSensitiveDepthZero
) {
4814 std::string Code
= R
"(
4816 void SetBool(bool &Var) { Var = true; }
4819 bool Foo = GiveBool();
4826 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4827 ASTContext
&ASTCtx
) {
4828 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4829 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4831 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4832 ASSERT_THAT(FooDecl
, NotNull());
4834 auto &FooVal
= getFormula(*FooDecl
, Env
);
4835 EXPECT_FALSE(Env
.proves(FooVal
));
4836 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(FooVal
)));
4838 {BuiltinOptions
{ContextSensitiveOptions
{/*.Depth=*/0}}});
4841 TEST(TransferTest
, ContextSensitiveSetTrue
) {
4842 std::string Code
= R
"(
4844 void SetBool(bool &Var) { Var = true; }
4847 bool Foo = GiveBool();
4854 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4855 ASTContext
&ASTCtx
) {
4856 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4857 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4859 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4860 ASSERT_THAT(FooDecl
, NotNull());
4862 auto &FooVal
= getFormula(*FooDecl
, Env
);
4863 EXPECT_TRUE(Env
.proves(FooVal
));
4865 {BuiltinOptions
{ContextSensitiveOptions
{}}});
4868 TEST(TransferTest
, ContextSensitiveSetFalse
) {
4869 std::string Code
= R
"(
4871 void SetBool(bool &Var) { Var = false; }
4874 bool Foo = GiveBool();
4881 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4882 ASTContext
&ASTCtx
) {
4883 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4884 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4886 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4887 ASSERT_THAT(FooDecl
, NotNull());
4889 auto &FooVal
= getFormula(*FooDecl
, Env
);
4890 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(FooVal
)));
4892 {BuiltinOptions
{ContextSensitiveOptions
{}}});
4895 TEST(TransferTest
, ContextSensitiveSetBothTrueAndFalse
) {
4896 std::string Code
= R
"(
4898 void SetBool(bool &Var, bool Val) { Var = Val; }
4901 bool Foo = GiveBool();
4902 bool Bar = GiveBool();
4904 SetBool(Bar, false);
4910 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4911 ASTContext
&ASTCtx
) {
4912 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4913 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4914 auto &A
= Env
.arena();
4916 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4917 ASSERT_THAT(FooDecl
, NotNull());
4919 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4920 ASSERT_THAT(BarDecl
, NotNull());
4922 auto &FooVal
= getFormula(*FooDecl
, Env
);
4923 EXPECT_TRUE(Env
.proves(FooVal
));
4924 EXPECT_FALSE(Env
.proves(A
.makeNot(FooVal
)));
4926 auto &BarVal
= getFormula(*BarDecl
, Env
);
4927 EXPECT_FALSE(Env
.proves(BarVal
));
4928 EXPECT_TRUE(Env
.proves(A
.makeNot(BarVal
)));
4930 {BuiltinOptions
{ContextSensitiveOptions
{}}});
4933 TEST(TransferTest
, ContextSensitiveSetTwoLayersDepthOne
) {
4934 std::string Code
= R
"(
4936 void SetBool1(bool &Var) { Var = true; }
4937 void SetBool2(bool &Var) { SetBool1(Var); }
4940 bool Foo = GiveBool();
4947 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4948 ASTContext
&ASTCtx
) {
4949 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4950 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4952 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4953 ASSERT_THAT(FooDecl
, NotNull());
4955 auto &FooVal
= getFormula(*FooDecl
, Env
);
4956 EXPECT_FALSE(Env
.proves(FooVal
));
4957 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(FooVal
)));
4959 {BuiltinOptions
{ContextSensitiveOptions
{/*.Depth=*/1}}});
4962 TEST(TransferTest
, ContextSensitiveSetTwoLayersDepthTwo
) {
4963 std::string Code
= R
"(
4965 void SetBool1(bool &Var) { Var = true; }
4966 void SetBool2(bool &Var) { SetBool1(Var); }
4969 bool Foo = GiveBool();
4976 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4977 ASTContext
&ASTCtx
) {
4978 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4979 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4981 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4982 ASSERT_THAT(FooDecl
, NotNull());
4984 auto &FooVal
= getFormula(*FooDecl
, Env
);
4985 EXPECT_TRUE(Env
.proves(FooVal
));
4987 {BuiltinOptions
{ContextSensitiveOptions
{/*.Depth=*/2}}});
4990 TEST(TransferTest
, ContextSensitiveSetThreeLayersDepthTwo
) {
4991 std::string Code
= R
"(
4993 void SetBool1(bool &Var) { Var = true; }
4994 void SetBool2(bool &Var) { SetBool1(Var); }
4995 void SetBool3(bool &Var) { SetBool2(Var); }
4998 bool Foo = GiveBool();
5005 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5006 ASTContext
&ASTCtx
) {
5007 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5008 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5010 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5011 ASSERT_THAT(FooDecl
, NotNull());
5013 auto &FooVal
= getFormula(*FooDecl
, Env
);
5014 EXPECT_FALSE(Env
.proves(FooVal
));
5015 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(FooVal
)));
5017 {BuiltinOptions
{ContextSensitiveOptions
{/*.Depth=*/2}}});
5020 TEST(TransferTest
, ContextSensitiveSetThreeLayersDepthThree
) {
5021 std::string Code
= R
"(
5023 void SetBool1(bool &Var) { Var = true; }
5024 void SetBool2(bool &Var) { SetBool1(Var); }
5025 void SetBool3(bool &Var) { SetBool2(Var); }
5028 bool Foo = GiveBool();
5035 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5036 ASTContext
&ASTCtx
) {
5037 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5038 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5040 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5041 ASSERT_THAT(FooDecl
, NotNull());
5043 auto &FooVal
= getFormula(*FooDecl
, Env
);
5044 EXPECT_TRUE(Env
.proves(FooVal
));
5046 {BuiltinOptions
{ContextSensitiveOptions
{/*.Depth=*/3}}});
5049 TEST(TransferTest
, ContextSensitiveMutualRecursion
) {
5050 std::string Code
= R
"(
5051 bool Pong(bool X, bool Y);
5053 bool Ping(bool X, bool Y) {
5061 bool Pong(bool X, bool Y) {
5070 bool Foo = Ping(false, false);
5076 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5077 ASTContext
&ASTCtx
) {
5078 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5079 // The analysis doesn't crash...
5080 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5082 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5083 ASSERT_THAT(FooDecl
, NotNull());
5085 auto &FooVal
= getFormula(*FooDecl
, Env
);
5086 // ... but it also can't prove anything here.
5087 EXPECT_FALSE(Env
.proves(FooVal
));
5088 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(FooVal
)));
5090 {BuiltinOptions
{ContextSensitiveOptions
{/*.Depth=*/4}}});
5093 TEST(TransferTest
, ContextSensitiveSetMultipleLines
) {
5094 std::string Code
= R
"(
5095 void SetBools(bool &Var1, bool &Var2) {
5109 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5110 ASTContext
&ASTCtx
) {
5111 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5112 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5114 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5115 ASSERT_THAT(FooDecl
, NotNull());
5117 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
5118 ASSERT_THAT(BarDecl
, NotNull());
5120 auto &FooVal
= getFormula(*FooDecl
, Env
);
5121 EXPECT_TRUE(Env
.proves(FooVal
));
5122 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(FooVal
)));
5124 auto &BarVal
= getFormula(*BarDecl
, Env
);
5125 EXPECT_FALSE(Env
.proves(BarVal
));
5126 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(BarVal
)));
5128 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5131 TEST(TransferTest
, ContextSensitiveSetMultipleBlocks
) {
5132 std::string Code
= R
"(
5133 void IfCond(bool Cond, bool &Then, bool &Else) {
5145 IfCond(Foo, Bar, Baz);
5151 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5152 ASTContext
&ASTCtx
) {
5153 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5154 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5156 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
5157 ASSERT_THAT(BarDecl
, NotNull());
5159 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
5160 ASSERT_THAT(BazDecl
, NotNull());
5162 auto &BarVal
= getFormula(*BarDecl
, Env
);
5163 EXPECT_FALSE(Env
.proves(BarVal
));
5164 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(BarVal
)));
5166 auto &BazVal
= getFormula(*BazDecl
, Env
);
5167 EXPECT_TRUE(Env
.proves(BazVal
));
5168 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(BazVal
)));
5170 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5173 TEST(TransferTest
, ContextSensitiveReturnVoid
) {
5174 std::string Code
= R
"(
5175 void Noop() { return; }
5184 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5185 ASTContext
&ASTCtx
) {
5186 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5187 // This just tests that the analysis doesn't crash.
5189 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5192 TEST(TransferTest
, ContextSensitiveReturnTrue
) {
5193 std::string Code
= R
"(
5194 bool GiveBool() { return true; }
5197 bool Foo = GiveBool();
5203 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5204 ASTContext
&ASTCtx
) {
5205 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5206 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5208 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5209 ASSERT_THAT(FooDecl
, NotNull());
5211 auto &FooVal
= getFormula(*FooDecl
, Env
);
5212 EXPECT_TRUE(Env
.proves(FooVal
));
5214 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5217 TEST(TransferTest
, ContextSensitiveReturnFalse
) {
5218 std::string Code
= R
"(
5219 bool GiveBool() { return false; }
5222 bool Foo = GiveBool();
5228 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5229 ASTContext
&ASTCtx
) {
5230 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5231 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5233 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5234 ASSERT_THAT(FooDecl
, NotNull());
5236 auto &FooVal
= getFormula(*FooDecl
, Env
);
5237 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(FooVal
)));
5239 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5242 TEST(TransferTest
, ContextSensitiveReturnArg
) {
5243 std::string Code
= R
"(
5245 bool GiveBack(bool Arg) { return Arg; }
5248 bool Foo = GiveBool();
5249 bool Bar = GiveBack(Foo);
5250 bool Baz = Foo == Bar;
5256 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5257 ASTContext
&ASTCtx
) {
5258 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5259 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5261 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
5262 ASSERT_THAT(BazDecl
, NotNull());
5264 auto &BazVal
= getFormula(*BazDecl
, Env
);
5265 EXPECT_TRUE(Env
.proves(BazVal
));
5267 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5270 TEST(TransferTest
, ContextSensitiveReturnInt
) {
5271 std::string Code
= R
"(
5272 int identity(int x) { return x; }
5275 int y = identity(42);
5281 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5282 ASTContext
&ASTCtx
) {
5283 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5284 // This just tests that the analysis doesn't crash.
5286 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5289 TEST(TransferTest
, ContextSensitiveMethodLiteral
) {
5290 std::string Code
= R
"(
5293 bool giveBool() { return true; }
5298 bool Foo = MyObj.giveBool();
5304 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5305 ASTContext
&ASTCtx
) {
5306 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5307 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5309 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5310 ASSERT_THAT(FooDecl
, NotNull());
5312 auto &FooVal
= getFormula(*FooDecl
, Env
);
5313 EXPECT_TRUE(Env
.proves(FooVal
));
5315 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5318 TEST(TransferTest
, ContextSensitiveMethodGetter
) {
5319 std::string Code
= R
"(
5322 bool getField() { return Field; }
5330 bool Foo = MyObj.getField();
5336 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5337 ASTContext
&ASTCtx
) {
5338 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5339 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5341 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5342 ASSERT_THAT(FooDecl
, NotNull());
5344 auto &FooVal
= getFormula(*FooDecl
, Env
);
5345 EXPECT_TRUE(Env
.proves(FooVal
));
5347 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5350 TEST(TransferTest
, ContextSensitiveMethodSetter
) {
5351 std::string Code
= R
"(
5354 void setField(bool Val) { Field = Val; }
5361 MyObj.setField(true);
5362 bool Foo = MyObj.Field;
5368 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5369 ASTContext
&ASTCtx
) {
5370 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5371 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5373 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5374 ASSERT_THAT(FooDecl
, NotNull());
5376 auto &FooVal
= getFormula(*FooDecl
, Env
);
5377 EXPECT_TRUE(Env
.proves(FooVal
));
5379 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5382 TEST(TransferTest
, ContextSensitiveMethodGetterAndSetter
) {
5383 std::string Code
= R
"(
5386 bool getField() { return Field; }
5387 void setField(bool Val) { Field = Val; }
5395 MyObj.setField(true);
5396 bool Foo = MyObj.getField();
5402 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5403 ASTContext
&ASTCtx
) {
5404 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5405 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5407 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5408 ASSERT_THAT(FooDecl
, NotNull());
5410 auto &FooVal
= getFormula(*FooDecl
, Env
);
5411 EXPECT_TRUE(Env
.proves(FooVal
));
5413 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5417 TEST(TransferTest
, ContextSensitiveMethodTwoLayersVoid
) {
5418 std::string Code
= R
"(
5421 void Inner() { MyField = true; }
5422 void Outer() { Inner(); }
5430 bool Foo = MyObj.MyField;
5436 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5437 ASTContext
&ASTCtx
) {
5438 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5440 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5442 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5443 ASSERT_THAT(FooDecl
, NotNull());
5445 auto &FooVal
= getFormula(*FooDecl
, Env
);
5446 EXPECT_TRUE(Env
.proves(FooVal
));
5448 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5451 TEST(TransferTest
, ContextSensitiveMethodTwoLayersReturn
) {
5452 std::string Code
= R
"(
5455 bool Inner() { return MyField; }
5456 bool Outer() { return Inner(); }
5463 MyObj.MyField = true;
5464 bool Foo = MyObj.Outer();
5470 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5471 ASTContext
&ASTCtx
) {
5472 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5474 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5476 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5477 ASSERT_THAT(FooDecl
, NotNull());
5479 auto &FooVal
= getFormula(*FooDecl
, Env
);
5480 EXPECT_TRUE(Env
.proves(FooVal
));
5482 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5485 TEST(TransferTest
, ContextSensitiveConstructorBody
) {
5486 std::string Code
= R
"(
5489 MyClass() { MyField = true; }
5496 bool Foo = MyObj.MyField;
5502 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5503 ASTContext
&ASTCtx
) {
5504 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5505 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5507 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5508 ASSERT_THAT(FooDecl
, NotNull());
5510 auto &FooVal
= getFormula(*FooDecl
, Env
);
5511 EXPECT_TRUE(Env
.proves(FooVal
));
5513 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5516 TEST(TransferTest
, ContextSensitiveConstructorInitializer
) {
5517 std::string Code
= R
"(
5520 MyClass() : MyField(true) {}
5527 bool Foo = MyObj.MyField;
5533 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5534 ASTContext
&ASTCtx
) {
5535 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5536 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5538 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5539 ASSERT_THAT(FooDecl
, NotNull());
5541 auto &FooVal
= getFormula(*FooDecl
, Env
);
5542 EXPECT_TRUE(Env
.proves(FooVal
));
5544 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5547 TEST(TransferTest
, ContextSensitiveConstructorDefault
) {
5548 std::string Code
= R
"(
5551 MyClass() = default;
5553 bool MyField = true;
5558 bool Foo = MyObj.MyField;
5564 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5565 ASTContext
&ASTCtx
) {
5566 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5567 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5569 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5570 ASSERT_THAT(FooDecl
, NotNull());
5572 auto &FooVal
= getFormula(*FooDecl
, Env
);
5573 EXPECT_TRUE(Env
.proves(FooVal
));
5575 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5578 TEST(TransferTest
, ContextSensitiveSelfReferentialClass
) {
5579 // Test that the `this` pointer seen in the constructor has the same value
5580 // as the address of the variable the object is constructed into.
5581 std::string Code
= R
"(
5584 MyClass() : Self(this) {}
5590 MyClass *SelfPtr = MyObj.Self;
5596 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5597 ASTContext
&ASTCtx
) {
5598 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5600 const ValueDecl
*MyObjDecl
= findValueDecl(ASTCtx
, "MyObj");
5601 ASSERT_THAT(MyObjDecl
, NotNull());
5603 const ValueDecl
*SelfDecl
= findValueDecl(ASTCtx
, "SelfPtr");
5604 ASSERT_THAT(SelfDecl
, NotNull());
5606 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5607 auto &SelfVal
= *cast
<PointerValue
>(Env
.getValue(*SelfDecl
));
5608 EXPECT_EQ(Env
.getStorageLocation(*MyObjDecl
), &SelfVal
.getPointeeLoc());
5610 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5613 TEST(TransferTest
, UnnamedBitfieldInitializer
) {
5614 std::string Code
= R
"(
5630 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5631 ASTContext
&ASTCtx
) {
5632 // This doesn't need a body because this test was crashing the framework
5633 // before handling correctly Unnamed bitfields in `InitListExpr`.
5637 // Repro for a crash that used to occur with chained short-circuiting logical
5639 TEST(TransferTest
, ChainedLogicalOps
) {
5640 std::string Code
= R
"(
5642 bool b = true || false || false || false;
5649 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5650 ASTContext
&ASTCtx
) {
5651 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5652 auto &B
= getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "b").formula();
5653 EXPECT_TRUE(Env
.proves(B
));
5657 // Repro for a crash that used to occur when we call a `noreturn` function
5658 // within one of the operands of a `&&` or `||` operator.
5659 TEST(TransferTest
, NoReturnFunctionInsideShortCircuitedBooleanOp
) {
5660 std::string Code
= R
"(
5661 __attribute__((noreturn)) int doesnt_return();
5662 bool some_condition();
5663 void target(bool b1, bool b2) {
5664 // Neither of these should crash. In addition, if we don't terminate the
5665 // program, we know that the operators need to trigger the short-circuit
5666 // logic, so `NoreturnOnRhsOfAnd` will be false and `NoreturnOnRhsOfOr`
5668 bool NoreturnOnRhsOfAnd = b1 && doesnt_return() > 0;
5669 bool NoreturnOnRhsOfOr = b2 || doesnt_return() > 0;
5671 // Calling a `noreturn` function on the LHS of an `&&` or `||` makes the
5672 // entire expression unreachable. So we know that in both of the following
5673 // cases, if `target()` terminates, the `else` branch was taken.
5674 bool NoreturnOnLhsMakesAndUnreachable = false;
5675 if (some_condition())
5676 doesnt_return() > 0 && some_condition();
5678 NoreturnOnLhsMakesAndUnreachable = true;
5680 bool NoreturnOnLhsMakesOrUnreachable = false;
5681 if (some_condition())
5682 doesnt_return() > 0 || some_condition();
5684 NoreturnOnLhsMakesOrUnreachable = true;
5691 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5692 ASTContext
&ASTCtx
) {
5693 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5694 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5695 auto &A
= Env
.arena();
5697 // Check that [[p]] is reachable with a non-false flow condition.
5698 EXPECT_FALSE(Env
.proves(A
.makeLiteral(false)));
5700 auto &B1
= getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "b1").formula();
5701 EXPECT_TRUE(Env
.proves(A
.makeNot(B1
)));
5703 auto &NoreturnOnRhsOfAnd
=
5704 getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "NoreturnOnRhsOfAnd").formula();
5705 EXPECT_TRUE(Env
.proves(A
.makeNot(NoreturnOnRhsOfAnd
)));
5707 auto &B2
= getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "b2").formula();
5708 EXPECT_TRUE(Env
.proves(B2
));
5710 auto &NoreturnOnRhsOfOr
=
5711 getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "NoreturnOnRhsOfOr")
5713 EXPECT_TRUE(Env
.proves(NoreturnOnRhsOfOr
));
5715 auto &NoreturnOnLhsMakesAndUnreachable
= getValueForDecl
<BoolValue
>(
5716 ASTCtx
, Env
, "NoreturnOnLhsMakesAndUnreachable").formula();
5717 EXPECT_TRUE(Env
.proves(NoreturnOnLhsMakesAndUnreachable
));
5719 auto &NoreturnOnLhsMakesOrUnreachable
= getValueForDecl
<BoolValue
>(
5720 ASTCtx
, Env
, "NoreturnOnLhsMakesOrUnreachable").formula();
5721 EXPECT_TRUE(Env
.proves(NoreturnOnLhsMakesOrUnreachable
));
5725 TEST(TransferTest
, NewExpressions
) {
5726 std::string Code
= R
"(
5728 int *p = new int(42);
5734 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5735 ASTContext
&ASTCtx
) {
5736 const Environment
&Env
=
5737 getEnvironmentAtAnnotation(Results
, "after_new");
5739 auto &P
= getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "p");
5741 EXPECT_THAT(Env
.getValue(P
.getPointeeLoc()), NotNull());
5745 TEST(TransferTest
, NewExpressions_Structs
) {
5746 std::string Code
= R
"(
5756 Outer *p = new Outer;
5757 // Access the fields to make sure the analysis actually generates children
5758 // for them in the `RecordStorageLocation` and `RecordValue`.
5759 p->OuterField.InnerField;
5765 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5766 ASTContext
&ASTCtx
) {
5767 const Environment
&Env
=
5768 getEnvironmentAtAnnotation(Results
, "after_new");
5770 const ValueDecl
*OuterField
= findValueDecl(ASTCtx
, "OuterField");
5771 const ValueDecl
*InnerField
= findValueDecl(ASTCtx
, "InnerField");
5773 auto &P
= getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "p");
5775 auto &OuterLoc
= cast
<RecordStorageLocation
>(P
.getPointeeLoc());
5776 auto &OuterFieldLoc
=
5777 *cast
<RecordStorageLocation
>(OuterLoc
.getChild(*OuterField
));
5778 auto &InnerFieldLoc
= *OuterFieldLoc
.getChild(*InnerField
);
5780 // Values for the struct and all fields exist after the new.
5781 EXPECT_THAT(Env
.getValue(OuterLoc
), NotNull());
5782 EXPECT_THAT(Env
.getValue(OuterFieldLoc
), NotNull());
5783 EXPECT_THAT(Env
.getValue(InnerFieldLoc
), NotNull());
5787 TEST(TransferTest
, FunctionToPointerDecayHasValue
) {
5788 std::string Code
= R
"(
5789 struct A { static void static_member_func(); };
5791 // To check that we're treating function-to-pointer decay correctly,
5792 // create two pointers, then verify they refer to the same storage
5794 // We need to do the test this way because even if an initializer (in this
5795 // case, the function-to-pointer decay) does not create a value, we still
5796 // create a value for the variable.
5797 void (*non_member_p1)() = target;
5798 void (*non_member_p2)() = target;
5800 // Do the same thing but for a static member function.
5801 void (*member_p1)() = A::static_member_func;
5802 void (*member_p2)() = A::static_member_func;
5808 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5809 ASTContext
&ASTCtx
) {
5810 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5813 getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "non_member_p1");
5815 getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "non_member_p2");
5816 EXPECT_EQ(&NonMemberP1
.getPointeeLoc(), &NonMemberP2
.getPointeeLoc());
5819 getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "member_p1");
5821 getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "member_p2");
5822 EXPECT_EQ(&MemberP1
.getPointeeLoc(), &MemberP2
.getPointeeLoc());
5826 // Check that a builtin function is not associated with a value. (It's only
5827 // possible to call builtin functions directly, not take their address.)
5828 TEST(TransferTest
, BuiltinFunctionModeled
) {
5829 std::string Code
= R
"(
5831 __builtin_expect(0, 0);
5837 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5838 ASTContext
&ASTCtx
) {
5839 using ast_matchers::selectFirst
;
5840 using ast_matchers::match
;
5841 using ast_matchers::traverse
;
5842 using ast_matchers::implicitCastExpr
;
5843 using ast_matchers::hasCastKind
;
5845 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5847 auto *ImplicitCast
= selectFirst
<ImplicitCastExpr
>(
5849 match(traverse(TK_AsIs
,
5850 implicitCastExpr(hasCastKind(CK_BuiltinFnToFnPtr
))
5851 .bind("implicit_cast")),
5854 ASSERT_THAT(ImplicitCast
, NotNull());
5855 EXPECT_THAT(Env
.getValue(*ImplicitCast
), IsNull());
5859 // Check that a callee of a member operator call is modeled as a `PointerValue`.
5860 // Member operator calls are unusual in that their callee is a pointer that
5861 // stems from a `FunctionToPointerDecay`. In calls to non-operator non-static
5862 // member functions, the callee is a `MemberExpr` (which does not have pointer
5864 // We want to make sure that we produce a pointer value for the callee in this
5865 // specific scenario and that its storage location is durable (for convergence).
5866 TEST(TransferTest
, MemberOperatorCallModelsPointerForCallee
) {
5867 std::string Code
= R
"(
5869 bool operator!=(S s);
5880 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5881 ASTContext
&ASTCtx
) {
5882 using ast_matchers::selectFirst
;
5883 using ast_matchers::match
;
5884 using ast_matchers::traverse
;
5885 using ast_matchers::cxxOperatorCallExpr
;
5887 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5889 auto Matches
= match(
5890 traverse(TK_AsIs
, cxxOperatorCallExpr().bind("call")), ASTCtx
);
5892 ASSERT_EQ(Matches
.size(), 2UL);
5894 auto *Call1
= Matches
[0].getNodeAs
<CXXOperatorCallExpr
>("call");
5895 auto *Call2
= Matches
[1].getNodeAs
<CXXOperatorCallExpr
>("call");
5897 ASSERT_THAT(Call1
, NotNull());
5898 ASSERT_THAT(Call2
, NotNull());
5900 EXPECT_EQ(cast
<ImplicitCastExpr
>(Call1
->getCallee())->getCastKind(),
5901 CK_FunctionToPointerDecay
);
5902 EXPECT_EQ(cast
<ImplicitCastExpr
>(Call2
->getCallee())->getCastKind(),
5903 CK_FunctionToPointerDecay
);
5905 auto *Ptr1
= cast
<PointerValue
>(Env
.getValue(*Call1
->getCallee()));
5906 auto *Ptr2
= cast
<PointerValue
>(Env
.getValue(*Call2
->getCallee()));
5908 ASSERT_EQ(&Ptr1
->getPointeeLoc(), &Ptr2
->getPointeeLoc());
5912 // Check that fields of anonymous records are modeled.
5913 TEST(TransferTest
, AnonymousStruct
) {
5914 std::string Code
= R
"(
5928 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5929 ASTContext
&ASTCtx
) {
5930 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5931 const ValueDecl
*SDecl
= findValueDecl(ASTCtx
, "s");
5932 const ValueDecl
*BDecl
= findValueDecl(ASTCtx
, "b");
5933 const IndirectFieldDecl
*IndirectField
=
5934 findIndirectFieldDecl(ASTCtx
, "b");
5936 auto *S
= cast
<RecordStorageLocation
>(Env
.getStorageLocation(*SDecl
));
5937 auto &AnonStruct
= *cast
<RecordStorageLocation
>(
5938 S
->getChild(*cast
<ValueDecl
>(IndirectField
->chain().front())));
5940 auto *B
= cast
<BoolValue
>(getFieldValue(&AnonStruct
, *BDecl
, Env
));
5941 ASSERT_TRUE(Env
.proves(B
->formula()));
5945 TEST(TransferTest
, AnonymousStructWithInitializer
) {
5946 std::string Code
= R
"(
5959 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5960 ASTContext
&ASTCtx
) {
5961 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5962 const ValueDecl
*BDecl
= findValueDecl(ASTCtx
, "b");
5963 const IndirectFieldDecl
*IndirectField
=
5964 findIndirectFieldDecl(ASTCtx
, "b");
5967 cast
<RecordStorageLocation
>(Env
.getThisPointeeStorageLocation());
5968 auto &AnonStruct
= *cast
<RecordStorageLocation
>(ThisLoc
->getChild(
5969 *cast
<ValueDecl
>(IndirectField
->chain().front())));
5971 auto *B
= cast
<BoolValue
>(getFieldValue(&AnonStruct
, *BDecl
, Env
));
5972 ASSERT_TRUE(Env
.proves(B
->formula()));
5976 TEST(TransferTest
, AnonymousStructWithReferenceField
) {
5977 std::string Code
= R
"(
5991 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5992 ASTContext
&ASTCtx
) {
5993 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5994 const ValueDecl
*GlobalIDecl
= findValueDecl(ASTCtx
, "global_i");
5995 const ValueDecl
*IDecl
= findValueDecl(ASTCtx
, "i");
5996 const IndirectFieldDecl
*IndirectField
=
5997 findIndirectFieldDecl(ASTCtx
, "i");
6000 cast
<RecordStorageLocation
>(Env
.getThisPointeeStorageLocation());
6001 auto &AnonStruct
= *cast
<RecordStorageLocation
>(ThisLoc
->getChild(
6002 *cast
<ValueDecl
>(IndirectField
->chain().front())));
6004 ASSERT_EQ(AnonStruct
.getChild(*IDecl
),
6005 Env
.getStorageLocation(*GlobalIDecl
));
6009 TEST(TransferTest
, EvaluateBlockWithUnreachablePreds
) {
6010 // This is a crash repro.
6011 // `false` block may not have been processed when we try to evaluate the `||`
6012 // after visiting `true`, because it is not necessary (and therefore the edge
6013 // is marked unreachable). Trying to get the analysis state via
6014 // `getEnvironment` for the subexpression still should not crash.
6015 std::string Code
= R
"(
6017 if ((i < 0 && true) || false) {
6025 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6026 ASTContext
&ASTCtx
) {});
6029 TEST(TransferTest
, LambdaCaptureByCopy
) {
6030 std::string Code
= R
"(
6031 void target(int Foo, int Bar) {
6038 runDataflowOnLambda(
6040 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6041 ASTContext
&ASTCtx
) {
6042 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6043 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6045 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6046 ASSERT_THAT(FooDecl
, NotNull());
6048 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
6049 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
6051 const Value
*FooVal
= Env
.getValue(*FooLoc
);
6052 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
6054 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
6055 ASSERT_THAT(BarDecl
, NotNull());
6057 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
6058 EXPECT_THAT(BarLoc
, IsNull());
6062 TEST(TransferTest
, LambdaCaptureByReference
) {
6063 std::string Code
= R
"(
6064 void target(int Foo, int Bar) {
6071 runDataflowOnLambda(
6073 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6074 ASTContext
&ASTCtx
) {
6075 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6076 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6078 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6079 ASSERT_THAT(FooDecl
, NotNull());
6081 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
6082 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
6084 const Value
*FooVal
= Env
.getValue(*FooLoc
);
6085 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
6087 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
6088 ASSERT_THAT(BarDecl
, NotNull());
6090 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
6091 EXPECT_THAT(BarLoc
, IsNull());
6095 TEST(TransferTest
, LambdaCaptureWithInitializer
) {
6096 std::string Code
= R
"(
6097 void target(int Bar) {
6104 runDataflowOnLambda(
6106 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6107 ASTContext
&ASTCtx
) {
6108 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6109 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6111 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6112 ASSERT_THAT(FooDecl
, NotNull());
6114 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
6115 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
6117 const Value
*FooVal
= Env
.getValue(*FooLoc
);
6118 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
6120 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
6121 ASSERT_THAT(BarDecl
, NotNull());
6123 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
6124 EXPECT_THAT(BarLoc
, IsNull());
6128 TEST(TransferTest
, LambdaCaptureByCopyImplicit
) {
6129 std::string Code
= R
"(
6130 void target(int Foo, int Bar) {
6137 runDataflowOnLambda(
6139 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6140 ASTContext
&ASTCtx
) {
6141 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6142 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6144 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6145 ASSERT_THAT(FooDecl
, NotNull());
6147 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
6148 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
6150 const Value
*FooVal
= Env
.getValue(*FooLoc
);
6151 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
6153 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
6154 ASSERT_THAT(BarDecl
, NotNull());
6156 // There is no storage location for `Bar` because it isn't used in the
6157 // body of the lambda.
6158 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
6159 EXPECT_THAT(BarLoc
, IsNull());
6163 TEST(TransferTest
, LambdaCaptureByReferenceImplicit
) {
6164 std::string Code
= R
"(
6165 void target(int Foo, int Bar) {
6172 runDataflowOnLambda(
6174 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6175 ASTContext
&ASTCtx
) {
6176 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6177 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6179 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6180 ASSERT_THAT(FooDecl
, NotNull());
6182 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
6183 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
6185 const Value
*FooVal
= Env
.getValue(*FooLoc
);
6186 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
6188 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
6189 ASSERT_THAT(BarDecl
, NotNull());
6191 // There is no storage location for `Bar` because it isn't used in the
6192 // body of the lambda.
6193 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
6194 EXPECT_THAT(BarLoc
, IsNull());
6198 TEST(TransferTest
, LambdaCaptureThis
) {
6199 std::string Code
= R
"(
6211 runDataflowOnLambda(
6213 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6214 ASTContext
&ASTCtx
) {
6215 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6216 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6218 const RecordStorageLocation
*ThisPointeeLoc
=
6219 Env
.getThisPointeeStorageLocation();
6220 ASSERT_THAT(ThisPointeeLoc
, NotNull());
6222 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6223 ASSERT_THAT(FooDecl
, NotNull());
6225 const StorageLocation
*FooLoc
= ThisPointeeLoc
->getChild(*FooDecl
);
6226 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
6228 const Value
*FooVal
= Env
.getValue(*FooLoc
);
6229 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
6233 TEST(TransferTest
, DifferentReferenceLocInJoin
) {
6234 // This test triggers a case where the storage location for a reference-type
6235 // variable is different for two states being joined. We used to believe this
6236 // could not happen and therefore had an assertion disallowing this; this test
6237 // exists to demonstrate that we can handle this condition without a failing
6238 // assertion. See also the discussion here:
6239 // https://discourse.llvm.org/t/70086/6
6240 std::string Code
= R
"(
6242 template <class T> struct initializer_list {
6248 void target(char* p, char* end) {
6255 auto && range = {1, 2};
6256 for (auto b = range.begin(), e = range.end(); b != e; ++b) {
6265 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6266 ASTContext
&ASTCtx
) {
6267 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6269 // Joining environments with different storage locations for the same
6270 // declaration results in the declaration being removed from the joined
6272 const ValueDecl
*VD
= findValueDecl(ASTCtx
, "range");
6273 ASSERT_EQ(Env
.getStorageLocation(*VD
), nullptr);