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 // It's legal for the assignment operator to take its source parameter by value.
2217 // Check that we handle this correctly. (This is a repro -- we used to
2218 // assert-fail on this.)
2219 TEST(TransferTest
, AssignmentOperator_ArgByValue
) {
2220 std::string Code
= R
"(
2235 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2236 ASTContext
&ASTCtx
) {
2237 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2238 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2240 const auto &FooLoc
=
2241 getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "Foo");
2242 const auto &BarLoc
=
2243 getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "Bar");
2245 const auto *FooBazVal
=
2246 cast
<IntegerValue
>(getFieldValue(&FooLoc
, *BazDecl
, Env
));
2247 const auto *BarBazVal
=
2248 cast
<IntegerValue
>(getFieldValue(&BarLoc
, *BazDecl
, Env
));
2249 EXPECT_EQ(FooBazVal
, BarBazVal
);
2253 TEST(TransferTest
, AssignmentOperatorFromBase
) {
2254 // This is a crash repro. We don't model the copy this case, so no
2255 // expectations on the copied field of the base class are checked.
2256 std::string Code
= R
"(
2260 struct Derived : public Base {
2261 using Base::operator=;
2264 void target(Base B, Derived D) {
2273 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2274 ASTContext
&ASTCtx
) {});
2277 TEST(TransferTest
, AssignmentOperatorFromCallResult
) {
2278 std::string Code
= R
"(
2289 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2290 ASTContext
&ASTCtx
) {
2291 // As of this writing, we don't produce a `Value` for the call
2292 // `ReturnA()`. The only condition we're testing for is that the
2293 // analysis should not crash in this case.
2297 TEST(TransferTest
, AssignmentOperatorWithInitAndInheritance
) {
2298 // This is a crash repro.
2299 std::string Code
= R
"(
2300 struct B { int Foo; };
2301 struct S : public B {};
2306 S1 = S2; // Only Dst has InitListExpr.
2307 S3 = S1; // Only Src has InitListExpr.
2313 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2314 ASTContext
&ASTCtx
) {});
2317 TEST(TransferTest
, CopyConstructor
) {
2318 std::string Code
= R
"(
2333 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2334 ASTContext
&ASTCtx
) {
2335 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2336 ASSERT_THAT(FooDecl
, NotNull());
2338 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2339 ASSERT_THAT(BarDecl
, NotNull());
2341 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2342 ASSERT_THAT(BazDecl
, NotNull());
2346 const Environment
&Env
=
2347 getEnvironmentAtAnnotation(Results
, "after_copy");
2349 const auto *FooLoc
=
2350 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2351 const auto *BarLoc
=
2352 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*BarDecl
));
2354 // `Foo` and `Bar` have different `RecordValue`s associated with them.
2355 const auto *FooVal
= cast
<RecordValue
>(Env
.getValue(*FooLoc
));
2356 const auto *BarVal
= cast
<RecordValue
>(Env
.getValue(*BarLoc
));
2357 EXPECT_NE(FooVal
, BarVal
);
2359 // But the records compare equal.
2360 EXPECT_TRUE(recordsEqual(*FooLoc
, *BarLoc
, Env
));
2362 // In particular, the value of `Baz` in both records is the same.
2363 const auto *FooBazVal
=
2364 cast
<IntegerValue
>(getFieldValue(FooLoc
, *BazDecl
, Env
));
2365 const auto *BarBazVal
=
2366 cast
<IntegerValue
>(getFieldValue(BarLoc
, *BazDecl
, Env
));
2367 EXPECT_EQ(FooBazVal
, BarBazVal
);
2372 const Environment
&Env
=
2373 getEnvironmentAtAnnotation(Results
, "after_update");
2375 const auto *FooLoc
=
2376 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2377 const auto *BarLoc
=
2378 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*BarDecl
));
2380 EXPECT_FALSE(recordsEqual(*FooLoc
, *BarLoc
, Env
));
2382 const auto *FooBazVal
=
2383 cast
<IntegerValue
>(getFieldValue(FooLoc
, *BazDecl
, Env
));
2384 const auto *BarBazVal
=
2385 cast
<IntegerValue
>(getFieldValue(BarLoc
, *BazDecl
, Env
));
2386 EXPECT_NE(FooBazVal
, BarBazVal
);
2391 TEST(TransferTest
, CopyConstructorWithDefaultArgument
) {
2392 std::string Code
= R
"(
2396 A(const A& a, bool def = true) { Baz = a.Baz; }
2408 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2409 ASTContext
&ASTCtx
) {
2410 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2411 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2413 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2414 ASSERT_THAT(FooDecl
, NotNull());
2416 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2417 ASSERT_THAT(BarDecl
, NotNull());
2419 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2420 ASSERT_THAT(BazDecl
, NotNull());
2422 const auto *FooLoc
=
2423 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2424 const auto *BarLoc
=
2425 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*BarDecl
));
2426 EXPECT_TRUE(recordsEqual(*FooLoc
, *BarLoc
, Env
));
2428 const auto *FooBazVal
=
2429 cast
<IntegerValue
>(getFieldValue(FooLoc
, *BazDecl
, Env
));
2430 const auto *BarBazVal
=
2431 cast
<IntegerValue
>(getFieldValue(BarLoc
, *BazDecl
, Env
));
2432 EXPECT_EQ(FooBazVal
, BarBazVal
);
2436 TEST(TransferTest
, CopyConstructorWithParens
) {
2437 std::string Code
= R
"(
2451 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2452 ASTContext
&ASTCtx
) {
2453 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2454 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2456 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2457 ASSERT_THAT(FooDecl
, NotNull());
2459 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2460 ASSERT_THAT(BarDecl
, NotNull());
2462 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2463 ASSERT_THAT(BazDecl
, NotNull());
2465 const auto *FooLoc
=
2466 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2467 const auto *BarLoc
=
2468 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*BarDecl
));
2469 EXPECT_TRUE(recordsEqual(*FooLoc
, *BarLoc
, Env
));
2471 const auto *FooBazVal
=
2472 cast
<IntegerValue
>(getFieldValue(FooLoc
, *BazDecl
, Env
));
2473 const auto *BarBazVal
=
2474 cast
<IntegerValue
>(getFieldValue(BarLoc
, *BazDecl
, Env
));
2475 EXPECT_EQ(FooBazVal
, BarBazVal
);
2479 TEST(TransferTest
, CopyConstructorWithInitializerListAsSyntacticSugar
) {
2480 std::string Code
= R
"(
2493 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2494 ASTContext
&ASTCtx
) {
2495 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2497 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2499 const auto &FooLoc
=
2500 getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "Foo");
2501 const auto &BarLoc
=
2502 getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "Bar");
2504 const auto *FooBazVal
=
2505 cast
<IntegerValue
>(getFieldValue(&FooLoc
, *BazDecl
, Env
));
2506 const auto *BarBazVal
=
2507 cast
<IntegerValue
>(getFieldValue(&BarLoc
, *BazDecl
, Env
));
2508 EXPECT_EQ(FooBazVal
, BarBazVal
);
2512 TEST(TransferTest
, CopyConstructorArgIsRefReturnedByFunction
) {
2513 // This is a crash repro.
2514 std::string Code
= R
"(
2516 const S &returnsSRef();
2523 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2524 ASTContext
&ASTCtx
) {});
2527 TEST(TransferTest
, MoveConstructor
) {
2528 std::string Code
= R
"(
2531 template <typename T> struct remove_reference { using type = T; };
2532 template <typename T> struct remove_reference<T&> { using type = T; };
2533 template <typename T> struct remove_reference<T&&> { using type = T; };
2535 template <typename T>
2536 using remove_reference_t = typename remove_reference<T>::type;
2538 template <typename T>
2539 std::remove_reference_t<T>&& move(T&& x);
2552 Foo = std::move(Bar);
2558 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2559 ASTContext
&ASTCtx
) {
2560 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p1", "p2"));
2561 const Environment
&Env1
= getEnvironmentAtAnnotation(Results
, "p1");
2562 const Environment
&Env2
= getEnvironmentAtAnnotation(Results
, "p2");
2564 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2565 ASSERT_THAT(FooDecl
, NotNull());
2567 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2568 ASSERT_THAT(BarDecl
, NotNull());
2570 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2571 ASSERT_THAT(BazDecl
, NotNull());
2573 const auto *FooLoc1
=
2574 cast
<RecordStorageLocation
>(Env1
.getStorageLocation(*FooDecl
));
2575 const auto *BarLoc1
=
2576 cast
<RecordStorageLocation
>(Env1
.getStorageLocation(*BarDecl
));
2578 EXPECT_FALSE(recordsEqual(*FooLoc1
, *BarLoc1
, Env1
));
2580 const auto *FooVal1
= cast
<RecordValue
>(Env1
.getValue(*FooLoc1
));
2581 const auto *BarVal1
= cast
<RecordValue
>(Env1
.getValue(*BarLoc1
));
2582 EXPECT_NE(FooVal1
, BarVal1
);
2584 const auto *FooBazVal1
=
2585 cast
<IntegerValue
>(getFieldValue(FooLoc1
, *BazDecl
, Env1
));
2586 const auto *BarBazVal1
=
2587 cast
<IntegerValue
>(getFieldValue(BarLoc1
, *BazDecl
, Env1
));
2588 EXPECT_NE(FooBazVal1
, BarBazVal1
);
2590 const auto *FooLoc2
=
2591 cast
<RecordStorageLocation
>(Env2
.getStorageLocation(*FooDecl
));
2592 const auto *FooVal2
= cast
<RecordValue
>(Env2
.getValue(*FooLoc2
));
2593 EXPECT_NE(FooVal2
, BarVal1
);
2594 EXPECT_TRUE(recordsEqual(*FooLoc2
, Env2
, *BarLoc1
, Env1
));
2596 const auto *FooBazVal2
=
2597 cast
<IntegerValue
>(getFieldValue(FooLoc1
, *BazDecl
, Env2
));
2598 EXPECT_EQ(FooBazVal2
, BarBazVal1
);
2602 TEST(TransferTest
, BindTemporary
) {
2603 std::string Code
= R
"(
2605 virtual ~A() = default;
2610 void target(A Foo) {
2611 int Bar = A(Foo).Baz;
2617 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2618 ASTContext
&ASTCtx
) {
2619 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2620 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2622 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2623 ASSERT_THAT(FooDecl
, NotNull());
2625 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2626 ASSERT_THAT(BarDecl
, NotNull());
2628 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2629 ASSERT_THAT(BazDecl
, NotNull());
2631 const auto &FooLoc
=
2632 *cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2633 const auto *BarVal
= cast
<IntegerValue
>(Env
.getValue(*BarDecl
));
2634 EXPECT_EQ(BarVal
, getFieldValue(&FooLoc
, *BazDecl
, Env
));
2638 TEST(TransferTest
, StaticCast
) {
2639 std::string Code
= R
"(
2640 void target(int Foo) {
2641 int Bar = static_cast<int>(Foo);
2647 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2648 ASTContext
&ASTCtx
) {
2649 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2650 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2652 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2653 ASSERT_THAT(FooDecl
, NotNull());
2655 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2656 ASSERT_THAT(BarDecl
, NotNull());
2658 const auto *FooVal
= Env
.getValue(*FooDecl
);
2659 const auto *BarVal
= Env
.getValue(*BarDecl
);
2660 EXPECT_TRUE(isa
<IntegerValue
>(FooVal
));
2661 EXPECT_TRUE(isa
<IntegerValue
>(BarVal
));
2662 EXPECT_EQ(FooVal
, BarVal
);
2666 TEST(TransferTest
, IntegralCast
) {
2667 std::string Code
= R
"(
2668 void target(int Foo) {
2675 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2676 ASTContext
&ASTCtx
) {
2677 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2678 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2680 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2681 ASSERT_THAT(FooDecl
, NotNull());
2683 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2684 ASSERT_THAT(BarDecl
, NotNull());
2686 const auto *FooVal
= Env
.getValue(*FooDecl
);
2687 const auto *BarVal
= Env
.getValue(*BarDecl
);
2688 EXPECT_TRUE(isa
<IntegerValue
>(FooVal
));
2689 EXPECT_TRUE(isa
<IntegerValue
>(BarVal
));
2690 EXPECT_EQ(FooVal
, BarVal
);
2694 TEST(TransferTest
, IntegraltoBooleanCast
) {
2695 std::string Code
= R
"(
2696 void target(int Foo) {
2703 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2704 ASTContext
&ASTCtx
) {
2705 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2706 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2708 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2709 ASSERT_THAT(FooDecl
, NotNull());
2711 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2712 ASSERT_THAT(BarDecl
, NotNull());
2714 const auto *FooVal
= Env
.getValue(*FooDecl
);
2715 const auto *BarVal
= Env
.getValue(*BarDecl
);
2716 EXPECT_TRUE(isa
<IntegerValue
>(FooVal
));
2717 EXPECT_TRUE(isa
<BoolValue
>(BarVal
));
2721 TEST(TransferTest
, IntegralToBooleanCastFromBool
) {
2722 std::string Code
= R
"(
2723 void target(bool Foo) {
2731 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2732 ASTContext
&ASTCtx
) {
2733 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2734 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2736 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2737 ASSERT_THAT(FooDecl
, NotNull());
2739 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2740 ASSERT_THAT(BarDecl
, NotNull());
2742 const auto *FooVal
= Env
.getValue(*FooDecl
);
2743 const auto *BarVal
= Env
.getValue(*BarDecl
);
2744 EXPECT_TRUE(isa
<BoolValue
>(FooVal
));
2745 EXPECT_TRUE(isa
<BoolValue
>(BarVal
));
2746 EXPECT_EQ(FooVal
, BarVal
);
2750 TEST(TransferTest
, NullToPointerCast
) {
2751 std::string Code
= R
"(
2752 using my_nullptr_t = decltype(nullptr);
2755 int *FooX = nullptr;
2756 int *FooY = nullptr;
2757 bool **Bar = nullptr;
2759 my_nullptr_t Null = 0;
2765 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2766 ASTContext
&ASTCtx
) {
2767 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2768 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2770 const ValueDecl
*FooXDecl
= findValueDecl(ASTCtx
, "FooX");
2771 ASSERT_THAT(FooXDecl
, NotNull());
2773 const ValueDecl
*FooYDecl
= findValueDecl(ASTCtx
, "FooY");
2774 ASSERT_THAT(FooYDecl
, NotNull());
2776 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2777 ASSERT_THAT(BarDecl
, NotNull());
2779 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2780 ASSERT_THAT(BazDecl
, NotNull());
2782 const ValueDecl
*NullDecl
= findValueDecl(ASTCtx
, "Null");
2783 ASSERT_THAT(NullDecl
, NotNull());
2785 const auto *FooXVal
= cast
<PointerValue
>(Env
.getValue(*FooXDecl
));
2786 const auto *FooYVal
= cast
<PointerValue
>(Env
.getValue(*FooYDecl
));
2787 const auto *BarVal
= cast
<PointerValue
>(Env
.getValue(*BarDecl
));
2788 const auto *BazVal
= cast
<PointerValue
>(Env
.getValue(*BazDecl
));
2789 const auto *NullVal
= cast
<PointerValue
>(Env
.getValue(*NullDecl
));
2791 EXPECT_EQ(FooXVal
, FooYVal
);
2792 EXPECT_NE(FooXVal
, BarVal
);
2793 EXPECT_NE(FooXVal
, BazVal
);
2794 EXPECT_NE(BarVal
, BazVal
);
2796 const StorageLocation
&FooPointeeLoc
= FooXVal
->getPointeeLoc();
2797 EXPECT_TRUE(isa
<ScalarStorageLocation
>(FooPointeeLoc
));
2798 EXPECT_THAT(Env
.getValue(FooPointeeLoc
), IsNull());
2800 const StorageLocation
&BarPointeeLoc
= BarVal
->getPointeeLoc();
2801 EXPECT_TRUE(isa
<ScalarStorageLocation
>(BarPointeeLoc
));
2802 EXPECT_THAT(Env
.getValue(BarPointeeLoc
), IsNull());
2804 const StorageLocation
&BazPointeeLoc
= BazVal
->getPointeeLoc();
2805 EXPECT_TRUE(isa
<RecordStorageLocation
>(BazPointeeLoc
));
2806 EXPECT_THAT(Env
.getValue(BazPointeeLoc
), IsNull());
2808 const StorageLocation
&NullPointeeLoc
= NullVal
->getPointeeLoc();
2809 EXPECT_TRUE(isa
<ScalarStorageLocation
>(NullPointeeLoc
));
2810 EXPECT_THAT(Env
.getValue(NullPointeeLoc
), IsNull());
2814 TEST(TransferTest
, PointerToMemberVariable
) {
2815 std::string Code
= R
"(
2820 int S::*MemberPointer = &S::i;
2826 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2827 ASTContext
&ASTCtx
) {
2828 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2830 const ValueDecl
*MemberPointerDecl
=
2831 findValueDecl(ASTCtx
, "MemberPointer");
2832 ASSERT_THAT(MemberPointerDecl
, NotNull());
2833 ASSERT_THAT(Env
.getValue(*MemberPointerDecl
), IsNull());
2837 TEST(TransferTest
, PointerToMemberFunction
) {
2838 std::string Code
= R
"(
2843 void (S::*MemberPointer)() = &S::Method;
2849 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2850 ASTContext
&ASTCtx
) {
2851 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2853 const ValueDecl
*MemberPointerDecl
=
2854 findValueDecl(ASTCtx
, "MemberPointer");
2855 ASSERT_THAT(MemberPointerDecl
, NotNull());
2856 ASSERT_THAT(Env
.getValue(*MemberPointerDecl
), IsNull());
2860 TEST(TransferTest
, NullToMemberPointerCast
) {
2861 std::string Code
= R
"(
2864 int Foo::*MemberPointer = nullptr;
2870 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2871 ASTContext
&ASTCtx
) {
2872 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2873 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2875 const ValueDecl
*MemberPointerDecl
=
2876 findValueDecl(ASTCtx
, "MemberPointer");
2877 ASSERT_THAT(MemberPointerDecl
, NotNull());
2878 ASSERT_THAT(Env
.getValue(*MemberPointerDecl
), IsNull());
2882 TEST(TransferTest
, AddrOfValue
) {
2883 std::string Code
= R
"(
2892 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2893 ASTContext
&ASTCtx
) {
2894 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2895 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2897 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2898 ASSERT_THAT(FooDecl
, NotNull());
2900 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2901 ASSERT_THAT(BarDecl
, NotNull());
2903 const auto *FooLoc
=
2904 cast
<ScalarStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2905 const auto *BarVal
= cast
<PointerValue
>(Env
.getValue(*BarDecl
));
2906 EXPECT_EQ(&BarVal
->getPointeeLoc(), FooLoc
);
2910 TEST(TransferTest
, AddrOfReference
) {
2911 std::string Code
= R
"(
2912 void target(int *Foo) {
2919 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2920 ASTContext
&ASTCtx
) {
2921 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2922 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2924 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2925 ASSERT_THAT(FooDecl
, NotNull());
2927 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2928 ASSERT_THAT(BarDecl
, NotNull());
2930 const auto *FooVal
= cast
<PointerValue
>(Env
.getValue(*FooDecl
));
2931 const auto *BarVal
= cast
<PointerValue
>(Env
.getValue(*BarDecl
));
2932 EXPECT_EQ(&BarVal
->getPointeeLoc(), &FooVal
->getPointeeLoc());
2936 TEST(TransferTest
, CannotAnalyzeFunctionTemplate
) {
2937 std::string Code
= R
"(
2938 template <typename T>
2942 checkDataflowWithNoopAnalysis(Code
),
2943 llvm::FailedWithMessage("Cannot analyze templated declarations"));
2946 TEST(TransferTest
, CannotAnalyzeMethodOfClassTemplate
) {
2947 std::string Code
= R
"(
2948 template <typename T>
2954 checkDataflowWithNoopAnalysis(Code
),
2955 llvm::FailedWithMessage("Cannot analyze templated declarations"));
2958 TEST(TransferTest
, VarDeclInitAssignConditionalOperator
) {
2959 std::string Code
= R
"(
2962 void target(A Foo, A Bar, bool Cond) {
2963 A Baz = Cond ? Foo : Bar;
2969 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2970 ASTContext
&ASTCtx
) {
2971 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2972 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2974 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2975 ASSERT_THAT(FooDecl
, NotNull());
2977 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2978 ASSERT_THAT(BarDecl
, NotNull());
2980 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2981 ASSERT_THAT(BazDecl
, NotNull());
2983 const auto *FooVal
= cast
<RecordValue
>(Env
.getValue(*FooDecl
));
2984 const auto *BarVal
= cast
<RecordValue
>(Env
.getValue(*BarDecl
));
2986 const auto *BazVal
= dyn_cast
<RecordValue
>(Env
.getValue(*BazDecl
));
2987 ASSERT_THAT(BazVal
, NotNull());
2989 EXPECT_NE(BazVal
, FooVal
);
2990 EXPECT_NE(BazVal
, BarVal
);
2994 TEST(TransferTest
, VarDeclInDoWhile
) {
2995 std::string Code
= R
"(
2996 void target(int *Foo) {
3007 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3008 ASTContext
&ASTCtx
) {
3009 const Environment
&EnvInLoop
=
3010 getEnvironmentAtAnnotation(Results
, "in_loop");
3011 const Environment
&EnvAfterLoop
=
3012 getEnvironmentAtAnnotation(Results
, "after_loop");
3014 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3015 ASSERT_THAT(FooDecl
, NotNull());
3017 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3018 ASSERT_THAT(BarDecl
, NotNull());
3020 const auto *FooVal
=
3021 cast
<PointerValue
>(EnvAfterLoop
.getValue(*FooDecl
));
3022 const auto *FooPointeeVal
=
3023 cast
<IntegerValue
>(EnvAfterLoop
.getValue(FooVal
->getPointeeLoc()));
3025 const auto *BarVal
= cast
<IntegerValue
>(EnvInLoop
.getValue(*BarDecl
));
3026 EXPECT_EQ(BarVal
, FooPointeeVal
);
3028 ASSERT_THAT(EnvAfterLoop
.getValue(*BarDecl
), IsNull());
3032 TEST(TransferTest
, UnreachableAfterWhileTrue
) {
3033 std::string Code
= R
"(
3042 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3043 ASTContext
&ASTCtx
) {
3044 // The node after the while-true is pruned because it is trivially
3045 // known to be unreachable.
3046 ASSERT_TRUE(Results
.empty());
3050 TEST(TransferTest
, AggregateInitialization
) {
3051 std::string BracesCode
= R
"(
3062 void target(int BarArg, int FooArg, int QuxArg) {
3063 B Quux{BarArg, {FooArg}, QuxArg};
3068 std::string BraceElisionCode
= R
"(
3079 void target(int BarArg, int FooArg, int QuxArg) {
3080 B Quux = {BarArg, FooArg, QuxArg};
3085 for (const std::string
&Code
: {BracesCode
, BraceElisionCode
}) {
3088 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3089 ASTContext
&ASTCtx
) {
3090 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3091 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3093 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3094 ASSERT_THAT(FooDecl
, NotNull());
3096 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3097 ASSERT_THAT(BarDecl
, NotNull());
3099 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
3100 ASSERT_THAT(BazDecl
, NotNull());
3102 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
3103 ASSERT_THAT(QuxDecl
, NotNull());
3105 const ValueDecl
*FooArgDecl
= findValueDecl(ASTCtx
, "FooArg");
3106 ASSERT_THAT(FooArgDecl
, NotNull());
3108 const ValueDecl
*BarArgDecl
= findValueDecl(ASTCtx
, "BarArg");
3109 ASSERT_THAT(BarArgDecl
, NotNull());
3111 const ValueDecl
*QuxArgDecl
= findValueDecl(ASTCtx
, "QuxArg");
3112 ASSERT_THAT(QuxArgDecl
, NotNull());
3114 const ValueDecl
*QuuxDecl
= findValueDecl(ASTCtx
, "Quux");
3115 ASSERT_THAT(QuuxDecl
, NotNull());
3117 const auto *FooArgVal
= cast
<IntegerValue
>(Env
.getValue(*FooArgDecl
));
3118 const auto *BarArgVal
= cast
<IntegerValue
>(Env
.getValue(*BarArgDecl
));
3119 const auto *QuxArgVal
= cast
<IntegerValue
>(Env
.getValue(*QuxArgDecl
));
3121 const auto &QuuxLoc
=
3122 *cast
<RecordStorageLocation
>(Env
.getStorageLocation(*QuuxDecl
));
3123 const auto &BazLoc
=
3124 *cast
<RecordStorageLocation
>(QuuxLoc
.getChild(*BazDecl
));
3126 EXPECT_EQ(getFieldValue(&QuuxLoc
, *BarDecl
, Env
), BarArgVal
);
3127 EXPECT_EQ(getFieldValue(&BazLoc
, *FooDecl
, Env
), FooArgVal
);
3128 EXPECT_EQ(getFieldValue(&QuuxLoc
, *QuxDecl
, Env
), QuxArgVal
);
3130 // Check that fields initialized in an initializer list are always
3131 // modeled in other instances of the same type.
3132 const auto &OtherBLoc
=
3133 getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "OtherB");
3134 EXPECT_THAT(OtherBLoc
.getChild(*BarDecl
), NotNull());
3135 EXPECT_THAT(OtherBLoc
.getChild(*BazDecl
), NotNull());
3136 EXPECT_THAT(OtherBLoc
.getChild(*QuxDecl
), NotNull());
3141 TEST(TransferTest
, AggregateInitializationReferenceField
) {
3142 std::string Code
= R
"(
3147 void target(int i) {
3154 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3155 ASTContext
&ASTCtx
) {
3156 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3158 const ValueDecl
*RefFieldDecl
= findValueDecl(ASTCtx
, "RefField");
3160 auto &ILoc
= getLocForDecl
<StorageLocation
>(ASTCtx
, Env
, "i");
3161 auto &SLoc
= getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "s");
3163 EXPECT_EQ(SLoc
.getChild(*RefFieldDecl
), &ILoc
);
3167 TEST(TransferTest
, AggregateInitialization_NotExplicitlyInitializedField
) {
3168 std::string Code
= R
"(
3174 void target(int i) {
3181 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3182 ASTContext
&ASTCtx
) {
3183 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3185 const ValueDecl
*I1FieldDecl
= findValueDecl(ASTCtx
, "i1");
3186 const ValueDecl
*I2FieldDecl
= findValueDecl(ASTCtx
, "i2");
3188 auto &SLoc
= getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "s");
3190 auto &IValue
= getValueForDecl
<IntegerValue
>(ASTCtx
, Env
, "i");
3192 *cast
<IntegerValue
>(getFieldValue(&SLoc
, *I1FieldDecl
, Env
));
3193 EXPECT_EQ(&I1Value
, &IValue
);
3195 *cast
<IntegerValue
>(getFieldValue(&SLoc
, *I2FieldDecl
, Env
));
3196 EXPECT_NE(&I2Value
, &IValue
);
3200 TEST(TransferTest
, AggregateInitializationFunctionPointer
) {
3201 // This is a repro for an assertion failure.
3202 // nullptr takes on the type of a const function pointer, but its type was
3203 // asserted to be equal to the *unqualified* type of Field, which no longer
3204 // included the const.
3205 std::string Code
= R
"(
3207 void (*const Field)();
3216 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3217 ASTContext
&ASTCtx
) {});
3220 TEST(TransferTest
, AssignToUnionMember
) {
3221 std::string Code
= R
"(
3226 void target(int Bar) {
3234 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3235 ASTContext
&ASTCtx
) {
3236 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3237 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3239 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
3240 ASSERT_THAT(BazDecl
, NotNull());
3241 ASSERT_TRUE(BazDecl
->getType()->isUnionType());
3243 auto BazFields
= BazDecl
->getType()->getAsRecordDecl()->fields();
3244 FieldDecl
*FooDecl
= nullptr;
3245 for (FieldDecl
*Field
: BazFields
) {
3246 if (Field
->getNameAsString() == "Foo") {
3249 FAIL() << "Unexpected field: " << Field
->getNameAsString();
3252 ASSERT_THAT(FooDecl
, NotNull());
3254 const auto *BazLoc
= dyn_cast_or_null
<RecordStorageLocation
>(
3255 Env
.getStorageLocation(*BazDecl
));
3256 ASSERT_THAT(BazLoc
, NotNull());
3257 ASSERT_THAT(Env
.getValue(*BazLoc
), NotNull());
3259 const auto *FooVal
=
3260 cast
<IntegerValue
>(getFieldValue(BazLoc
, *FooDecl
, Env
));
3262 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3263 ASSERT_THAT(BarDecl
, NotNull());
3264 const auto *BarLoc
= Env
.getStorageLocation(*BarDecl
);
3265 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
3267 EXPECT_EQ(Env
.getValue(*BarLoc
), FooVal
);
3271 TEST(TransferTest
, AssignFromBoolLiteral
) {
3272 std::string Code
= R
"(
3281 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3282 ASTContext
&ASTCtx
) {
3283 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3284 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3286 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3287 ASSERT_THAT(FooDecl
, NotNull());
3289 const auto *FooVal
=
3290 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*FooDecl
));
3291 ASSERT_THAT(FooVal
, NotNull());
3293 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3294 ASSERT_THAT(BarDecl
, NotNull());
3296 const auto *BarVal
=
3297 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BarDecl
));
3298 ASSERT_THAT(BarVal
, NotNull());
3300 EXPECT_EQ(FooVal
, &Env
.getBoolLiteralValue(true));
3301 EXPECT_EQ(BarVal
, &Env
.getBoolLiteralValue(false));
3305 TEST(TransferTest
, AssignFromCompositeBoolExpression
) {
3307 std::string Code
= R
"(
3308 void target(bool Foo, bool Bar, bool Qux) {
3309 bool Baz = (Foo) && (Bar || Qux);
3315 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3316 ASTContext
&ASTCtx
) {
3317 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3318 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3320 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3321 ASSERT_THAT(FooDecl
, NotNull());
3323 const auto *FooVal
=
3324 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*FooDecl
));
3325 ASSERT_THAT(FooVal
, NotNull());
3327 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3328 ASSERT_THAT(BarDecl
, NotNull());
3330 const auto *BarVal
=
3331 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BarDecl
));
3332 ASSERT_THAT(BarVal
, NotNull());
3334 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
3335 ASSERT_THAT(QuxDecl
, NotNull());
3337 const auto *QuxVal
=
3338 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*QuxDecl
));
3339 ASSERT_THAT(QuxVal
, NotNull());
3341 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
3342 ASSERT_THAT(BazDecl
, NotNull());
3344 const auto *BazVal
=
3345 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BazDecl
));
3346 ASSERT_THAT(BazVal
, NotNull());
3347 auto &A
= Env
.arena();
3348 EXPECT_EQ(&BazVal
->formula(),
3349 &A
.makeAnd(FooVal
->formula(),
3350 A
.makeOr(BarVal
->formula(), QuxVal
->formula())));
3355 std::string Code
= R
"(
3356 void target(bool Foo, bool Bar, bool Qux) {
3357 bool Baz = (Foo && Qux) || (Bar);
3363 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3364 ASTContext
&ASTCtx
) {
3365 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3366 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3368 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3369 ASSERT_THAT(FooDecl
, NotNull());
3371 const auto *FooVal
=
3372 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*FooDecl
));
3373 ASSERT_THAT(FooVal
, NotNull());
3375 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3376 ASSERT_THAT(BarDecl
, NotNull());
3378 const auto *BarVal
=
3379 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BarDecl
));
3380 ASSERT_THAT(BarVal
, NotNull());
3382 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
3383 ASSERT_THAT(QuxDecl
, NotNull());
3385 const auto *QuxVal
=
3386 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*QuxDecl
));
3387 ASSERT_THAT(QuxVal
, NotNull());
3389 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
3390 ASSERT_THAT(BazDecl
, NotNull());
3392 const auto *BazVal
=
3393 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BazDecl
));
3394 ASSERT_THAT(BazVal
, NotNull());
3395 auto &A
= Env
.arena();
3396 EXPECT_EQ(&BazVal
->formula(),
3397 &A
.makeOr(A
.makeAnd(FooVal
->formula(), QuxVal
->formula()),
3398 BarVal
->formula()));
3403 std::string Code
= R
"(
3404 void target(bool A, bool B, bool C, bool D) {
3405 bool Foo = ((A && B) && C) && D;
3411 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3412 ASTContext
&ASTCtx
) {
3413 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3414 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3416 const ValueDecl
*ADecl
= findValueDecl(ASTCtx
, "A");
3417 ASSERT_THAT(ADecl
, NotNull());
3419 const auto *AVal
= dyn_cast_or_null
<BoolValue
>(Env
.getValue(*ADecl
));
3420 ASSERT_THAT(AVal
, NotNull());
3422 const ValueDecl
*BDecl
= findValueDecl(ASTCtx
, "B");
3423 ASSERT_THAT(BDecl
, NotNull());
3425 const auto *BVal
= dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BDecl
));
3426 ASSERT_THAT(BVal
, NotNull());
3428 const ValueDecl
*CDecl
= findValueDecl(ASTCtx
, "C");
3429 ASSERT_THAT(CDecl
, NotNull());
3431 const auto *CVal
= dyn_cast_or_null
<BoolValue
>(Env
.getValue(*CDecl
));
3432 ASSERT_THAT(CVal
, NotNull());
3434 const ValueDecl
*DDecl
= findValueDecl(ASTCtx
, "D");
3435 ASSERT_THAT(DDecl
, NotNull());
3437 const auto *DVal
= dyn_cast_or_null
<BoolValue
>(Env
.getValue(*DDecl
));
3438 ASSERT_THAT(DVal
, NotNull());
3440 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3441 ASSERT_THAT(FooDecl
, NotNull());
3443 const auto *FooVal
=
3444 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*FooDecl
));
3445 ASSERT_THAT(FooVal
, NotNull());
3446 auto &A
= Env
.arena();
3449 &A
.makeAnd(A
.makeAnd(A
.makeAnd(AVal
->formula(), BVal
->formula()),
3456 TEST(TransferTest
, AssignFromBoolNegation
) {
3457 std::string Code
= R
"(
3466 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3467 ASTContext
&ASTCtx
) {
3468 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3469 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3471 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3472 ASSERT_THAT(FooDecl
, NotNull());
3474 const auto *FooVal
=
3475 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*FooDecl
));
3476 ASSERT_THAT(FooVal
, NotNull());
3478 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3479 ASSERT_THAT(BarDecl
, NotNull());
3481 const auto *BarVal
=
3482 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BarDecl
));
3483 ASSERT_THAT(BarVal
, NotNull());
3484 auto &A
= Env
.arena();
3485 EXPECT_EQ(&BarVal
->formula(), &A
.makeNot(FooVal
->formula()));
3489 TEST(TransferTest
, BuiltinExpect
) {
3490 std::string Code
= R
"(
3491 void target(long Foo) {
3492 long Bar = __builtin_expect(Foo, true);
3498 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3499 ASTContext
&ASTCtx
) {
3500 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3501 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3503 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3504 ASSERT_THAT(FooDecl
, NotNull());
3506 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3507 ASSERT_THAT(BarDecl
, NotNull());
3509 EXPECT_EQ(Env
.getValue(*FooDecl
), Env
.getValue(*BarDecl
));
3513 // `__builtin_expect` takes and returns a `long` argument, so other types
3514 // involve casts. This verifies that we identify the input and output in that
3516 TEST(TransferTest
, BuiltinExpectBoolArg
) {
3517 std::string Code
= R
"(
3518 void target(bool Foo) {
3519 bool Bar = __builtin_expect(Foo, true);
3525 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3526 ASTContext
&ASTCtx
) {
3527 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3528 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3530 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3531 ASSERT_THAT(FooDecl
, NotNull());
3533 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3534 ASSERT_THAT(BarDecl
, NotNull());
3536 EXPECT_EQ(Env
.getValue(*FooDecl
), Env
.getValue(*BarDecl
));
3540 TEST(TransferTest
, BuiltinUnreachable
) {
3541 std::string Code
= R
"(
3542 void target(bool Foo) {
3547 __builtin_unreachable();
3554 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3555 ASTContext
&ASTCtx
) {
3556 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3557 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3559 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3560 ASSERT_THAT(FooDecl
, NotNull());
3562 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3563 ASSERT_THAT(BarDecl
, NotNull());
3565 // `__builtin_unreachable` promises that the code is
3566 // unreachable, so the compiler treats the "then" branch as the
3567 // only possible predecessor of this statement.
3568 EXPECT_EQ(Env
.getValue(*FooDecl
), Env
.getValue(*BarDecl
));
3572 TEST(TransferTest
, BuiltinTrap
) {
3573 std::string Code
= R
"(
3574 void target(bool Foo) {
3586 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3587 ASTContext
&ASTCtx
) {
3588 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3589 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3591 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3592 ASSERT_THAT(FooDecl
, NotNull());
3594 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3595 ASSERT_THAT(BarDecl
, NotNull());
3597 // `__builtin_trap` ensures program termination, so only the
3598 // "then" branch is a predecessor of this statement.
3599 EXPECT_EQ(Env
.getValue(*FooDecl
), Env
.getValue(*BarDecl
));
3603 TEST(TransferTest
, BuiltinDebugTrap
) {
3604 std::string Code
= R
"(
3605 void target(bool Foo) {
3610 __builtin_debugtrap();
3617 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3618 ASTContext
&ASTCtx
) {
3619 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3620 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3622 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3623 ASSERT_THAT(FooDecl
, NotNull());
3625 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3626 ASSERT_THAT(BarDecl
, NotNull());
3628 // `__builtin_debugtrap` doesn't ensure program termination.
3629 EXPECT_NE(Env
.getValue(*FooDecl
), Env
.getValue(*BarDecl
));
3633 TEST(TransferTest
, StaticIntSingleVarDecl
) {
3634 std::string Code
= R
"(
3642 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3643 ASTContext
&ASTCtx
) {
3644 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3645 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3647 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3648 ASSERT_THAT(FooDecl
, NotNull());
3650 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
3651 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
3653 const Value
*FooVal
= Env
.getValue(*FooLoc
);
3654 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
3658 TEST(TransferTest
, StaticIntGroupVarDecl
) {
3659 std::string Code
= R
"(
3661 static int Foo, Bar;
3668 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3669 ASTContext
&ASTCtx
) {
3670 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3671 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3673 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3674 ASSERT_THAT(FooDecl
, NotNull());
3676 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3677 ASSERT_THAT(BarDecl
, NotNull());
3679 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
3680 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
3682 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
3683 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
3685 const Value
*FooVal
= Env
.getValue(*FooLoc
);
3686 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
3688 const Value
*BarVal
= Env
.getValue(*BarLoc
);
3689 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
3691 EXPECT_NE(FooVal
, BarVal
);
3695 TEST(TransferTest
, GlobalIntVarDecl
) {
3696 std::string Code
= R
"(
3707 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3708 ASTContext
&ASTCtx
) {
3709 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3710 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3712 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3713 ASSERT_THAT(BarDecl
, NotNull());
3715 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
3716 ASSERT_THAT(BazDecl
, NotNull());
3718 const Value
*BarVal
= cast
<IntegerValue
>(Env
.getValue(*BarDecl
));
3719 const Value
*BazVal
= cast
<IntegerValue
>(Env
.getValue(*BazDecl
));
3720 EXPECT_EQ(BarVal
, BazVal
);
3724 TEST(TransferTest
, StaticMemberIntVarDecl
) {
3725 std::string Code
= R
"(
3738 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3739 ASTContext
&ASTCtx
) {
3740 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3741 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3743 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3744 ASSERT_THAT(BarDecl
, NotNull());
3746 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
3747 ASSERT_THAT(BazDecl
, NotNull());
3749 const Value
*BarVal
= cast
<IntegerValue
>(Env
.getValue(*BarDecl
));
3750 const Value
*BazVal
= cast
<IntegerValue
>(Env
.getValue(*BazDecl
));
3751 EXPECT_EQ(BarVal
, BazVal
);
3755 TEST(TransferTest
, StaticMemberRefVarDecl
) {
3756 std::string Code
= R
"(
3769 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3770 ASTContext
&ASTCtx
) {
3771 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3772 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3774 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3775 ASSERT_THAT(BarDecl
, NotNull());
3777 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
3778 ASSERT_THAT(BazDecl
, NotNull());
3780 const Value
*BarVal
= cast
<IntegerValue
>(Env
.getValue(*BarDecl
));
3781 const Value
*BazVal
= cast
<IntegerValue
>(Env
.getValue(*BazDecl
));
3782 EXPECT_EQ(BarVal
, BazVal
);
3786 TEST(TransferTest
, AssignMemberBeforeCopy
) {
3787 std::string Code
= R
"(
3803 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3804 ASTContext
&ASTCtx
) {
3805 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3806 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3808 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3809 ASSERT_THAT(FooDecl
, NotNull());
3811 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3812 ASSERT_THAT(BarDecl
, NotNull());
3814 const ValueDecl
*A1Decl
= findValueDecl(ASTCtx
, "A1");
3815 ASSERT_THAT(A1Decl
, NotNull());
3817 const ValueDecl
*A2Decl
= findValueDecl(ASTCtx
, "A2");
3818 ASSERT_THAT(A2Decl
, NotNull());
3820 const auto *BarVal
= cast
<IntegerValue
>(Env
.getValue(*BarDecl
));
3823 *cast
<RecordStorageLocation
>(Env
.getStorageLocation(*A2Decl
));
3824 EXPECT_EQ(getFieldValue(&A2Loc
, *FooDecl
, Env
), BarVal
);
3828 TEST(TransferTest
, BooleanEquality
) {
3829 std::string Code
= R
"(
3830 void target(bool Bar) {
3843 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3844 ASTContext
&ASTCtx
) {
3845 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p-then", "p-else"));
3846 const Environment
&EnvThen
=
3847 getEnvironmentAtAnnotation(Results
, "p-then");
3848 const Environment
&EnvElse
=
3849 getEnvironmentAtAnnotation(Results
, "p-else");
3851 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3852 ASSERT_THAT(BarDecl
, NotNull());
3854 auto &BarValThen
= getFormula(*BarDecl
, EnvThen
);
3855 EXPECT_TRUE(EnvThen
.proves(BarValThen
));
3857 auto &BarValElse
= getFormula(*BarDecl
, EnvElse
);
3858 EXPECT_TRUE(EnvElse
.proves(EnvElse
.arena().makeNot(BarValElse
)));
3862 TEST(TransferTest
, BooleanInequality
) {
3863 std::string Code
= R
"(
3864 void target(bool Bar) {
3877 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3878 ASTContext
&ASTCtx
) {
3879 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p-then", "p-else"));
3880 const Environment
&EnvThen
=
3881 getEnvironmentAtAnnotation(Results
, "p-then");
3882 const Environment
&EnvElse
=
3883 getEnvironmentAtAnnotation(Results
, "p-else");
3885 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3886 ASSERT_THAT(BarDecl
, NotNull());
3888 auto &BarValThen
= getFormula(*BarDecl
, EnvThen
);
3889 EXPECT_TRUE(EnvThen
.proves(EnvThen
.arena().makeNot(BarValThen
)));
3891 auto &BarValElse
= getFormula(*BarDecl
, EnvElse
);
3892 EXPECT_TRUE(EnvElse
.proves(BarValElse
));
3896 TEST(TransferTest
, IntegerLiteralEquality
) {
3897 std::string Code
= R
"(
3899 bool equal = (42 == 42);
3905 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3906 ASTContext
&ASTCtx
) {
3907 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3910 getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "equal").formula();
3911 EXPECT_TRUE(Env
.proves(Equal
));
3915 TEST(TransferTest
, CorrelatedBranches
) {
3916 std::string Code
= R
"(
3917 void target(bool B, bool C) {
3935 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3936 ASTContext
&ASTCtx
) {
3937 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p0", "p1", "p2"));
3939 const ValueDecl
*CDecl
= findValueDecl(ASTCtx
, "C");
3940 ASSERT_THAT(CDecl
, NotNull());
3943 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p0");
3944 const ValueDecl
*BDecl
= findValueDecl(ASTCtx
, "B");
3945 ASSERT_THAT(BDecl
, NotNull());
3946 auto &BVal
= getFormula(*BDecl
, Env
);
3948 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(BVal
)));
3952 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p1");
3953 auto &CVal
= getFormula(*CDecl
, Env
);
3954 EXPECT_TRUE(Env
.proves(CVal
));
3958 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p2");
3959 auto &CVal
= getFormula(*CDecl
, Env
);
3960 EXPECT_TRUE(Env
.proves(CVal
));
3965 TEST(TransferTest
, LoopWithAssignmentConverges
) {
3966 std::string Code
= R
"(
3978 // The key property that we are verifying is implicit in `runDataflow` --
3979 // namely, that the analysis succeeds, rather than hitting the maximum number
3983 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3984 ASTContext
&ASTCtx
) {
3985 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3986 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3988 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3989 ASSERT_THAT(BarDecl
, NotNull());
3991 auto &BarVal
= getFormula(*BarDecl
, Env
);
3992 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(BarVal
)));
3996 TEST(TransferTest
, LoopWithStagedAssignments
) {
3997 std::string Code
= R
"(
4013 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4014 ASTContext
&ASTCtx
) {
4015 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4016 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4018 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4019 ASSERT_THAT(BarDecl
, NotNull());
4020 const ValueDecl
*ErrDecl
= findValueDecl(ASTCtx
, "Err");
4021 ASSERT_THAT(ErrDecl
, NotNull());
4023 auto &BarVal
= getFormula(*BarDecl
, Env
);
4024 auto &ErrVal
= getFormula(*ErrDecl
, Env
);
4025 EXPECT_TRUE(Env
.proves(BarVal
));
4026 // An unsound analysis, for example only evaluating the loop once, can
4027 // conclude that `Err` is false. So, we test that this conclusion is not
4029 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(ErrVal
)));
4033 TEST(TransferTest
, LoopWithReferenceAssignmentConverges
) {
4034 std::string Code
= R
"(
4046 // The key property that we are verifying is that the analysis succeeds,
4047 // rather than hitting the maximum number of iterations.
4050 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4051 ASTContext
&ASTCtx
) {
4052 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4053 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4055 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4056 ASSERT_THAT(BarDecl
, NotNull());
4058 auto &BarVal
= getFormula(*BarDecl
, Env
);
4059 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(BarVal
)));
4063 TEST(TransferTest
, LoopWithStructReferenceAssignmentConverges
) {
4064 std::string Code
= R
"(
4069 void target(Lookup val, bool b) {
4070 const Lookup* l = nullptr;
4079 // The key property that we are verifying is implicit in `runDataflow` --
4080 // namely, that the analysis succeeds, rather than hitting the maximum number
4084 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4085 ASTContext
&ASTCtx
) {
4086 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p-inner", "p-outer"));
4087 const Environment
&InnerEnv
=
4088 getEnvironmentAtAnnotation(Results
, "p-inner");
4089 const Environment
&OuterEnv
=
4090 getEnvironmentAtAnnotation(Results
, "p-outer");
4092 const ValueDecl
*ValDecl
= findValueDecl(ASTCtx
, "val");
4093 ASSERT_THAT(ValDecl
, NotNull());
4095 const ValueDecl
*LDecl
= findValueDecl(ASTCtx
, "l");
4096 ASSERT_THAT(LDecl
, NotNull());
4099 auto *LVal
= dyn_cast
<PointerValue
>(InnerEnv
.getValue(*LDecl
));
4100 ASSERT_THAT(LVal
, NotNull());
4102 EXPECT_EQ(&LVal
->getPointeeLoc(),
4103 InnerEnv
.getStorageLocation(*ValDecl
));
4106 LVal
= dyn_cast
<PointerValue
>(OuterEnv
.getValue(*LDecl
));
4107 ASSERT_THAT(LVal
, NotNull());
4109 // The loop body may not have been executed, so we should not conclude
4110 // that `l` points to `val`.
4111 EXPECT_NE(&LVal
->getPointeeLoc(),
4112 OuterEnv
.getStorageLocation(*ValDecl
));
4116 TEST(TransferTest
, LoopDereferencingChangingPointerConverges
) {
4117 std::string Code
= R
"cc(
4118 bool some_condition();
4120 void target(int i1, int i2) {
4124 if (some_condition())
4131 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code
), llvm::Succeeded());
4134 TEST(TransferTest
, LoopDereferencingChangingRecordPointerConverges
) {
4135 std::string Code
= R
"cc(
4140 bool some_condition();
4142 void target(Lookup l1, Lookup l2) {
4146 if (some_condition())
4153 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code
), llvm::Succeeded());
4156 TEST(TransferTest
, LoopWithShortCircuitedConditionConverges
) {
4157 std::string Code
= R
"cc(
4162 while (foo() || foo()) {
4167 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code
), llvm::Succeeded());
4170 TEST(TransferTest
, DoesNotCrashOnUnionThisExpr
) {
4171 std::string Code
= R
"(
4183 // This is a crash regression test when calling the transfer function on a
4184 // `CXXThisExpr` that refers to a union.
4187 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
4189 LangStandard::lang_cxx17
, /*ApplyBuiltinTransfer=*/true, "operator=");
4192 TEST(TransferTest
, StructuredBindingAssignFromStructIntMembersToRefs
) {
4193 std::string Code
= R
"(
4203 auto &FooRef = Baz.Foo;
4204 auto &BarRef = Baz.Bar;
4205 auto &[BoundFooRef, BoundBarRef] = Baz;
4211 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4212 ASTContext
&ASTCtx
) {
4213 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4214 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4216 const ValueDecl
*FooRefDecl
= findValueDecl(ASTCtx
, "FooRef");
4217 ASSERT_THAT(FooRefDecl
, NotNull());
4219 const ValueDecl
*BarRefDecl
= findValueDecl(ASTCtx
, "BarRef");
4220 ASSERT_THAT(BarRefDecl
, NotNull());
4222 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
4223 ASSERT_THAT(QuxDecl
, NotNull());
4225 const ValueDecl
*BoundFooRefDecl
= findValueDecl(ASTCtx
, "BoundFooRef");
4226 ASSERT_THAT(BoundFooRefDecl
, NotNull());
4228 const ValueDecl
*BoundBarRefDecl
= findValueDecl(ASTCtx
, "BoundBarRef");
4229 ASSERT_THAT(BoundBarRefDecl
, NotNull());
4231 const StorageLocation
*FooRefLoc
= Env
.getStorageLocation(*FooRefDecl
);
4232 ASSERT_THAT(FooRefLoc
, NotNull());
4234 const StorageLocation
*BarRefLoc
= Env
.getStorageLocation(*BarRefDecl
);
4235 ASSERT_THAT(BarRefLoc
, NotNull());
4237 const Value
*QuxVal
= Env
.getValue(*QuxDecl
);
4238 ASSERT_THAT(QuxVal
, NotNull());
4240 const StorageLocation
*BoundFooRefLoc
=
4241 Env
.getStorageLocation(*BoundFooRefDecl
);
4242 EXPECT_EQ(BoundFooRefLoc
, FooRefLoc
);
4244 const StorageLocation
*BoundBarRefLoc
=
4245 Env
.getStorageLocation(*BoundBarRefDecl
);
4246 EXPECT_EQ(BoundBarRefLoc
, BarRefLoc
);
4248 EXPECT_EQ(Env
.getValue(*BoundFooRefDecl
), QuxVal
);
4252 TEST(TransferTest
, StructuredBindingAssignFromStructRefMembersToRefs
) {
4253 std::string Code
= R
"(
4259 void target(A Baz) {
4262 auto &FooRef = Baz.Foo;
4263 auto &BarRef = Baz.Bar;
4264 auto &[BoundFooRef, BoundBarRef] = Baz;
4270 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4271 ASTContext
&ASTCtx
) {
4272 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4273 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4275 const ValueDecl
*FooRefDecl
= findValueDecl(ASTCtx
, "FooRef");
4276 ASSERT_THAT(FooRefDecl
, NotNull());
4278 const ValueDecl
*BarRefDecl
= findValueDecl(ASTCtx
, "BarRef");
4279 ASSERT_THAT(BarRefDecl
, NotNull());
4281 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
4282 ASSERT_THAT(QuxDecl
, NotNull());
4284 const ValueDecl
*BoundFooRefDecl
= findValueDecl(ASTCtx
, "BoundFooRef");
4285 ASSERT_THAT(BoundFooRefDecl
, NotNull());
4287 const ValueDecl
*BoundBarRefDecl
= findValueDecl(ASTCtx
, "BoundBarRef");
4288 ASSERT_THAT(BoundBarRefDecl
, NotNull());
4290 const StorageLocation
*FooRefLoc
= Env
.getStorageLocation(*FooRefDecl
);
4291 ASSERT_THAT(FooRefLoc
, NotNull());
4293 const StorageLocation
*BarRefLoc
= Env
.getStorageLocation(*BarRefDecl
);
4294 ASSERT_THAT(BarRefLoc
, NotNull());
4296 const Value
*QuxVal
= Env
.getValue(*QuxDecl
);
4297 ASSERT_THAT(QuxVal
, NotNull());
4299 const StorageLocation
*BoundFooRefLoc
=
4300 Env
.getStorageLocation(*BoundFooRefDecl
);
4301 EXPECT_EQ(BoundFooRefLoc
, FooRefLoc
);
4303 const StorageLocation
*BoundBarRefLoc
=
4304 Env
.getStorageLocation(*BoundBarRefDecl
);
4305 EXPECT_EQ(BoundBarRefLoc
, BarRefLoc
);
4307 EXPECT_EQ(Env
.getValue(*BoundFooRefDecl
), QuxVal
);
4311 TEST(TransferTest
, StructuredBindingAssignFromStructIntMembersToInts
) {
4312 std::string Code
= R
"(
4322 auto &FooRef = Baz.Foo;
4323 auto &BarRef = Baz.Bar;
4324 auto [BoundFoo, BoundBar] = Baz;
4330 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4331 ASTContext
&ASTCtx
) {
4332 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4333 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4335 const ValueDecl
*FooRefDecl
= findValueDecl(ASTCtx
, "FooRef");
4336 ASSERT_THAT(FooRefDecl
, NotNull());
4338 const ValueDecl
*BarRefDecl
= findValueDecl(ASTCtx
, "BarRef");
4339 ASSERT_THAT(BarRefDecl
, NotNull());
4341 const ValueDecl
*BoundFooDecl
= findValueDecl(ASTCtx
, "BoundFoo");
4342 ASSERT_THAT(BoundFooDecl
, NotNull());
4344 const ValueDecl
*BoundBarDecl
= findValueDecl(ASTCtx
, "BoundBar");
4345 ASSERT_THAT(BoundBarDecl
, NotNull());
4347 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
4348 ASSERT_THAT(QuxDecl
, NotNull());
4350 const StorageLocation
*FooRefLoc
= Env
.getStorageLocation(*FooRefDecl
);
4351 ASSERT_THAT(FooRefLoc
, NotNull());
4353 const StorageLocation
*BarRefLoc
= Env
.getStorageLocation(*BarRefDecl
);
4354 ASSERT_THAT(BarRefLoc
, NotNull());
4356 const Value
*QuxVal
= Env
.getValue(*QuxDecl
);
4357 ASSERT_THAT(QuxVal
, NotNull());
4359 const StorageLocation
*BoundFooLoc
=
4360 Env
.getStorageLocation(*BoundFooDecl
);
4361 EXPECT_NE(BoundFooLoc
, FooRefLoc
);
4363 const StorageLocation
*BoundBarLoc
=
4364 Env
.getStorageLocation(*BoundBarDecl
);
4365 EXPECT_NE(BoundBarLoc
, BarRefLoc
);
4367 EXPECT_EQ(Env
.getValue(*BoundFooDecl
), QuxVal
);
4371 TEST(TransferTest
, StructuredBindingAssignFromTupleLikeType
) {
4372 std::string Code
= R
"(
4375 template <class> struct tuple_size;
4376 template <std::size_t, class> struct tuple_element;
4377 template <class...> class tuple;
4380 template <class T, T v>
4381 struct size_helper { static const T value = v; };
4384 template <class... T>
4385 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {};
4387 template <std::size_t I, class... T>
4388 struct tuple_element<I, tuple<T...>> {
4389 using type = __type_pack_element<I, T...>;
4392 template <class...> class tuple {};
4394 template <std::size_t I, class... T>
4395 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
4398 std::tuple<bool, int> makeTuple();
4400 void target(bool B) {
4401 auto [BoundFoo, BoundBar] = makeTuple();
4403 // Include if-then-else to test interaction of `BindingDecl` with join.
4417 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4418 ASTContext
&ASTCtx
) {
4419 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p1", "p2"));
4420 const Environment
&Env1
= getEnvironmentAtAnnotation(Results
, "p1");
4422 const ValueDecl
*BoundFooDecl
= findValueDecl(ASTCtx
, "BoundFoo");
4423 ASSERT_THAT(BoundFooDecl
, NotNull());
4425 const ValueDecl
*BoundBarDecl
= findValueDecl(ASTCtx
, "BoundBar");
4426 ASSERT_THAT(BoundBarDecl
, NotNull());
4428 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
4429 ASSERT_THAT(BazDecl
, NotNull());
4431 // BindingDecls always map to references -- either lvalue or rvalue, so
4432 // we still need to skip here.
4433 const Value
*BoundFooValue
= Env1
.getValue(*BoundFooDecl
);
4434 ASSERT_THAT(BoundFooValue
, NotNull());
4435 EXPECT_TRUE(isa
<BoolValue
>(BoundFooValue
));
4437 const Value
*BoundBarValue
= Env1
.getValue(*BoundBarDecl
);
4438 ASSERT_THAT(BoundBarValue
, NotNull());
4439 EXPECT_TRUE(isa
<IntegerValue
>(BoundBarValue
));
4441 // Test that a `DeclRefExpr` to a `BindingDecl` works as expected.
4442 EXPECT_EQ(Env1
.getValue(*BazDecl
), BoundFooValue
);
4444 const Environment
&Env2
= getEnvironmentAtAnnotation(Results
, "p2");
4446 // Test that `BoundFooDecl` retains the value we expect, after the join.
4447 BoundFooValue
= Env2
.getValue(*BoundFooDecl
);
4448 EXPECT_EQ(Env2
.getValue(*BazDecl
), BoundFooValue
);
4452 TEST(TransferTest
, StructuredBindingAssignRefFromTupleLikeType
) {
4453 std::string Code
= R
"(
4456 template <class> struct tuple_size;
4457 template <std::size_t, class> struct tuple_element;
4458 template <class...> class tuple;
4461 template <class T, T v>
4462 struct size_helper { static const T value = v; };
4465 template <class... T>
4466 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {};
4468 template <std::size_t I, class... T>
4469 struct tuple_element<I, tuple<T...>> {
4470 using type = __type_pack_element<I, T...>;
4473 template <class...> class tuple {};
4475 template <std::size_t I, class... T>
4476 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
4479 std::tuple<bool, int> &getTuple();
4481 void target(bool B) {
4482 auto &[BoundFoo, BoundBar] = getTuple();
4484 // Include if-then-else to test interaction of `BindingDecl` with join.
4498 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4499 ASTContext
&ASTCtx
) {
4500 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p1", "p2"));
4501 const Environment
&Env1
= getEnvironmentAtAnnotation(Results
, "p1");
4503 const ValueDecl
*BoundFooDecl
= findValueDecl(ASTCtx
, "BoundFoo");
4504 ASSERT_THAT(BoundFooDecl
, NotNull());
4506 const ValueDecl
*BoundBarDecl
= findValueDecl(ASTCtx
, "BoundBar");
4507 ASSERT_THAT(BoundBarDecl
, NotNull());
4509 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
4510 ASSERT_THAT(BazDecl
, NotNull());
4512 const Value
*BoundFooValue
= Env1
.getValue(*BoundFooDecl
);
4513 ASSERT_THAT(BoundFooValue
, NotNull());
4514 EXPECT_TRUE(isa
<BoolValue
>(BoundFooValue
));
4516 const Value
*BoundBarValue
= Env1
.getValue(*BoundBarDecl
);
4517 ASSERT_THAT(BoundBarValue
, NotNull());
4518 EXPECT_TRUE(isa
<IntegerValue
>(BoundBarValue
));
4520 // Test that a `DeclRefExpr` to a `BindingDecl` (with reference type)
4521 // works as expected. We don't test aliasing properties of the
4522 // reference, because we don't model `std::get` and so have no way to
4523 // equate separate references into the tuple.
4524 EXPECT_EQ(Env1
.getValue(*BazDecl
), BoundFooValue
);
4526 const Environment
&Env2
= getEnvironmentAtAnnotation(Results
, "p2");
4528 // Test that `BoundFooDecl` retains the value we expect, after the join.
4529 BoundFooValue
= Env2
.getValue(*BoundFooDecl
);
4530 EXPECT_EQ(Env2
.getValue(*BazDecl
), BoundFooValue
);
4534 TEST(TransferTest
, BinaryOperatorComma
) {
4535 std::string Code
= R
"(
4536 void target(int Foo, int Bar) {
4537 int &Baz = (Foo, Bar);
4543 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4544 ASTContext
&ASTCtx
) {
4545 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4546 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4548 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4549 ASSERT_THAT(BarDecl
, NotNull());
4551 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
4552 ASSERT_THAT(BazDecl
, NotNull());
4554 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
4555 ASSERT_THAT(BarLoc
, NotNull());
4557 const StorageLocation
*BazLoc
= Env
.getStorageLocation(*BazDecl
);
4558 EXPECT_EQ(BazLoc
, BarLoc
);
4562 TEST(TransferTest
, IfStmtBranchExtendsFlowCondition
) {
4563 std::string Code
= R
"(
4564 void target(bool Foo) {
4576 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4577 ASTContext
&ASTCtx
) {
4578 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("if_then", "if_else"));
4579 const Environment
&ThenEnv
=
4580 getEnvironmentAtAnnotation(Results
, "if_then");
4581 const Environment
&ElseEnv
=
4582 getEnvironmentAtAnnotation(Results
, "if_else");
4584 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4585 ASSERT_THAT(FooDecl
, NotNull());
4587 auto &ThenFooVal
= getFormula(*FooDecl
, ThenEnv
);
4588 EXPECT_TRUE(ThenEnv
.proves(ThenFooVal
));
4590 auto &ElseFooVal
= getFormula(*FooDecl
, ElseEnv
);
4591 EXPECT_TRUE(ElseEnv
.proves(ElseEnv
.arena().makeNot(ElseFooVal
)));
4595 TEST(TransferTest
, WhileStmtBranchExtendsFlowCondition
) {
4596 std::string Code
= R
"(
4597 void target(bool Foo) {
4608 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4609 ASTContext
&ASTCtx
) {
4610 ASSERT_THAT(Results
.keys(),
4611 UnorderedElementsAre("loop_body", "after_loop"));
4612 const Environment
&LoopBodyEnv
=
4613 getEnvironmentAtAnnotation(Results
, "loop_body");
4614 const Environment
&AfterLoopEnv
=
4615 getEnvironmentAtAnnotation(Results
, "after_loop");
4617 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4618 ASSERT_THAT(FooDecl
, NotNull());
4620 auto &LoopBodyFooVal
= getFormula(*FooDecl
, LoopBodyEnv
);
4621 EXPECT_TRUE(LoopBodyEnv
.proves(LoopBodyFooVal
));
4623 auto &AfterLoopFooVal
= getFormula(*FooDecl
, AfterLoopEnv
);
4625 AfterLoopEnv
.proves(AfterLoopEnv
.arena().makeNot(AfterLoopFooVal
)));
4629 TEST(TransferTest
, DoWhileStmtBranchExtendsFlowCondition
) {
4630 std::string Code
= R
"(
4631 void target(bool Foo) {
4644 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4645 ASTContext
&ASTCtx
) {
4646 ASSERT_THAT(Results
.keys(),
4647 UnorderedElementsAre("loop_body", "after_loop"));
4648 const Environment
&LoopBodyEnv
=
4649 getEnvironmentAtAnnotation(Results
, "loop_body");
4650 const Environment
&AfterLoopEnv
=
4651 getEnvironmentAtAnnotation(Results
, "after_loop");
4652 auto &A
= AfterLoopEnv
.arena();
4654 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4655 ASSERT_THAT(FooDecl
, NotNull());
4657 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4658 ASSERT_THAT(BarDecl
, NotNull());
4660 auto &LoopBodyFooVal
= getFormula(*FooDecl
, LoopBodyEnv
);
4661 auto &LoopBodyBarVal
= getFormula(*BarDecl
, LoopBodyEnv
);
4663 LoopBodyEnv
.proves(A
.makeOr(LoopBodyBarVal
, LoopBodyFooVal
)));
4665 auto &AfterLoopFooVal
= getFormula(*FooDecl
, AfterLoopEnv
);
4666 auto &AfterLoopBarVal
= getFormula(*BarDecl
, AfterLoopEnv
);
4667 EXPECT_TRUE(AfterLoopEnv
.proves(A
.makeNot(AfterLoopFooVal
)));
4668 EXPECT_TRUE(AfterLoopEnv
.proves(A
.makeNot(AfterLoopBarVal
)));
4672 TEST(TransferTest
, ForStmtBranchExtendsFlowCondition
) {
4673 std::string Code
= R
"(
4674 void target(bool Foo) {
4685 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4686 ASTContext
&ASTCtx
) {
4687 ASSERT_THAT(Results
.keys(),
4688 UnorderedElementsAre("loop_body", "after_loop"));
4689 const Environment
&LoopBodyEnv
=
4690 getEnvironmentAtAnnotation(Results
, "loop_body");
4691 const Environment
&AfterLoopEnv
=
4692 getEnvironmentAtAnnotation(Results
, "after_loop");
4694 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4695 ASSERT_THAT(FooDecl
, NotNull());
4697 auto &LoopBodyFooVal
= getFormula(*FooDecl
, LoopBodyEnv
);
4698 EXPECT_TRUE(LoopBodyEnv
.proves(LoopBodyFooVal
));
4700 auto &AfterLoopFooVal
= getFormula(*FooDecl
, AfterLoopEnv
);
4702 AfterLoopEnv
.proves(AfterLoopEnv
.arena().makeNot(AfterLoopFooVal
)));
4706 TEST(TransferTest
, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition
) {
4707 std::string Code
= R
"(
4708 void target(bool Foo) {
4717 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4718 ASTContext
&ASTCtx
) {
4719 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("loop_body"));
4720 const Environment
&LoopBodyEnv
=
4721 getEnvironmentAtAnnotation(Results
, "loop_body");
4723 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4724 ASSERT_THAT(FooDecl
, NotNull());
4726 auto &LoopBodyFooVal
= getFormula(*FooDecl
, LoopBodyEnv
);
4727 EXPECT_FALSE(LoopBodyEnv
.proves(LoopBodyFooVal
));
4731 TEST(TransferTest
, ContextSensitiveOptionDisabled
) {
4732 std::string Code
= R
"(
4734 void SetBool(bool &Var) { Var = true; }
4737 bool Foo = GiveBool();
4744 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4745 ASTContext
&ASTCtx
) {
4746 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4747 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4749 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4750 ASSERT_THAT(FooDecl
, NotNull());
4752 auto &FooVal
= getFormula(*FooDecl
, Env
);
4753 EXPECT_FALSE(Env
.proves(FooVal
));
4754 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(FooVal
)));
4756 {BuiltinOptions
{/*.ContextSensitiveOpts=*/std::nullopt
}});
4759 TEST(TransferTest
, ContextSensitiveReturnReference
) {
4760 std::string Code
= R
"(
4762 S& target(bool b, S &s) {
4769 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4770 ASTContext
&ASTCtx
) {
4771 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4773 const ValueDecl
*SDecl
= findValueDecl(ASTCtx
, "s");
4774 ASSERT_THAT(SDecl
, NotNull());
4776 auto *SLoc
= Env
.getStorageLocation(*SDecl
);
4777 ASSERT_THAT(SLoc
, NotNull());
4779 ASSERT_THAT(Env
.getReturnStorageLocation(), Eq(SLoc
));
4781 {BuiltinOptions
{ContextSensitiveOptions
{}}});
4784 // This test is a regression test, based on a real crash.
4785 TEST(TransferTest
, ContextSensitiveReturnReferenceWithConditionalOperator
) {
4786 std::string Code
= R
"(
4788 S& target(bool b, S &s) {
4795 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4796 ASTContext
&ASTCtx
) {
4797 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4798 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4800 const ValueDecl
*SDecl
= findValueDecl(ASTCtx
, "s");
4801 ASSERT_THAT(SDecl
, NotNull());
4803 auto *SLoc
= Env
.getStorageLocation(*SDecl
);
4804 ASSERT_THAT(SLoc
, NotNull());
4805 EXPECT_THAT(Env
.getValue(*SLoc
), NotNull());
4807 auto *Loc
= Env
.getReturnStorageLocation();
4808 ASSERT_THAT(Loc
, NotNull());
4809 EXPECT_THAT(Env
.getValue(*Loc
), NotNull());
4811 // TODO: We would really like to make this stronger assertion, but that
4812 // doesn't work because we don't propagate values correctly through
4813 // the conditional operator yet.
4814 // ASSERT_THAT(Loc, Eq(SLoc));
4816 {BuiltinOptions
{ContextSensitiveOptions
{}}});
4819 TEST(TransferTest
, ContextSensitiveReturnOneOfTwoReferences
) {
4820 std::string Code
= R
"(
4822 S &callee(bool b, S &s1_parm, S &s2_parm) {
4828 void target(bool b) {
4833 S &return_dont_know = callee(b, s1, s2);
4839 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4840 ASTContext
&ASTCtx
) {
4841 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4843 const ValueDecl
*S1
= findValueDecl(ASTCtx
, "s1");
4844 ASSERT_THAT(S1
, NotNull());
4845 const ValueDecl
*S2
= findValueDecl(ASTCtx
, "s2");
4846 ASSERT_THAT(S2
, NotNull());
4847 const ValueDecl
*ReturnS1
= findValueDecl(ASTCtx
, "return_s1");
4848 ASSERT_THAT(ReturnS1
, NotNull());
4849 const ValueDecl
*ReturnS2
= findValueDecl(ASTCtx
, "return_s2");
4850 ASSERT_THAT(ReturnS2
, NotNull());
4851 const ValueDecl
*ReturnDontKnow
=
4852 findValueDecl(ASTCtx
, "return_dont_know");
4853 ASSERT_THAT(ReturnDontKnow
, NotNull());
4855 StorageLocation
*S1Loc
= Env
.getStorageLocation(*S1
);
4856 StorageLocation
*S2Loc
= Env
.getStorageLocation(*S2
);
4858 EXPECT_THAT(Env
.getStorageLocation(*ReturnS1
), Eq(S1Loc
));
4859 EXPECT_THAT(Env
.getStorageLocation(*ReturnS2
), Eq(S2Loc
));
4861 // In the case where we don't have a consistent storage location for
4862 // the return value, the framework creates a new storage location, which
4863 // should be different from the storage locations of `s1` and `s2`.
4864 EXPECT_THAT(Env
.getStorageLocation(*ReturnDontKnow
), Ne(S1Loc
));
4865 EXPECT_THAT(Env
.getStorageLocation(*ReturnDontKnow
), Ne(S2Loc
));
4867 {BuiltinOptions
{ContextSensitiveOptions
{}}});
4870 TEST(TransferTest
, ContextSensitiveDepthZero
) {
4871 std::string Code
= R
"(
4873 void SetBool(bool &Var) { Var = true; }
4876 bool Foo = GiveBool();
4883 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4884 ASTContext
&ASTCtx
) {
4885 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4886 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4888 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4889 ASSERT_THAT(FooDecl
, NotNull());
4891 auto &FooVal
= getFormula(*FooDecl
, Env
);
4892 EXPECT_FALSE(Env
.proves(FooVal
));
4893 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(FooVal
)));
4895 {BuiltinOptions
{ContextSensitiveOptions
{/*.Depth=*/0}}});
4898 TEST(TransferTest
, ContextSensitiveSetTrue
) {
4899 std::string Code
= R
"(
4901 void SetBool(bool &Var) { Var = true; }
4904 bool Foo = GiveBool();
4911 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4912 ASTContext
&ASTCtx
) {
4913 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4914 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4916 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4917 ASSERT_THAT(FooDecl
, NotNull());
4919 auto &FooVal
= getFormula(*FooDecl
, Env
);
4920 EXPECT_TRUE(Env
.proves(FooVal
));
4922 {BuiltinOptions
{ContextSensitiveOptions
{}}});
4925 TEST(TransferTest
, ContextSensitiveSetFalse
) {
4926 std::string Code
= R
"(
4928 void SetBool(bool &Var) { Var = false; }
4931 bool Foo = GiveBool();
4938 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4939 ASTContext
&ASTCtx
) {
4940 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4941 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4943 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4944 ASSERT_THAT(FooDecl
, NotNull());
4946 auto &FooVal
= getFormula(*FooDecl
, Env
);
4947 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(FooVal
)));
4949 {BuiltinOptions
{ContextSensitiveOptions
{}}});
4952 TEST(TransferTest
, ContextSensitiveSetBothTrueAndFalse
) {
4953 std::string Code
= R
"(
4955 void SetBool(bool &Var, bool Val) { Var = Val; }
4958 bool Foo = GiveBool();
4959 bool Bar = GiveBool();
4961 SetBool(Bar, false);
4967 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4968 ASTContext
&ASTCtx
) {
4969 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4970 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4971 auto &A
= Env
.arena();
4973 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4974 ASSERT_THAT(FooDecl
, NotNull());
4976 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4977 ASSERT_THAT(BarDecl
, NotNull());
4979 auto &FooVal
= getFormula(*FooDecl
, Env
);
4980 EXPECT_TRUE(Env
.proves(FooVal
));
4981 EXPECT_FALSE(Env
.proves(A
.makeNot(FooVal
)));
4983 auto &BarVal
= getFormula(*BarDecl
, Env
);
4984 EXPECT_FALSE(Env
.proves(BarVal
));
4985 EXPECT_TRUE(Env
.proves(A
.makeNot(BarVal
)));
4987 {BuiltinOptions
{ContextSensitiveOptions
{}}});
4990 TEST(TransferTest
, ContextSensitiveSetTwoLayersDepthOne
) {
4991 std::string Code
= R
"(
4993 void SetBool1(bool &Var) { Var = true; }
4994 void SetBool2(bool &Var) { SetBool1(Var); }
4997 bool Foo = GiveBool();
5004 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5005 ASTContext
&ASTCtx
) {
5006 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5007 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5009 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5010 ASSERT_THAT(FooDecl
, NotNull());
5012 auto &FooVal
= getFormula(*FooDecl
, Env
);
5013 EXPECT_FALSE(Env
.proves(FooVal
));
5014 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(FooVal
)));
5016 {BuiltinOptions
{ContextSensitiveOptions
{/*.Depth=*/1}}});
5019 TEST(TransferTest
, ContextSensitiveSetTwoLayersDepthTwo
) {
5020 std::string Code
= R
"(
5022 void SetBool1(bool &Var) { Var = true; }
5023 void SetBool2(bool &Var) { SetBool1(Var); }
5026 bool Foo = GiveBool();
5033 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5034 ASTContext
&ASTCtx
) {
5035 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5036 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5038 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5039 ASSERT_THAT(FooDecl
, NotNull());
5041 auto &FooVal
= getFormula(*FooDecl
, Env
);
5042 EXPECT_TRUE(Env
.proves(FooVal
));
5044 {BuiltinOptions
{ContextSensitiveOptions
{/*.Depth=*/2}}});
5047 TEST(TransferTest
, ContextSensitiveSetThreeLayersDepthTwo
) {
5048 std::string Code
= R
"(
5050 void SetBool1(bool &Var) { Var = true; }
5051 void SetBool2(bool &Var) { SetBool1(Var); }
5052 void SetBool3(bool &Var) { SetBool2(Var); }
5055 bool Foo = GiveBool();
5062 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5063 ASTContext
&ASTCtx
) {
5064 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5065 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5067 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5068 ASSERT_THAT(FooDecl
, NotNull());
5070 auto &FooVal
= getFormula(*FooDecl
, Env
);
5071 EXPECT_FALSE(Env
.proves(FooVal
));
5072 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(FooVal
)));
5074 {BuiltinOptions
{ContextSensitiveOptions
{/*.Depth=*/2}}});
5077 TEST(TransferTest
, ContextSensitiveSetThreeLayersDepthThree
) {
5078 std::string Code
= R
"(
5080 void SetBool1(bool &Var) { Var = true; }
5081 void SetBool2(bool &Var) { SetBool1(Var); }
5082 void SetBool3(bool &Var) { SetBool2(Var); }
5085 bool Foo = GiveBool();
5092 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5093 ASTContext
&ASTCtx
) {
5094 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5095 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5097 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5098 ASSERT_THAT(FooDecl
, NotNull());
5100 auto &FooVal
= getFormula(*FooDecl
, Env
);
5101 EXPECT_TRUE(Env
.proves(FooVal
));
5103 {BuiltinOptions
{ContextSensitiveOptions
{/*.Depth=*/3}}});
5106 TEST(TransferTest
, ContextSensitiveMutualRecursion
) {
5107 std::string Code
= R
"(
5108 bool Pong(bool X, bool Y);
5110 bool Ping(bool X, bool Y) {
5118 bool Pong(bool X, bool Y) {
5127 bool Foo = Ping(false, false);
5133 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5134 ASTContext
&ASTCtx
) {
5135 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5136 // The analysis doesn't crash...
5137 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5139 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5140 ASSERT_THAT(FooDecl
, NotNull());
5142 auto &FooVal
= getFormula(*FooDecl
, Env
);
5143 // ... but it also can't prove anything here.
5144 EXPECT_FALSE(Env
.proves(FooVal
));
5145 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(FooVal
)));
5147 {BuiltinOptions
{ContextSensitiveOptions
{/*.Depth=*/4}}});
5150 TEST(TransferTest
, ContextSensitiveSetMultipleLines
) {
5151 std::string Code
= R
"(
5152 void SetBools(bool &Var1, bool &Var2) {
5166 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5167 ASTContext
&ASTCtx
) {
5168 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5169 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5171 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5172 ASSERT_THAT(FooDecl
, NotNull());
5174 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
5175 ASSERT_THAT(BarDecl
, NotNull());
5177 auto &FooVal
= getFormula(*FooDecl
, Env
);
5178 EXPECT_TRUE(Env
.proves(FooVal
));
5179 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(FooVal
)));
5181 auto &BarVal
= getFormula(*BarDecl
, Env
);
5182 EXPECT_FALSE(Env
.proves(BarVal
));
5183 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(BarVal
)));
5185 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5188 TEST(TransferTest
, ContextSensitiveSetMultipleBlocks
) {
5189 std::string Code
= R
"(
5190 void IfCond(bool Cond, bool &Then, bool &Else) {
5202 IfCond(Foo, Bar, Baz);
5208 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5209 ASTContext
&ASTCtx
) {
5210 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5211 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5213 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
5214 ASSERT_THAT(BarDecl
, NotNull());
5216 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
5217 ASSERT_THAT(BazDecl
, NotNull());
5219 auto &BarVal
= getFormula(*BarDecl
, Env
);
5220 EXPECT_FALSE(Env
.proves(BarVal
));
5221 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(BarVal
)));
5223 auto &BazVal
= getFormula(*BazDecl
, Env
);
5224 EXPECT_TRUE(Env
.proves(BazVal
));
5225 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(BazVal
)));
5227 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5230 TEST(TransferTest
, ContextSensitiveReturnVoid
) {
5231 std::string Code
= R
"(
5232 void Noop() { return; }
5241 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5242 ASTContext
&ASTCtx
) {
5243 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5244 // This just tests that the analysis doesn't crash.
5246 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5249 TEST(TransferTest
, ContextSensitiveReturnTrue
) {
5250 std::string Code
= R
"(
5251 bool GiveBool() { return true; }
5254 bool Foo = GiveBool();
5260 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5261 ASTContext
&ASTCtx
) {
5262 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5263 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5265 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5266 ASSERT_THAT(FooDecl
, NotNull());
5268 auto &FooVal
= getFormula(*FooDecl
, Env
);
5269 EXPECT_TRUE(Env
.proves(FooVal
));
5271 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5274 TEST(TransferTest
, ContextSensitiveReturnFalse
) {
5275 std::string Code
= R
"(
5276 bool GiveBool() { return false; }
5279 bool Foo = GiveBool();
5285 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5286 ASTContext
&ASTCtx
) {
5287 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5288 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5290 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5291 ASSERT_THAT(FooDecl
, NotNull());
5293 auto &FooVal
= getFormula(*FooDecl
, Env
);
5294 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(FooVal
)));
5296 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5299 TEST(TransferTest
, ContextSensitiveReturnArg
) {
5300 std::string Code
= R
"(
5302 bool GiveBack(bool Arg) { return Arg; }
5305 bool Foo = GiveBool();
5306 bool Bar = GiveBack(Foo);
5307 bool Baz = Foo == Bar;
5313 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5314 ASTContext
&ASTCtx
) {
5315 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5316 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5318 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
5319 ASSERT_THAT(BazDecl
, NotNull());
5321 auto &BazVal
= getFormula(*BazDecl
, Env
);
5322 EXPECT_TRUE(Env
.proves(BazVal
));
5324 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5327 TEST(TransferTest
, ContextSensitiveReturnInt
) {
5328 std::string Code
= R
"(
5329 int identity(int x) { return x; }
5332 int y = identity(42);
5338 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5339 ASTContext
&ASTCtx
) {
5340 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5341 // This just tests that the analysis doesn't crash.
5343 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5346 TEST(TransferTest
, ContextSensitiveMethodLiteral
) {
5347 std::string Code
= R
"(
5350 bool giveBool() { return true; }
5355 bool Foo = MyObj.giveBool();
5361 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5362 ASTContext
&ASTCtx
) {
5363 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5364 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5366 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5367 ASSERT_THAT(FooDecl
, NotNull());
5369 auto &FooVal
= getFormula(*FooDecl
, Env
);
5370 EXPECT_TRUE(Env
.proves(FooVal
));
5372 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5375 TEST(TransferTest
, ContextSensitiveMethodGetter
) {
5376 std::string Code
= R
"(
5379 bool getField() { return Field; }
5387 bool Foo = MyObj.getField();
5393 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5394 ASTContext
&ASTCtx
) {
5395 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5396 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5398 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5399 ASSERT_THAT(FooDecl
, NotNull());
5401 auto &FooVal
= getFormula(*FooDecl
, Env
);
5402 EXPECT_TRUE(Env
.proves(FooVal
));
5404 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5407 TEST(TransferTest
, ContextSensitiveMethodSetter
) {
5408 std::string Code
= R
"(
5411 void setField(bool Val) { Field = Val; }
5418 MyObj.setField(true);
5419 bool Foo = MyObj.Field;
5425 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5426 ASTContext
&ASTCtx
) {
5427 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5428 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5430 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5431 ASSERT_THAT(FooDecl
, NotNull());
5433 auto &FooVal
= getFormula(*FooDecl
, Env
);
5434 EXPECT_TRUE(Env
.proves(FooVal
));
5436 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5439 TEST(TransferTest
, ContextSensitiveMethodGetterAndSetter
) {
5440 std::string Code
= R
"(
5443 bool getField() { return Field; }
5444 void setField(bool Val) { Field = Val; }
5452 MyObj.setField(true);
5453 bool Foo = MyObj.getField();
5459 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5460 ASTContext
&ASTCtx
) {
5461 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5462 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5464 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5465 ASSERT_THAT(FooDecl
, NotNull());
5467 auto &FooVal
= getFormula(*FooDecl
, Env
);
5468 EXPECT_TRUE(Env
.proves(FooVal
));
5470 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5474 TEST(TransferTest
, ContextSensitiveMethodTwoLayersVoid
) {
5475 std::string Code
= R
"(
5478 void Inner() { MyField = true; }
5479 void Outer() { Inner(); }
5487 bool Foo = MyObj.MyField;
5493 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5494 ASTContext
&ASTCtx
) {
5495 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5497 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5499 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5500 ASSERT_THAT(FooDecl
, NotNull());
5502 auto &FooVal
= getFormula(*FooDecl
, Env
);
5503 EXPECT_TRUE(Env
.proves(FooVal
));
5505 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5508 TEST(TransferTest
, ContextSensitiveMethodTwoLayersReturn
) {
5509 std::string Code
= R
"(
5512 bool Inner() { return MyField; }
5513 bool Outer() { return Inner(); }
5520 MyObj.MyField = true;
5521 bool Foo = MyObj.Outer();
5527 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5528 ASTContext
&ASTCtx
) {
5529 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5531 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5533 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5534 ASSERT_THAT(FooDecl
, NotNull());
5536 auto &FooVal
= getFormula(*FooDecl
, Env
);
5537 EXPECT_TRUE(Env
.proves(FooVal
));
5539 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5542 TEST(TransferTest
, ContextSensitiveConstructorBody
) {
5543 std::string Code
= R
"(
5546 MyClass() { MyField = true; }
5553 bool Foo = MyObj.MyField;
5559 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5560 ASTContext
&ASTCtx
) {
5561 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5562 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5564 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5565 ASSERT_THAT(FooDecl
, NotNull());
5567 auto &FooVal
= getFormula(*FooDecl
, Env
);
5568 EXPECT_TRUE(Env
.proves(FooVal
));
5570 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5573 TEST(TransferTest
, ContextSensitiveConstructorInitializer
) {
5574 std::string Code
= R
"(
5577 MyClass() : MyField(true) {}
5584 bool Foo = MyObj.MyField;
5590 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5591 ASTContext
&ASTCtx
) {
5592 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5593 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5595 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5596 ASSERT_THAT(FooDecl
, NotNull());
5598 auto &FooVal
= getFormula(*FooDecl
, Env
);
5599 EXPECT_TRUE(Env
.proves(FooVal
));
5601 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5604 TEST(TransferTest
, ContextSensitiveConstructorDefault
) {
5605 std::string Code
= R
"(
5608 MyClass() = default;
5610 bool MyField = true;
5615 bool Foo = MyObj.MyField;
5621 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5622 ASTContext
&ASTCtx
) {
5623 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5624 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5626 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5627 ASSERT_THAT(FooDecl
, NotNull());
5629 auto &FooVal
= getFormula(*FooDecl
, Env
);
5630 EXPECT_TRUE(Env
.proves(FooVal
));
5632 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5635 TEST(TransferTest
, ContextSensitiveSelfReferentialClass
) {
5636 // Test that the `this` pointer seen in the constructor has the same value
5637 // as the address of the variable the object is constructed into.
5638 std::string Code
= R
"(
5641 MyClass() : Self(this) {}
5647 MyClass *SelfPtr = MyObj.Self;
5653 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5654 ASTContext
&ASTCtx
) {
5655 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5657 const ValueDecl
*MyObjDecl
= findValueDecl(ASTCtx
, "MyObj");
5658 ASSERT_THAT(MyObjDecl
, NotNull());
5660 const ValueDecl
*SelfDecl
= findValueDecl(ASTCtx
, "SelfPtr");
5661 ASSERT_THAT(SelfDecl
, NotNull());
5663 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5664 auto &SelfVal
= *cast
<PointerValue
>(Env
.getValue(*SelfDecl
));
5665 EXPECT_EQ(Env
.getStorageLocation(*MyObjDecl
), &SelfVal
.getPointeeLoc());
5667 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5670 TEST(TransferTest
, UnnamedBitfieldInitializer
) {
5671 std::string Code
= R
"(
5687 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5688 ASTContext
&ASTCtx
) {
5689 // This doesn't need a body because this test was crashing the framework
5690 // before handling correctly Unnamed bitfields in `InitListExpr`.
5694 // Repro for a crash that used to occur with chained short-circuiting logical
5696 TEST(TransferTest
, ChainedLogicalOps
) {
5697 std::string Code
= R
"(
5699 bool b = true || false || false || false;
5706 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5707 ASTContext
&ASTCtx
) {
5708 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5709 auto &B
= getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "b").formula();
5710 EXPECT_TRUE(Env
.proves(B
));
5714 // Repro for a crash that used to occur when we call a `noreturn` function
5715 // within one of the operands of a `&&` or `||` operator.
5716 TEST(TransferTest
, NoReturnFunctionInsideShortCircuitedBooleanOp
) {
5717 std::string Code
= R
"(
5718 __attribute__((noreturn)) int doesnt_return();
5719 bool some_condition();
5720 void target(bool b1, bool b2) {
5721 // Neither of these should crash. In addition, if we don't terminate the
5722 // program, we know that the operators need to trigger the short-circuit
5723 // logic, so `NoreturnOnRhsOfAnd` will be false and `NoreturnOnRhsOfOr`
5725 bool NoreturnOnRhsOfAnd = b1 && doesnt_return() > 0;
5726 bool NoreturnOnRhsOfOr = b2 || doesnt_return() > 0;
5728 // Calling a `noreturn` function on the LHS of an `&&` or `||` makes the
5729 // entire expression unreachable. So we know that in both of the following
5730 // cases, if `target()` terminates, the `else` branch was taken.
5731 bool NoreturnOnLhsMakesAndUnreachable = false;
5732 if (some_condition())
5733 doesnt_return() > 0 && some_condition();
5735 NoreturnOnLhsMakesAndUnreachable = true;
5737 bool NoreturnOnLhsMakesOrUnreachable = false;
5738 if (some_condition())
5739 doesnt_return() > 0 || some_condition();
5741 NoreturnOnLhsMakesOrUnreachable = true;
5748 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5749 ASTContext
&ASTCtx
) {
5750 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5751 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5752 auto &A
= Env
.arena();
5754 // Check that [[p]] is reachable with a non-false flow condition.
5755 EXPECT_FALSE(Env
.proves(A
.makeLiteral(false)));
5757 auto &B1
= getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "b1").formula();
5758 EXPECT_TRUE(Env
.proves(A
.makeNot(B1
)));
5760 auto &NoreturnOnRhsOfAnd
=
5761 getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "NoreturnOnRhsOfAnd").formula();
5762 EXPECT_TRUE(Env
.proves(A
.makeNot(NoreturnOnRhsOfAnd
)));
5764 auto &B2
= getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "b2").formula();
5765 EXPECT_TRUE(Env
.proves(B2
));
5767 auto &NoreturnOnRhsOfOr
=
5768 getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "NoreturnOnRhsOfOr")
5770 EXPECT_TRUE(Env
.proves(NoreturnOnRhsOfOr
));
5772 auto &NoreturnOnLhsMakesAndUnreachable
= getValueForDecl
<BoolValue
>(
5773 ASTCtx
, Env
, "NoreturnOnLhsMakesAndUnreachable").formula();
5774 EXPECT_TRUE(Env
.proves(NoreturnOnLhsMakesAndUnreachable
));
5776 auto &NoreturnOnLhsMakesOrUnreachable
= getValueForDecl
<BoolValue
>(
5777 ASTCtx
, Env
, "NoreturnOnLhsMakesOrUnreachable").formula();
5778 EXPECT_TRUE(Env
.proves(NoreturnOnLhsMakesOrUnreachable
));
5782 TEST(TransferTest
, NewExpressions
) {
5783 std::string Code
= R
"(
5785 int *p = new int(42);
5791 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5792 ASTContext
&ASTCtx
) {
5793 const Environment
&Env
=
5794 getEnvironmentAtAnnotation(Results
, "after_new");
5796 auto &P
= getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "p");
5798 EXPECT_THAT(Env
.getValue(P
.getPointeeLoc()), NotNull());
5802 TEST(TransferTest
, NewExpressions_Structs
) {
5803 std::string Code
= R
"(
5813 Outer *p = new Outer;
5814 // Access the fields to make sure the analysis actually generates children
5815 // for them in the `RecordStorageLocation` and `RecordValue`.
5816 p->OuterField.InnerField;
5822 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5823 ASTContext
&ASTCtx
) {
5824 const Environment
&Env
=
5825 getEnvironmentAtAnnotation(Results
, "after_new");
5827 const ValueDecl
*OuterField
= findValueDecl(ASTCtx
, "OuterField");
5828 const ValueDecl
*InnerField
= findValueDecl(ASTCtx
, "InnerField");
5830 auto &P
= getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "p");
5832 auto &OuterLoc
= cast
<RecordStorageLocation
>(P
.getPointeeLoc());
5833 auto &OuterFieldLoc
=
5834 *cast
<RecordStorageLocation
>(OuterLoc
.getChild(*OuterField
));
5835 auto &InnerFieldLoc
= *OuterFieldLoc
.getChild(*InnerField
);
5837 // Values for the struct and all fields exist after the new.
5838 EXPECT_THAT(Env
.getValue(OuterLoc
), NotNull());
5839 EXPECT_THAT(Env
.getValue(OuterFieldLoc
), NotNull());
5840 EXPECT_THAT(Env
.getValue(InnerFieldLoc
), NotNull());
5844 TEST(TransferTest
, FunctionToPointerDecayHasValue
) {
5845 std::string Code
= R
"(
5846 struct A { static void static_member_func(); };
5848 // To check that we're treating function-to-pointer decay correctly,
5849 // create two pointers, then verify they refer to the same storage
5851 // We need to do the test this way because even if an initializer (in this
5852 // case, the function-to-pointer decay) does not create a value, we still
5853 // create a value for the variable.
5854 void (*non_member_p1)() = target;
5855 void (*non_member_p2)() = target;
5857 // Do the same thing but for a static member function.
5858 void (*member_p1)() = A::static_member_func;
5859 void (*member_p2)() = A::static_member_func;
5865 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5866 ASTContext
&ASTCtx
) {
5867 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5870 getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "non_member_p1");
5872 getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "non_member_p2");
5873 EXPECT_EQ(&NonMemberP1
.getPointeeLoc(), &NonMemberP2
.getPointeeLoc());
5876 getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "member_p1");
5878 getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "member_p2");
5879 EXPECT_EQ(&MemberP1
.getPointeeLoc(), &MemberP2
.getPointeeLoc());
5883 // Check that a builtin function is not associated with a value. (It's only
5884 // possible to call builtin functions directly, not take their address.)
5885 TEST(TransferTest
, BuiltinFunctionModeled
) {
5886 std::string Code
= R
"(
5888 __builtin_expect(0, 0);
5894 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5895 ASTContext
&ASTCtx
) {
5896 using ast_matchers::selectFirst
;
5897 using ast_matchers::match
;
5898 using ast_matchers::traverse
;
5899 using ast_matchers::implicitCastExpr
;
5900 using ast_matchers::hasCastKind
;
5902 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5904 auto *ImplicitCast
= selectFirst
<ImplicitCastExpr
>(
5906 match(traverse(TK_AsIs
,
5907 implicitCastExpr(hasCastKind(CK_BuiltinFnToFnPtr
))
5908 .bind("implicit_cast")),
5911 ASSERT_THAT(ImplicitCast
, NotNull());
5912 EXPECT_THAT(Env
.getValue(*ImplicitCast
), IsNull());
5916 // Check that a callee of a member operator call is modeled as a `PointerValue`.
5917 // Member operator calls are unusual in that their callee is a pointer that
5918 // stems from a `FunctionToPointerDecay`. In calls to non-operator non-static
5919 // member functions, the callee is a `MemberExpr` (which does not have pointer
5921 // We want to make sure that we produce a pointer value for the callee in this
5922 // specific scenario and that its storage location is durable (for convergence).
5923 TEST(TransferTest
, MemberOperatorCallModelsPointerForCallee
) {
5924 std::string Code
= R
"(
5926 bool operator!=(S s);
5937 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5938 ASTContext
&ASTCtx
) {
5939 using ast_matchers::selectFirst
;
5940 using ast_matchers::match
;
5941 using ast_matchers::traverse
;
5942 using ast_matchers::cxxOperatorCallExpr
;
5944 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5946 auto Matches
= match(
5947 traverse(TK_AsIs
, cxxOperatorCallExpr().bind("call")), ASTCtx
);
5949 ASSERT_EQ(Matches
.size(), 2UL);
5951 auto *Call1
= Matches
[0].getNodeAs
<CXXOperatorCallExpr
>("call");
5952 auto *Call2
= Matches
[1].getNodeAs
<CXXOperatorCallExpr
>("call");
5954 ASSERT_THAT(Call1
, NotNull());
5955 ASSERT_THAT(Call2
, NotNull());
5957 EXPECT_EQ(cast
<ImplicitCastExpr
>(Call1
->getCallee())->getCastKind(),
5958 CK_FunctionToPointerDecay
);
5959 EXPECT_EQ(cast
<ImplicitCastExpr
>(Call2
->getCallee())->getCastKind(),
5960 CK_FunctionToPointerDecay
);
5962 auto *Ptr1
= cast
<PointerValue
>(Env
.getValue(*Call1
->getCallee()));
5963 auto *Ptr2
= cast
<PointerValue
>(Env
.getValue(*Call2
->getCallee()));
5965 ASSERT_EQ(&Ptr1
->getPointeeLoc(), &Ptr2
->getPointeeLoc());
5969 // Check that fields of anonymous records are modeled.
5970 TEST(TransferTest
, AnonymousStruct
) {
5971 std::string Code
= R
"(
5985 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5986 ASTContext
&ASTCtx
) {
5987 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5988 const ValueDecl
*SDecl
= findValueDecl(ASTCtx
, "s");
5989 const ValueDecl
*BDecl
= findValueDecl(ASTCtx
, "b");
5990 const IndirectFieldDecl
*IndirectField
=
5991 findIndirectFieldDecl(ASTCtx
, "b");
5993 auto *S
= cast
<RecordStorageLocation
>(Env
.getStorageLocation(*SDecl
));
5994 auto &AnonStruct
= *cast
<RecordStorageLocation
>(
5995 S
->getChild(*cast
<ValueDecl
>(IndirectField
->chain().front())));
5997 auto *B
= cast
<BoolValue
>(getFieldValue(&AnonStruct
, *BDecl
, Env
));
5998 ASSERT_TRUE(Env
.proves(B
->formula()));
6002 TEST(TransferTest
, AnonymousStructWithInitializer
) {
6003 std::string Code
= R
"(
6016 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6017 ASTContext
&ASTCtx
) {
6018 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6019 const ValueDecl
*BDecl
= findValueDecl(ASTCtx
, "b");
6020 const IndirectFieldDecl
*IndirectField
=
6021 findIndirectFieldDecl(ASTCtx
, "b");
6024 cast
<RecordStorageLocation
>(Env
.getThisPointeeStorageLocation());
6025 auto &AnonStruct
= *cast
<RecordStorageLocation
>(ThisLoc
->getChild(
6026 *cast
<ValueDecl
>(IndirectField
->chain().front())));
6028 auto *B
= cast
<BoolValue
>(getFieldValue(&AnonStruct
, *BDecl
, Env
));
6029 ASSERT_TRUE(Env
.proves(B
->formula()));
6033 TEST(TransferTest
, AnonymousStructWithReferenceField
) {
6034 std::string Code
= R
"(
6048 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6049 ASTContext
&ASTCtx
) {
6050 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6051 const ValueDecl
*GlobalIDecl
= findValueDecl(ASTCtx
, "global_i");
6052 const ValueDecl
*IDecl
= findValueDecl(ASTCtx
, "i");
6053 const IndirectFieldDecl
*IndirectField
=
6054 findIndirectFieldDecl(ASTCtx
, "i");
6057 cast
<RecordStorageLocation
>(Env
.getThisPointeeStorageLocation());
6058 auto &AnonStruct
= *cast
<RecordStorageLocation
>(ThisLoc
->getChild(
6059 *cast
<ValueDecl
>(IndirectField
->chain().front())));
6061 ASSERT_EQ(AnonStruct
.getChild(*IDecl
),
6062 Env
.getStorageLocation(*GlobalIDecl
));
6066 TEST(TransferTest
, EvaluateBlockWithUnreachablePreds
) {
6067 // This is a crash repro.
6068 // `false` block may not have been processed when we try to evaluate the `||`
6069 // after visiting `true`, because it is not necessary (and therefore the edge
6070 // is marked unreachable). Trying to get the analysis state via
6071 // `getEnvironment` for the subexpression still should not crash.
6072 std::string Code
= R
"(
6074 if ((i < 0 && true) || false) {
6082 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6083 ASTContext
&ASTCtx
) {});
6086 TEST(TransferTest
, LambdaCaptureByCopy
) {
6087 std::string Code
= R
"(
6088 void target(int Foo, int Bar) {
6095 runDataflowOnLambda(
6097 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6098 ASTContext
&ASTCtx
) {
6099 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6100 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6102 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6103 ASSERT_THAT(FooDecl
, NotNull());
6105 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
6106 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
6108 const Value
*FooVal
= Env
.getValue(*FooLoc
);
6109 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
6111 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
6112 ASSERT_THAT(BarDecl
, NotNull());
6114 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
6115 EXPECT_THAT(BarLoc
, IsNull());
6119 TEST(TransferTest
, LambdaCaptureByReference
) {
6120 std::string Code
= R
"(
6121 void target(int Foo, int Bar) {
6128 runDataflowOnLambda(
6130 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6131 ASTContext
&ASTCtx
) {
6132 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6133 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6135 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6136 ASSERT_THAT(FooDecl
, NotNull());
6138 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
6139 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
6141 const Value
*FooVal
= Env
.getValue(*FooLoc
);
6142 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
6144 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
6145 ASSERT_THAT(BarDecl
, NotNull());
6147 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
6148 EXPECT_THAT(BarLoc
, IsNull());
6152 TEST(TransferTest
, LambdaCaptureWithInitializer
) {
6153 std::string Code
= R
"(
6154 void target(int Bar) {
6161 runDataflowOnLambda(
6163 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6164 ASTContext
&ASTCtx
) {
6165 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6166 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6168 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6169 ASSERT_THAT(FooDecl
, NotNull());
6171 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
6172 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
6174 const Value
*FooVal
= Env
.getValue(*FooLoc
);
6175 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
6177 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
6178 ASSERT_THAT(BarDecl
, NotNull());
6180 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
6181 EXPECT_THAT(BarLoc
, IsNull());
6185 TEST(TransferTest
, LambdaCaptureByCopyImplicit
) {
6186 std::string Code
= R
"(
6187 void target(int Foo, int Bar) {
6194 runDataflowOnLambda(
6196 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6197 ASTContext
&ASTCtx
) {
6198 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6199 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6201 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6202 ASSERT_THAT(FooDecl
, NotNull());
6204 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
6205 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
6207 const Value
*FooVal
= Env
.getValue(*FooLoc
);
6208 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
6210 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
6211 ASSERT_THAT(BarDecl
, NotNull());
6213 // There is no storage location for `Bar` because it isn't used in the
6214 // body of the lambda.
6215 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
6216 EXPECT_THAT(BarLoc
, IsNull());
6220 TEST(TransferTest
, LambdaCaptureByReferenceImplicit
) {
6221 std::string Code
= R
"(
6222 void target(int Foo, int Bar) {
6229 runDataflowOnLambda(
6231 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6232 ASTContext
&ASTCtx
) {
6233 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6234 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6236 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6237 ASSERT_THAT(FooDecl
, NotNull());
6239 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
6240 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
6242 const Value
*FooVal
= Env
.getValue(*FooLoc
);
6243 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
6245 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
6246 ASSERT_THAT(BarDecl
, NotNull());
6248 // There is no storage location for `Bar` because it isn't used in the
6249 // body of the lambda.
6250 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
6251 EXPECT_THAT(BarLoc
, IsNull());
6255 TEST(TransferTest
, LambdaCaptureThis
) {
6256 std::string Code
= R
"(
6268 runDataflowOnLambda(
6270 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6271 ASTContext
&ASTCtx
) {
6272 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6273 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6275 const RecordStorageLocation
*ThisPointeeLoc
=
6276 Env
.getThisPointeeStorageLocation();
6277 ASSERT_THAT(ThisPointeeLoc
, NotNull());
6279 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6280 ASSERT_THAT(FooDecl
, NotNull());
6282 const StorageLocation
*FooLoc
= ThisPointeeLoc
->getChild(*FooDecl
);
6283 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
6285 const Value
*FooVal
= Env
.getValue(*FooLoc
);
6286 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
6290 TEST(TransferTest
, DifferentReferenceLocInJoin
) {
6291 // This test triggers a case where the storage location for a reference-type
6292 // variable is different for two states being joined. We used to believe this
6293 // could not happen and therefore had an assertion disallowing this; this test
6294 // exists to demonstrate that we can handle this condition without a failing
6295 // assertion. See also the discussion here:
6296 // https://discourse.llvm.org/t/70086/6
6297 std::string Code
= R
"(
6299 template <class T> struct initializer_list {
6305 void target(char* p, char* end) {
6312 auto && range = {1, 2};
6313 for (auto b = range.begin(), e = range.end(); b != e; ++b) {
6322 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6323 ASTContext
&ASTCtx
) {
6324 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6326 // Joining environments with different storage locations for the same
6327 // declaration results in the declaration being removed from the joined
6329 const ValueDecl
*VD
= findValueDecl(ASTCtx
, "range");
6330 ASSERT_EQ(Env
.getStorageLocation(*VD
), nullptr);