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/NoopAnalysis.h"
16 #include "clang/Analysis/FlowSensitive/RecordOps.h"
17 #include "clang/Analysis/FlowSensitive/StorageLocation.h"
18 #include "clang/Analysis/FlowSensitive/Value.h"
19 #include "clang/Basic/LangStandard.h"
20 #include "clang/Testing/TestAST.h"
21 #include "llvm/ADT/SmallVector.h"
22 #include "llvm/ADT/StringRef.h"
23 #include "llvm/Testing/Support/Error.h"
24 #include "gmock/gmock.h"
25 #include "gtest/gtest.h"
28 #include <string_view>
34 AST_MATCHER(FunctionDecl
, isTemplated
) { return Node
.isTemplated(); }
36 } // namespace dataflow
41 using namespace clang
;
42 using namespace dataflow
;
45 using ::testing::IsNull
;
47 using ::testing::NotNull
;
48 using ::testing::UnorderedElementsAre
;
50 // Declares a minimal coroutine library.
51 constexpr llvm::StringRef CoroutineLibrary
= R
"cc(
56 template <class, class...>
57 struct coroutine_traits {};
59 struct coroutine_traits<task> {
60 using promise_type = promise;
63 template <class Promise = void>
64 struct coroutine_handle {
65 static constexpr coroutine_handle from_address(void *addr) { return {}; }
70 bool await_ready() const noexcept;
71 void await_suspend(std::coroutine_handle<promise>) const noexcept;
72 void await_resume() const noexcept;
76 task get_return_object();
77 awaitable initial_suspend();
78 awaitable final_suspend() noexcept;
79 void unhandled_exception();
87 void(const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
90 DataflowAnalysisOptions Options
,
91 LangStandard::Kind Std
= LangStandard::lang_cxx17
,
92 llvm::StringRef TargetFun
= "target") {
93 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code
, VerifyResults
, Options
,
101 void(const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
104 LangStandard::Kind Std
= LangStandard::lang_cxx17
,
105 bool ApplyBuiltinTransfer
= true, llvm::StringRef TargetFun
= "target") {
106 runDataflow(Code
, std::move(VerifyResults
),
107 {ApplyBuiltinTransfer
? BuiltinOptions
{}
108 : std::optional
<BuiltinOptions
>()},
112 void runDataflowOnLambda(
113 llvm::StringRef Code
,
115 void(const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
118 DataflowAnalysisOptions Options
,
119 LangStandard::Kind Std
= LangStandard::lang_cxx17
) {
121 checkDataflowWithNoopAnalysis(
123 ast_matchers::hasDeclContext(
124 ast_matchers::cxxRecordDecl(ast_matchers::isLambda())),
125 VerifyResults
, Options
, Std
),
129 void runDataflowOnLambda(
130 llvm::StringRef Code
,
132 void(const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
135 LangStandard::Kind Std
= LangStandard::lang_cxx17
,
136 bool ApplyBuiltinTransfer
= true) {
137 runDataflowOnLambda(Code
, std::move(VerifyResults
),
138 {ApplyBuiltinTransfer
? BuiltinOptions
{}
139 : std::optional
<BuiltinOptions
>()},
143 const Formula
&getFormula(const ValueDecl
&D
, const Environment
&Env
) {
144 return cast
<BoolValue
>(Env
.getValue(D
))->formula();
147 const BindingDecl
*findBindingDecl(ASTContext
&ASTCtx
, std::string_view Name
) {
148 using ast_matchers::bindingDecl
;
149 using ast_matchers::hasName
;
151 ast_matchers::match(bindingDecl(hasName(Name
)).bind("v"), ASTCtx
);
152 assert(TargetNodes
.size() == 1 && "Name must be unique");
153 return ast_matchers::selectFirst
<BindingDecl
>("v", TargetNodes
);
156 TEST(TransferTest
, CNotSupported
) {
157 TestInputs
Inputs("void target() {}");
158 Inputs
.Language
= TestLanguage::Lang_C89
;
159 clang::TestAST
AST(Inputs
);
161 cast
<FunctionDecl
>(test::findValueDecl(AST
.context(), "target"));
162 ASSERT_THAT_ERROR(AdornedCFG::build(*Target
).takeError(),
163 llvm::FailedWithMessage("Can only analyze C++"));
166 TEST(TransferTest
, ObjectiveCNotSupported
) {
167 TestInputs
Inputs("void target() {}");
168 Inputs
.Language
= TestLanguage::Lang_OBJC
;
169 clang::TestAST
AST(Inputs
);
171 cast
<FunctionDecl
>(test::findValueDecl(AST
.context(), "target"));
172 ASSERT_THAT_ERROR(AdornedCFG::build(*Target
).takeError(),
173 llvm::FailedWithMessage("Can only analyze C++"));
176 TEST(TransferTest
, ObjectiveCXXNotSupported
) {
177 TestInputs
Inputs("void target() {}");
178 Inputs
.Language
= TestLanguage::Lang_OBJCXX
;
179 clang::TestAST
AST(Inputs
);
181 cast
<FunctionDecl
>(test::findValueDecl(AST
.context(), "target"));
182 ASSERT_THAT_ERROR(AdornedCFG::build(*Target
).takeError(),
183 llvm::FailedWithMessage("Can only analyze C++"));
186 TEST(TransferTest
, IntVarDeclNotTrackedWhenTransferDisabled
) {
187 std::string Code
= R
"(
195 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
196 ASTContext
&ASTCtx
) {
197 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
198 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
200 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
201 ASSERT_THAT(FooDecl
, NotNull());
203 EXPECT_EQ(Env
.getStorageLocation(*FooDecl
), nullptr);
205 LangStandard::lang_cxx17
,
206 /*ApplyBuiltinTransfer=*/false);
209 TEST(TransferTest
, BoolVarDecl
) {
210 std::string Code
= R
"(
218 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
219 ASTContext
&ASTCtx
) {
220 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
221 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
223 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
224 ASSERT_THAT(FooDecl
, NotNull());
226 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
227 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
229 const Value
*FooVal
= Env
.getValue(*FooLoc
);
230 EXPECT_TRUE(isa_and_nonnull
<BoolValue
>(FooVal
));
234 TEST(TransferTest
, IntVarDecl
) {
235 std::string Code
= R
"(
243 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
244 ASTContext
&ASTCtx
) {
245 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
246 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
248 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
249 ASSERT_THAT(FooDecl
, NotNull());
251 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
252 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
254 const Value
*FooVal
= Env
.getValue(*FooLoc
);
255 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
259 TEST(TransferTest
, StructIncomplete
) {
260 std::string Code
= R
"(
270 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
271 ASTContext
&ASTCtx
) {
272 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
273 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
275 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
276 ASSERT_THAT(FooDecl
, NotNull());
277 auto *FooValue
= dyn_cast_or_null
<PointerValue
>(Env
.getValue(*FooDecl
));
278 ASSERT_THAT(FooValue
, NotNull());
280 EXPECT_TRUE(isa
<RecordStorageLocation
>(FooValue
->getPointeeLoc()));
284 // As a memory optimization, we prevent modeling fields nested below a certain
285 // level (currently, depth 3). This test verifies this lack of modeling. We also
286 // include a regression test for the case that the unmodeled field is a
287 // reference to a struct; previously, we crashed when accessing such a field.
288 TEST(TransferTest
, StructFieldUnmodeled
) {
289 std::string Code
= R
"(
292 struct A { S &Unmodeled = GlobalS; };
299 A &Foo = Bar.F1.F2.F3;
300 int Zab = Foo.Unmodeled.X;
306 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
307 ASTContext
&ASTCtx
) {
308 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
309 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
311 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
312 ASSERT_THAT(FooDecl
, NotNull());
313 QualType FooReferentType
= FooDecl
->getType()->getPointeeType();
314 ASSERT_TRUE(FooReferentType
->isStructureType());
315 auto FooFields
= FooReferentType
->getAsRecordDecl()->fields();
317 FieldDecl
*UnmodeledDecl
= nullptr;
318 for (FieldDecl
*Field
: FooFields
) {
319 if (Field
->getNameAsString() == "Unmodeled") {
320 UnmodeledDecl
= Field
;
322 FAIL() << "Unexpected field: " << Field
->getNameAsString();
325 ASSERT_THAT(UnmodeledDecl
, NotNull());
328 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
329 const auto &UnmodeledLoc
=
330 *cast
<RecordStorageLocation
>(FooLoc
->getChild(*UnmodeledDecl
));
331 StorageLocation
&UnmodeledXLoc
= getFieldLoc(UnmodeledLoc
, "X", ASTCtx
);
332 EXPECT_EQ(Env
.getValue(UnmodeledXLoc
), nullptr);
334 const ValueDecl
*ZabDecl
= findValueDecl(ASTCtx
, "Zab");
335 ASSERT_THAT(ZabDecl
, NotNull());
336 EXPECT_THAT(Env
.getValue(*ZabDecl
), NotNull());
340 TEST(TransferTest
, StructVarDecl
) {
341 std::string Code
= R
"(
354 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
355 ASTContext
&ASTCtx
) {
356 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
357 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
359 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
360 ASSERT_THAT(FooDecl
, NotNull());
362 ASSERT_TRUE(FooDecl
->getType()->isStructureType());
363 auto FooFields
= FooDecl
->getType()->getAsRecordDecl()->fields();
365 FieldDecl
*BarDecl
= nullptr;
366 for (FieldDecl
*Field
: FooFields
) {
367 if (Field
->getNameAsString() == "Bar") {
370 FAIL() << "Unexpected field: " << Field
->getNameAsString();
373 ASSERT_THAT(BarDecl
, NotNull());
376 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
377 EXPECT_TRUE(isa
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
)));
381 TEST(TransferTest
, StructVarDeclWithInit
) {
382 std::string Code
= R
"(
397 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
398 ASTContext
&ASTCtx
) {
399 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
400 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
402 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
403 ASSERT_THAT(FooDecl
, NotNull());
405 ASSERT_TRUE(FooDecl
->getType()->isStructureType());
406 auto FooFields
= FooDecl
->getType()->getAsRecordDecl()->fields();
408 FieldDecl
*BarDecl
= nullptr;
409 for (FieldDecl
*Field
: FooFields
) {
410 if (Field
->getNameAsString() == "Bar") {
413 FAIL() << "Unexpected field: " << Field
->getNameAsString();
416 ASSERT_THAT(BarDecl
, NotNull());
419 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
420 EXPECT_TRUE(isa
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
)));
424 TEST(TransferTest
, StructArrayVarDecl
) {
425 std::string Code
= R
"(
435 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
436 ASTContext
&ASTCtx
) {
437 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
439 const ValueDecl
*ArrayDecl
= findValueDecl(ASTCtx
, "Array");
441 // We currently don't create values for arrays.
442 ASSERT_THAT(Env
.getValue(*ArrayDecl
), IsNull());
446 TEST(TransferTest
, ClassVarDecl
) {
447 std::string Code
= R
"(
461 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
462 ASTContext
&ASTCtx
) {
463 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
464 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
466 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
467 ASSERT_THAT(FooDecl
, NotNull());
469 ASSERT_TRUE(FooDecl
->getType()->isClassType());
470 auto FooFields
= FooDecl
->getType()->getAsRecordDecl()->fields();
472 FieldDecl
*BarDecl
= nullptr;
473 for (FieldDecl
*Field
: FooFields
) {
474 if (Field
->getNameAsString() == "Bar") {
477 FAIL() << "Unexpected field: " << Field
->getNameAsString();
480 ASSERT_THAT(BarDecl
, NotNull());
483 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
484 EXPECT_TRUE(isa
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
)));
488 TEST(TransferTest
, ReferenceVarDecl
) {
489 std::string Code
= R
"(
501 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
502 ASTContext
&ASTCtx
) {
503 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
504 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
506 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
507 ASSERT_THAT(FooDecl
, NotNull());
509 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
510 ASSERT_TRUE(isa_and_nonnull
<RecordStorageLocation
>(FooLoc
));
514 TEST(TransferTest
, SelfReferentialReferenceVarDecl
) {
515 std::string Code
= R
"(
535 (void)Foo.Bar.FooRef;
536 (void)Foo.Bar.FooPtr;
537 (void)Foo.Bar.BazRef;
538 (void)Foo.Bar.BazPtr;
542 runDataflow(Code
, [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>>
544 ASTContext
&ASTCtx
) {
545 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
546 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
548 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
549 ASSERT_THAT(FooDecl
, NotNull());
551 ASSERT_TRUE(FooDecl
->getType()->isReferenceType());
552 ASSERT_TRUE(FooDecl
->getType().getNonReferenceType()->isStructureType());
553 const auto FooFields
=
554 FooDecl
->getType().getNonReferenceType()->getAsRecordDecl()->fields();
556 FieldDecl
*BarDecl
= nullptr;
557 for (FieldDecl
*Field
: FooFields
) {
558 if (Field
->getNameAsString() == "Bar") {
561 FAIL() << "Unexpected field: " << Field
->getNameAsString();
564 ASSERT_THAT(BarDecl
, NotNull());
566 ASSERT_TRUE(BarDecl
->getType()->isReferenceType());
567 ASSERT_TRUE(BarDecl
->getType().getNonReferenceType()->isStructureType());
568 const auto BarFields
=
569 BarDecl
->getType().getNonReferenceType()->getAsRecordDecl()->fields();
571 FieldDecl
*FooRefDecl
= nullptr;
572 FieldDecl
*FooPtrDecl
= nullptr;
573 FieldDecl
*BazRefDecl
= nullptr;
574 FieldDecl
*BazPtrDecl
= nullptr;
575 for (FieldDecl
*Field
: BarFields
) {
576 if (Field
->getNameAsString() == "FooRef") {
578 } else if (Field
->getNameAsString() == "FooPtr") {
580 } else if (Field
->getNameAsString() == "BazRef") {
582 } else if (Field
->getNameAsString() == "BazPtr") {
585 FAIL() << "Unexpected field: " << Field
->getNameAsString();
588 ASSERT_THAT(FooRefDecl
, NotNull());
589 ASSERT_THAT(FooPtrDecl
, NotNull());
590 ASSERT_THAT(BazRefDecl
, NotNull());
591 ASSERT_THAT(BazPtrDecl
, NotNull());
594 *cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
597 *cast
<RecordStorageLocation
>(FooLoc
.getChild(*BarDecl
));
599 const auto &FooReferentLoc
=
600 *cast
<RecordStorageLocation
>(BarLoc
.getChild(*FooRefDecl
));
601 EXPECT_EQ(Env
.getValue(*cast
<RecordStorageLocation
>(
602 FooReferentLoc
.getChild(*BarDecl
))
603 ->getChild(*FooPtrDecl
)),
606 const auto &FooPtrVal
=
607 *cast
<PointerValue
>(getFieldValue(&BarLoc
, *FooPtrDecl
, Env
));
608 const auto &FooPtrPointeeLoc
=
609 cast
<RecordStorageLocation
>(FooPtrVal
.getPointeeLoc());
610 EXPECT_EQ(Env
.getValue(*cast
<RecordStorageLocation
>(
611 FooPtrPointeeLoc
.getChild(*BarDecl
))
612 ->getChild(*FooPtrDecl
)),
615 EXPECT_TRUE(isa
<PointerValue
>(getFieldValue(&BarLoc
, *BazPtrDecl
, Env
)));
619 TEST(TransferTest
, PointerVarDecl
) {
620 std::string Code
= R
"(
632 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
633 ASTContext
&ASTCtx
) {
634 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
635 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
637 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
638 ASSERT_THAT(FooDecl
, NotNull());
640 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
641 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
643 const PointerValue
*FooVal
= cast
<PointerValue
>(Env
.getValue(*FooLoc
));
644 const StorageLocation
&FooPointeeLoc
= FooVal
->getPointeeLoc();
645 EXPECT_TRUE(isa
<RecordStorageLocation
>(&FooPointeeLoc
));
649 TEST(TransferTest
, SelfReferentialPointerVarDecl
) {
650 std::string Code
= R
"(
670 (void)Foo->Bar->FooRef;
671 (void)Foo->Bar->FooPtr;
672 (void)Foo->Bar->BazRef;
673 (void)Foo->Bar->BazPtr;
679 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
680 ASTContext
&ASTCtx
) {
681 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
682 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
684 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
685 ASSERT_THAT(FooDecl
, NotNull());
687 ASSERT_TRUE(FooDecl
->getType()->isPointerType());
688 ASSERT_TRUE(FooDecl
->getType()
689 ->getAs
<PointerType
>()
691 ->isStructureType());
692 const auto FooFields
= FooDecl
->getType()
693 ->getAs
<PointerType
>()
698 FieldDecl
*BarDecl
= nullptr;
699 for (FieldDecl
*Field
: FooFields
) {
700 if (Field
->getNameAsString() == "Bar") {
703 FAIL() << "Unexpected field: " << Field
->getNameAsString();
706 ASSERT_THAT(BarDecl
, NotNull());
708 ASSERT_TRUE(BarDecl
->getType()->isPointerType());
709 ASSERT_TRUE(BarDecl
->getType()
710 ->getAs
<PointerType
>()
712 ->isStructureType());
713 const auto BarFields
= BarDecl
->getType()
714 ->getAs
<PointerType
>()
719 FieldDecl
*FooRefDecl
= nullptr;
720 FieldDecl
*FooPtrDecl
= nullptr;
721 FieldDecl
*BazRefDecl
= nullptr;
722 FieldDecl
*BazPtrDecl
= nullptr;
723 for (FieldDecl
*Field
: BarFields
) {
724 if (Field
->getNameAsString() == "FooRef") {
726 } else if (Field
->getNameAsString() == "FooPtr") {
728 } else if (Field
->getNameAsString() == "BazRef") {
730 } else if (Field
->getNameAsString() == "BazPtr") {
733 FAIL() << "Unexpected field: " << Field
->getNameAsString();
736 ASSERT_THAT(FooRefDecl
, NotNull());
737 ASSERT_THAT(FooPtrDecl
, NotNull());
738 ASSERT_THAT(BazRefDecl
, NotNull());
739 ASSERT_THAT(BazPtrDecl
, NotNull());
742 *cast
<ScalarStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
743 const auto &FooVal
= *cast
<PointerValue
>(Env
.getValue(FooLoc
));
744 const auto &FooPointeeLoc
=
745 cast
<RecordStorageLocation
>(FooVal
.getPointeeLoc());
748 *cast
<PointerValue
>(getFieldValue(&FooPointeeLoc
, *BarDecl
, Env
));
749 const auto &BarPointeeLoc
=
750 cast
<RecordStorageLocation
>(BarVal
.getPointeeLoc());
752 const auto &FooPtrVal
= *cast
<PointerValue
>(
753 getFieldValue(&BarPointeeLoc
, *FooPtrDecl
, Env
));
754 const auto &FooPtrPointeeLoc
=
755 cast
<RecordStorageLocation
>(FooPtrVal
.getPointeeLoc());
756 EXPECT_EQ(Env
.getValue(*FooPtrPointeeLoc
.getChild(*BarDecl
)), nullptr);
759 isa
<PointerValue
>(getFieldValue(&BarPointeeLoc
, *BazPtrDecl
, Env
)));
763 TEST(TransferTest
, DirectlySelfReferentialReference
) {
764 std::string Code
= R
"(
770 target &self = *this;
775 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
776 ASTContext
&ASTCtx
) {
777 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
778 const ValueDecl
*SelfDecl
= findValueDecl(ASTCtx
, "self");
780 auto *ThisLoc
= Env
.getThisPointeeStorageLocation();
781 ASSERT_EQ(ThisLoc
->getChild(*SelfDecl
), ThisLoc
);
785 TEST(TransferTest
, MultipleVarsDecl
) {
786 std::string Code
= R
"(
795 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
796 ASTContext
&ASTCtx
) {
797 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
798 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
800 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
801 ASSERT_THAT(FooDecl
, NotNull());
803 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
804 ASSERT_THAT(BarDecl
, NotNull());
806 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
807 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
809 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
810 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
812 const Value
*FooVal
= Env
.getValue(*FooLoc
);
813 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
815 const Value
*BarVal
= Env
.getValue(*BarLoc
);
816 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
820 TEST(TransferTest
, JoinVarDecl
) {
821 std::string Code
= R
"(
822 void target(bool B) {
836 runDataflow(Code
, [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>>
838 ASTContext
&ASTCtx
) {
839 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p1", "p2", "p3", "p4"));
841 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
842 ASSERT_THAT(FooDecl
, NotNull());
844 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
845 ASSERT_THAT(BarDecl
, NotNull());
847 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
848 ASSERT_THAT(BazDecl
, NotNull());
850 const Environment
&Env1
= getEnvironmentAtAnnotation(Results
, "p1");
852 const StorageLocation
*FooLoc
= Env1
.getStorageLocation(*FooDecl
);
853 EXPECT_THAT(FooLoc
, NotNull());
854 EXPECT_THAT(Env1
.getStorageLocation(*BarDecl
), IsNull());
855 EXPECT_THAT(Env1
.getStorageLocation(*BazDecl
), IsNull());
857 const Environment
&Env2
= getEnvironmentAtAnnotation(Results
, "p2");
858 EXPECT_EQ(Env2
.getStorageLocation(*FooDecl
), FooLoc
);
859 EXPECT_THAT(Env2
.getStorageLocation(*BarDecl
), NotNull());
860 EXPECT_THAT(Env2
.getStorageLocation(*BazDecl
), IsNull());
862 const Environment
&Env3
= getEnvironmentAtAnnotation(Results
, "p3");
863 EXPECT_EQ(Env3
.getStorageLocation(*FooDecl
), FooLoc
);
864 EXPECT_THAT(Env3
.getStorageLocation(*BarDecl
), IsNull());
865 EXPECT_THAT(Env3
.getStorageLocation(*BazDecl
), NotNull());
867 const Environment
&Env4
= getEnvironmentAtAnnotation(Results
, "p4");
868 EXPECT_EQ(Env4
.getStorageLocation(*FooDecl
), FooLoc
);
869 EXPECT_THAT(Env4
.getStorageLocation(*BarDecl
), IsNull());
870 EXPECT_THAT(Env4
.getStorageLocation(*BazDecl
), IsNull());
874 TEST(TransferTest
, BinaryOperatorAssign
) {
875 std::string Code
= R
"(
885 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
886 ASTContext
&ASTCtx
) {
887 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
888 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
890 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
891 ASSERT_THAT(FooDecl
, NotNull());
893 const Value
*FooVal
= Env
.getValue(*FooDecl
);
894 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
896 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
897 ASSERT_THAT(BarDecl
, NotNull());
899 EXPECT_EQ(Env
.getValue(*BarDecl
), FooVal
);
903 TEST(TransferTest
, BinaryOperatorAssignIntegerLiteral
) {
904 std::string Code
= R
"(
914 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
915 ASTContext
&ASTCtx
) {
916 const Environment
&Before
=
917 getEnvironmentAtAnnotation(Results
, "before");
918 const Environment
&After
= getEnvironmentAtAnnotation(Results
, "after");
920 const auto &ValBefore
=
921 getValueForDecl
<IntegerValue
>(ASTCtx
, Before
, "Foo");
922 const auto &ValAfter
=
923 getValueForDecl
<IntegerValue
>(ASTCtx
, After
, "Foo");
924 EXPECT_NE(&ValBefore
, &ValAfter
);
928 TEST(TransferTest
, VarDeclInitAssign
) {
929 std::string Code
= R
"(
938 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
939 ASTContext
&ASTCtx
) {
940 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
941 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
943 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
944 ASSERT_THAT(FooDecl
, NotNull());
946 const Value
*FooVal
= Env
.getValue(*FooDecl
);
947 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
949 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
950 ASSERT_THAT(BarDecl
, NotNull());
952 EXPECT_EQ(Env
.getValue(*BarDecl
), FooVal
);
956 TEST(TransferTest
, VarDeclInitAssignChained
) {
957 std::string Code
= R
"(
961 int Baz = (Bar = Foo);
967 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
968 ASTContext
&ASTCtx
) {
969 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
970 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
972 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
973 ASSERT_THAT(FooDecl
, NotNull());
975 const Value
*FooVal
= Env
.getValue(*FooDecl
);
976 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
978 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
979 ASSERT_THAT(BarDecl
, NotNull());
981 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
982 ASSERT_THAT(BazDecl
, NotNull());
984 EXPECT_EQ(Env
.getValue(*BarDecl
), FooVal
);
985 EXPECT_EQ(Env
.getValue(*BazDecl
), FooVal
);
989 TEST(TransferTest
, VarDeclInitAssignPtrDeref
) {
990 std::string Code
= R
"(
1001 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1002 ASTContext
&ASTCtx
) {
1003 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1004 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1006 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1007 ASSERT_THAT(FooDecl
, NotNull());
1009 const Value
*FooVal
= Env
.getValue(*FooDecl
);
1010 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
1012 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
1013 ASSERT_THAT(BarDecl
, NotNull());
1015 const auto *BarVal
= cast
<PointerValue
>(Env
.getValue(*BarDecl
));
1016 EXPECT_EQ(Env
.getValue(BarVal
->getPointeeLoc()), FooVal
);
1018 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
1019 ASSERT_THAT(BazDecl
, NotNull());
1021 EXPECT_EQ(Env
.getValue(*BazDecl
), FooVal
);
1025 TEST(TransferTest
, AssignToAndFromReference
) {
1026 std::string Code
= R
"(
1040 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1041 ASTContext
&ASTCtx
) {
1042 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p1", "p2"));
1043 const Environment
&Env1
= getEnvironmentAtAnnotation(Results
, "p1");
1044 const Environment
&Env2
= getEnvironmentAtAnnotation(Results
, "p2");
1046 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1047 ASSERT_THAT(FooDecl
, NotNull());
1049 const Value
*FooVal
= Env1
.getValue(*FooDecl
);
1050 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
1052 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
1053 ASSERT_THAT(BarDecl
, NotNull());
1055 const Value
*BarVal
= Env1
.getValue(*BarDecl
);
1056 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
1058 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
1059 ASSERT_THAT(BazDecl
, NotNull());
1061 EXPECT_EQ(Env1
.getValue(*BazDecl
), FooVal
);
1063 EXPECT_EQ(Env2
.getValue(*BazDecl
), BarVal
);
1064 EXPECT_EQ(Env2
.getValue(*FooDecl
), BarVal
);
1066 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
1067 ASSERT_THAT(QuxDecl
, NotNull());
1068 EXPECT_EQ(Env2
.getValue(*QuxDecl
), BarVal
);
1070 const ValueDecl
*QuuxDecl
= findValueDecl(ASTCtx
, "Quux");
1071 ASSERT_THAT(QuuxDecl
, NotNull());
1072 EXPECT_EQ(Env2
.getValue(*QuuxDecl
), BarVal
);
1076 TEST(TransferTest
, MultipleParamDecls
) {
1077 std::string Code
= R
"(
1078 void target(int Foo, int Bar) {
1085 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1086 ASTContext
&ASTCtx
) {
1087 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1088 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1090 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1091 ASSERT_THAT(FooDecl
, NotNull());
1093 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
1094 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
1096 const Value
*FooVal
= Env
.getValue(*FooLoc
);
1097 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
1099 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
1100 ASSERT_THAT(BarDecl
, NotNull());
1102 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
1103 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
1105 const Value
*BarVal
= Env
.getValue(*BarLoc
);
1106 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
1110 TEST(TransferTest
, StructParamDecl
) {
1111 std::string Code
= R
"(
1116 void target(A Foo) {
1123 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1124 ASTContext
&ASTCtx
) {
1125 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1126 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1128 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1129 ASSERT_THAT(FooDecl
, NotNull());
1131 ASSERT_TRUE(FooDecl
->getType()->isStructureType());
1132 auto FooFields
= FooDecl
->getType()->getAsRecordDecl()->fields();
1134 FieldDecl
*BarDecl
= nullptr;
1135 for (FieldDecl
*Field
: FooFields
) {
1136 if (Field
->getNameAsString() == "Bar") {
1139 FAIL() << "Unexpected field: " << Field
->getNameAsString();
1142 ASSERT_THAT(BarDecl
, NotNull());
1144 const auto *FooLoc
=
1145 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
1146 EXPECT_TRUE(isa
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
)));
1150 TEST(TransferTest
, ReferenceParamDecl
) {
1151 std::string Code
= R
"(
1154 void target(A &Foo) {
1161 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1162 ASTContext
&ASTCtx
) {
1163 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1164 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1166 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1167 ASSERT_THAT(FooDecl
, NotNull());
1169 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
1170 ASSERT_TRUE(isa_and_nonnull
<RecordStorageLocation
>(FooLoc
));
1174 TEST(TransferTest
, PointerParamDecl
) {
1175 std::string Code
= R
"(
1178 void target(A *Foo) {
1185 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1186 ASTContext
&ASTCtx
) {
1187 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1188 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1190 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1191 ASSERT_THAT(FooDecl
, NotNull());
1193 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
1194 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
1196 const PointerValue
*FooVal
= cast
<PointerValue
>(Env
.getValue(*FooLoc
));
1197 const StorageLocation
&FooPointeeLoc
= FooVal
->getPointeeLoc();
1198 EXPECT_TRUE(isa
<RecordStorageLocation
>(&FooPointeeLoc
));
1202 TEST(TransferTest
, StructMember
) {
1203 std::string Code
= R
"(
1208 void target(A Foo) {
1215 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1216 ASTContext
&ASTCtx
) {
1217 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1218 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1220 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1221 ASSERT_THAT(FooDecl
, NotNull());
1223 ASSERT_TRUE(FooDecl
->getType()->isStructureType());
1224 auto FooFields
= FooDecl
->getType()->getAsRecordDecl()->fields();
1226 FieldDecl
*BarDecl
= nullptr;
1227 for (FieldDecl
*Field
: FooFields
) {
1228 if (Field
->getNameAsString() == "Bar") {
1231 FAIL() << "Unexpected field: " << Field
->getNameAsString();
1234 ASSERT_THAT(BarDecl
, NotNull());
1236 const auto *FooLoc
=
1237 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
1238 const auto *BarVal
=
1239 cast
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
));
1241 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
1242 ASSERT_THAT(BazDecl
, NotNull());
1244 EXPECT_EQ(Env
.getValue(*BazDecl
), BarVal
);
1248 TEST(TransferTest
, StructMemberEnum
) {
1249 std::string Code
= R
"(
1252 enum E { ONE, TWO };
1255 void target(A Foo) {
1260 // Minimal expectations -- we're just testing that it doesn't crash, since
1261 // enums aren't interpreted.
1264 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1265 ASTContext
&ASTCtx
) {
1266 EXPECT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1270 TEST(TransferTest
, DerivedBaseMemberClass
) {
1271 std::string Code
= R
"(
1282 friend void target();
1285 class B : public A {
1293 friend void target();
1299 (void)Foo.AProtected;
1303 (void)Foo.BProtected;
1310 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1311 ASTContext
&ASTCtx
) {
1312 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1313 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1315 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1316 ASSERT_THAT(FooDecl
, NotNull());
1317 ASSERT_TRUE(FooDecl
->getType()->isRecordType());
1319 // Derived-class fields.
1320 const FieldDecl
*BDefaultDecl
= nullptr;
1321 const FieldDecl
*BProtectedDecl
= nullptr;
1322 const FieldDecl
*BPrivateDecl
= nullptr;
1323 for (const FieldDecl
*Field
:
1324 FooDecl
->getType()->getAsRecordDecl()->fields()) {
1325 if (Field
->getNameAsString() == "BDefault") {
1326 BDefaultDecl
= Field
;
1327 } else if (Field
->getNameAsString() == "BProtected") {
1328 BProtectedDecl
= Field
;
1329 } else if (Field
->getNameAsString() == "BPrivate") {
1330 BPrivateDecl
= Field
;
1332 FAIL() << "Unexpected field: " << Field
->getNameAsString();
1335 ASSERT_THAT(BDefaultDecl
, NotNull());
1336 ASSERT_THAT(BProtectedDecl
, NotNull());
1337 ASSERT_THAT(BPrivateDecl
, NotNull());
1339 // Base-class fields.
1340 const FieldDecl
*ADefaultDecl
= nullptr;
1341 const FieldDecl
*APrivateDecl
= nullptr;
1342 const FieldDecl
*AProtectedDecl
= nullptr;
1343 const FieldDecl
*APublicDecl
= nullptr;
1344 for (const clang::CXXBaseSpecifier
&Base
:
1345 FooDecl
->getType()->getAsCXXRecordDecl()->bases()) {
1346 QualType BaseType
= Base
.getType();
1347 ASSERT_TRUE(BaseType
->isRecordType());
1348 for (const FieldDecl
*Field
: BaseType
->getAsRecordDecl()->fields()) {
1349 if (Field
->getNameAsString() == "ADefault") {
1350 ADefaultDecl
= Field
;
1351 } else if (Field
->getNameAsString() == "AProtected") {
1352 AProtectedDecl
= Field
;
1353 } else if (Field
->getNameAsString() == "APrivate") {
1354 APrivateDecl
= Field
;
1355 } else if (Field
->getNameAsString() == "APublic") {
1356 APublicDecl
= Field
;
1358 FAIL() << "Unexpected field: " << Field
->getNameAsString();
1362 ASSERT_THAT(ADefaultDecl
, NotNull());
1363 ASSERT_THAT(AProtectedDecl
, NotNull());
1364 ASSERT_THAT(APrivateDecl
, NotNull());
1365 ASSERT_THAT(APublicDecl
, NotNull());
1368 isa
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
)));
1372 static void derivedBaseMemberExpectations(
1373 const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1374 ASTContext
&ASTCtx
) {
1375 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1376 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1378 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1379 ASSERT_THAT(FooDecl
, NotNull());
1381 ASSERT_TRUE(FooDecl
->getType()->isRecordType());
1382 const FieldDecl
*BarDecl
= nullptr;
1383 for (const clang::CXXBaseSpecifier
&Base
:
1384 FooDecl
->getType()->getAsCXXRecordDecl()->bases()) {
1385 QualType BaseType
= Base
.getType();
1386 ASSERT_TRUE(BaseType
->isStructureType());
1388 for (const FieldDecl
*Field
: BaseType
->getAsRecordDecl()->fields()) {
1389 if (Field
->getNameAsString() == "Bar") {
1392 FAIL() << "Unexpected field: " << Field
->getNameAsString();
1396 ASSERT_THAT(BarDecl
, NotNull());
1398 const auto &FooLoc
=
1399 *cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
1400 EXPECT_NE(Env
.getValue(*FooLoc
.getChild(*BarDecl
)), nullptr);
1403 TEST(TransferTest
, DerivedBaseMemberStructDefault
) {
1404 std::string Code
= R
"(
1408 struct B : public A {
1417 runDataflow(Code
, derivedBaseMemberExpectations
);
1420 TEST(TransferTest
, DerivedBaseMemberPrivateFriend
) {
1421 // Include an access to `Foo.Bar` to verify the analysis doesn't crash on that
1423 std::string Code
= R
"(
1426 friend void target();
1429 struct B : public A {
1438 runDataflow(Code
, derivedBaseMemberExpectations
);
1441 TEST(TransferTest
, ClassMember
) {
1442 std::string Code
= R
"(
1448 void target(A Foo) {
1455 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1456 ASTContext
&ASTCtx
) {
1457 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1458 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1460 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1461 ASSERT_THAT(FooDecl
, NotNull());
1463 ASSERT_TRUE(FooDecl
->getType()->isClassType());
1464 auto FooFields
= FooDecl
->getType()->getAsRecordDecl()->fields();
1466 FieldDecl
*BarDecl
= nullptr;
1467 for (FieldDecl
*Field
: FooFields
) {
1468 if (Field
->getNameAsString() == "Bar") {
1471 FAIL() << "Unexpected field: " << Field
->getNameAsString();
1474 ASSERT_THAT(BarDecl
, NotNull());
1476 const auto *FooLoc
=
1477 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
1478 const auto *BarVal
=
1479 cast
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
));
1481 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
1482 ASSERT_THAT(BazDecl
, NotNull());
1484 EXPECT_EQ(Env
.getValue(*BazDecl
), BarVal
);
1488 TEST(TransferTest
, BaseClassInitializer
) {
1489 using ast_matchers::cxxConstructorDecl
;
1490 using ast_matchers::hasName
;
1491 using ast_matchers::ofClass
;
1493 std::string Code
= R
"(
1496 A(int I) : Bar(I) {}
1500 class B : public A {
1509 checkDataflow
<NoopAnalysis
>(
1510 AnalysisInputs
<NoopAnalysis
>(
1511 Code
, cxxConstructorDecl(ofClass(hasName("B"))),
1512 [](ASTContext
&C
, Environment
&) { return NoopAnalysis(C
); })
1514 {"-fsyntax-only", "-fno-delayed-template-parsing",
1515 "-std=" + std::string(LangStandard::getLangStandardForKind(
1516 LangStandard::lang_cxx17
)
1519 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1520 const AnalysisOutputs
&) {
1521 // Regression test to verify that base-class initializers do not
1522 // trigger an assertion. If we add support for such initializers in
1523 // the future, we can expand this test to check more specific
1525 EXPECT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1530 TEST(TransferTest
, FieldsDontHaveValuesInConstructor
) {
1531 // In a constructor, unlike in regular member functions, we don't want fields
1532 // to be pre-initialized with values, because doing so is the job of the
1534 std::string Code
= R
"(
1539 // Mention the field so it is modeled;
1548 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1549 ASTContext
&ASTCtx
) {
1550 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1551 EXPECT_EQ(getFieldValue(Env
.getThisPointeeStorageLocation(), "Val",
1557 TEST(TransferTest
, FieldsDontHaveValuesInConstructorWithBaseClass
) {
1558 // See above, but for a class with a base class.
1559 std::string Code
= R
"(
1564 struct target : public Base {
1568 // Mention the fields so they are modeled.
1578 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1579 ASTContext
&ASTCtx
) {
1580 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1581 // The field of the base class should already have been initialized with
1582 // a value by the base constructor.
1583 EXPECT_NE(getFieldValue(Env
.getThisPointeeStorageLocation(), "BaseVal",
1586 EXPECT_EQ(getFieldValue(Env
.getThisPointeeStorageLocation(), "Val",
1592 TEST(TransferTest
, StructModeledFieldsWithAccessor
) {
1593 std::string Code
= R
"(
1602 int *getPtr() const { return Ptr; }
1603 int *getPtrNonConst() { return PtrNonConst; }
1604 int getInt(int i) const { return Int; }
1605 int getWithInc(int i) { IntWithInc += i; return IntWithInc; }
1606 int getIntNotAccessed() const { return IntNotAccessed; }
1607 int getIntNoDefinition() const;
1608 int &getIntRef() { return IntRef; }
1609 void returnVoid() const { return; }
1614 int *p1 = s.getPtr();
1615 int *p2 = s.getPtrNonConst();
1616 int i1 = s.getInt(1);
1617 int i2 = s.getWithInc(1);
1618 int i3 = s.getIntNoDefinition();
1619 int &iref = s.getIntRef();
1621 // Regression test: Don't crash on an indirect call (which doesn't have
1622 // an associated `CXXMethodDecl`).
1623 auto ptr_to_member_fn = &S::getPtr;
1624 p1 = (s.*ptr_to_member_fn)();
1626 // Regression test: Don't crash on a return statement without a value.
1633 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1634 ASTContext
&ASTCtx
) {
1635 const Environment
&Env
=
1636 getEnvironmentAtAnnotation(Results
, "p");
1637 auto &SLoc
= getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "s");
1638 std::vector
<const ValueDecl
*> Fields
;
1639 for (auto [Field
, _
] : SLoc
.children())
1640 Fields
.push_back(Field
);
1641 // Only the fields that have simple accessor methods (that have a
1642 // single statement body that returns the member variable) should be
1644 ASSERT_THAT(Fields
, UnorderedElementsAre(
1645 findValueDecl(ASTCtx
, "Ptr"), findValueDecl(ASTCtx
, "PtrNonConst"),
1646 findValueDecl(ASTCtx
, "Int"), findValueDecl(ASTCtx
, "IntRef")));
1650 TEST(TransferTest
, StructModeledFieldsInTypeid
) {
1651 // Test that we model fields mentioned inside a `typeid()` expression only if
1652 // that expression is potentially evaluated -- i.e. if the expression inside
1653 // `typeid()` is a glvalue of polymorphic type (see
1654 // `CXXTypeidExpr::isPotentiallyEvaluated()` and [expr.typeid]p3).
1655 std::string Code
= R
"(
1656 // Definitions needed for `typeid`.
1659 class bad_typeid {};
1662 struct NonPolymorphic {};
1664 struct Polymorphic {
1665 virtual ~Polymorphic() = default;
1669 NonPolymorphic *NonPoly;
1681 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1682 ASTContext
&ASTCtx
) {
1683 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1684 auto &SLoc
= getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "s");
1685 std::vector
<const ValueDecl
*> Fields
;
1686 for (auto [Field
, _
] : SLoc
.children())
1687 Fields
.push_back(Field
);
1689 UnorderedElementsAre(findValueDecl(ASTCtx
, "Poly")));
1693 TEST(TransferTest
, StructModeledFieldsWithComplicatedInheritance
) {
1694 std::string Code
= R
"(
1699 struct Intermediate : Base1 {
1707 struct MostDerived : public Intermediate, Base2 {
1715 MD.intermediate_2 = 1;
1717 MD.most_derived_2 = 1;
1723 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1724 ASTContext
&ASTCtx
) {
1725 const Environment
&Env
=
1726 getEnvironmentAtAnnotation(Results
, "p");
1728 // Only the accessed fields should exist in the model.
1729 auto &MDLoc
= getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "MD");
1730 std::vector
<const ValueDecl
*> Fields
;
1731 for (auto [Field
, _
] : MDLoc
.children())
1732 Fields
.push_back(Field
);
1733 ASSERT_THAT(Fields
, UnorderedElementsAre(
1734 findValueDecl(ASTCtx
, "base1_2"),
1735 findValueDecl(ASTCtx
, "intermediate_2"),
1736 findValueDecl(ASTCtx
, "base2_2"),
1737 findValueDecl(ASTCtx
, "most_derived_2")));
1741 TEST(TransferTest
, StructInitializerListWithComplicatedInheritance
) {
1742 std::string Code
= R
"(
1746 struct Intermediate : Base1 {
1752 struct MostDerived : public Intermediate, Base2 {
1757 MostDerived MD = {};
1763 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1764 ASTContext
&ASTCtx
) {
1765 const Environment
&Env
=
1766 getEnvironmentAtAnnotation(Results
, "p");
1768 // When a struct is initialized with a initializer list, all the
1769 // fields are considered "accessed", and therefore do exist.
1770 auto &MD
= getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "MD");
1771 ASSERT_THAT(cast
<IntegerValue
>(
1772 getFieldValue(&MD
, *findValueDecl(ASTCtx
, "base1"), Env
)),
1774 ASSERT_THAT(cast
<IntegerValue
>(
1775 getFieldValue(&MD
, *findValueDecl(ASTCtx
, "intermediate"), Env
)),
1777 ASSERT_THAT(cast
<IntegerValue
>(
1778 getFieldValue(&MD
, *findValueDecl(ASTCtx
, "base2"), Env
)),
1780 ASSERT_THAT(cast
<IntegerValue
>(
1781 getFieldValue(&MD
, *findValueDecl(ASTCtx
, "most_derived"), Env
)),
1786 TEST(TransferTest
, ReferenceMember
) {
1787 std::string Code
= R
"(
1792 void target(A Foo) {
1799 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1800 ASTContext
&ASTCtx
) {
1801 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1802 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1804 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1805 ASSERT_THAT(FooDecl
, NotNull());
1807 ASSERT_TRUE(FooDecl
->getType()->isStructureType());
1808 auto FooFields
= FooDecl
->getType()->getAsRecordDecl()->fields();
1810 FieldDecl
*BarDecl
= nullptr;
1811 for (FieldDecl
*Field
: FooFields
) {
1812 if (Field
->getNameAsString() == "Bar") {
1815 FAIL() << "Unexpected field: " << Field
->getNameAsString();
1818 ASSERT_THAT(BarDecl
, NotNull());
1820 const auto *FooLoc
=
1821 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
1822 const auto *BarReferentVal
=
1823 cast
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
));
1825 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
1826 ASSERT_THAT(BazDecl
, NotNull());
1828 EXPECT_EQ(Env
.getValue(*BazDecl
), BarReferentVal
);
1832 TEST(TransferTest
, StructThisMember
) {
1833 std::string Code
= R
"(
1852 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1853 ASTContext
&ASTCtx
) {
1854 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1855 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1857 const auto *ThisLoc
= Env
.getThisPointeeStorageLocation();
1858 ASSERT_THAT(ThisLoc
, NotNull());
1860 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
1861 ASSERT_THAT(BarDecl
, NotNull());
1863 const auto *BarLoc
=
1864 cast
<ScalarStorageLocation
>(ThisLoc
->getChild(*BarDecl
));
1865 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
1867 const Value
*BarVal
= Env
.getValue(*BarLoc
);
1868 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
1870 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1871 ASSERT_THAT(FooDecl
, NotNull());
1872 EXPECT_EQ(Env
.getValue(*FooDecl
), BarVal
);
1874 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
1875 ASSERT_THAT(QuxDecl
, NotNull());
1877 ASSERT_TRUE(QuxDecl
->getType()->isStructureType());
1878 auto QuxFields
= QuxDecl
->getType()->getAsRecordDecl()->fields();
1880 FieldDecl
*BazDecl
= nullptr;
1881 for (FieldDecl
*Field
: QuxFields
) {
1882 if (Field
->getNameAsString() == "Baz") {
1885 FAIL() << "Unexpected field: " << Field
->getNameAsString();
1888 ASSERT_THAT(BazDecl
, NotNull());
1890 const auto *QuxLoc
=
1891 cast
<RecordStorageLocation
>(ThisLoc
->getChild(*QuxDecl
));
1893 const auto *BazVal
=
1894 cast
<IntegerValue
>(getFieldValue(QuxLoc
, *BazDecl
, Env
));
1896 const ValueDecl
*QuuxDecl
= findValueDecl(ASTCtx
, "Quux");
1897 ASSERT_THAT(QuuxDecl
, NotNull());
1898 EXPECT_EQ(Env
.getValue(*QuuxDecl
), BazVal
);
1902 TEST(TransferTest
, ClassThisMember
) {
1903 std::string Code
= R
"(
1923 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1924 ASTContext
&ASTCtx
) {
1925 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1926 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1928 const auto *ThisLoc
= Env
.getThisPointeeStorageLocation();
1930 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
1931 ASSERT_THAT(BarDecl
, NotNull());
1933 const auto *BarLoc
=
1934 cast
<ScalarStorageLocation
>(ThisLoc
->getChild(*BarDecl
));
1935 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
1937 const Value
*BarVal
= Env
.getValue(*BarLoc
);
1938 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
1940 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1941 ASSERT_THAT(FooDecl
, NotNull());
1942 EXPECT_EQ(Env
.getValue(*FooDecl
), BarVal
);
1944 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
1945 ASSERT_THAT(QuxDecl
, NotNull());
1947 ASSERT_TRUE(QuxDecl
->getType()->isClassType());
1948 auto QuxFields
= QuxDecl
->getType()->getAsRecordDecl()->fields();
1950 FieldDecl
*BazDecl
= nullptr;
1951 for (FieldDecl
*Field
: QuxFields
) {
1952 if (Field
->getNameAsString() == "Baz") {
1955 FAIL() << "Unexpected field: " << Field
->getNameAsString();
1958 ASSERT_THAT(BazDecl
, NotNull());
1960 const auto *QuxLoc
=
1961 cast
<RecordStorageLocation
>(ThisLoc
->getChild(*QuxDecl
));
1963 const auto *BazVal
=
1964 cast
<IntegerValue
>(getFieldValue(QuxLoc
, *BazDecl
, Env
));
1966 const ValueDecl
*QuuxDecl
= findValueDecl(ASTCtx
, "Quux");
1967 ASSERT_THAT(QuuxDecl
, NotNull());
1968 EXPECT_EQ(Env
.getValue(*QuuxDecl
), BazVal
);
1972 TEST(TransferTest
, UnionThisMember
) {
1973 std::string Code
= R
"(
1980 // Mention the fields to ensure they're included in the analysis.
1989 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
1990 ASTContext
&ASTCtx
) {
1991 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
1992 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
1994 const auto *ThisLoc
= Env
.getThisPointeeStorageLocation();
1995 ASSERT_THAT(ThisLoc
, NotNull());
1997 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
1998 ASSERT_THAT(FooDecl
, NotNull());
2000 const auto *FooLoc
=
2001 cast
<ScalarStorageLocation
>(ThisLoc
->getChild(*FooDecl
));
2002 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
2004 const Value
*FooVal
= Env
.getValue(*FooLoc
);
2005 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
2007 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2008 ASSERT_THAT(BarDecl
, NotNull());
2010 const auto *BarLoc
=
2011 cast
<ScalarStorageLocation
>(ThisLoc
->getChild(*BarDecl
));
2012 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
2014 const Value
*BarVal
= Env
.getValue(*BarLoc
);
2015 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
2019 TEST(TransferTest
, StructThisInLambda
) {
2020 std::string ThisCaptureCode
= R
"(
2034 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2035 ASTContext
&ASTCtx
) {
2036 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p1"));
2037 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p1");
2039 const auto *ThisLoc
= Env
.getThisPointeeStorageLocation();
2040 ASSERT_THAT(ThisLoc
, NotNull());
2042 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2043 ASSERT_THAT(BarDecl
, NotNull());
2045 const auto *BarLoc
=
2046 cast
<ScalarStorageLocation
>(ThisLoc
->getChild(*BarDecl
));
2047 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
2049 const Value
*BarVal
= Env
.getValue(*BarLoc
);
2050 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
2052 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2053 ASSERT_THAT(FooDecl
, NotNull());
2054 EXPECT_EQ(Env
.getValue(*FooDecl
), BarVal
);
2056 LangStandard::lang_cxx17
, /*ApplyBuiltinTransfer=*/true, "operator()");
2058 std::string RefCaptureDefaultCode
= R
"(
2071 RefCaptureDefaultCode
,
2072 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2073 ASTContext
&ASTCtx
) {
2074 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p2"));
2075 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p2");
2077 const auto *ThisLoc
= Env
.getThisPointeeStorageLocation();
2078 ASSERT_THAT(ThisLoc
, NotNull());
2080 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2081 ASSERT_THAT(BarDecl
, NotNull());
2083 const auto *BarLoc
=
2084 cast
<ScalarStorageLocation
>(ThisLoc
->getChild(*BarDecl
));
2085 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
2087 const Value
*BarVal
= Env
.getValue(*BarLoc
);
2088 ASSERT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
2090 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2091 ASSERT_THAT(FooDecl
, NotNull());
2092 EXPECT_EQ(Env
.getValue(*FooDecl
), BarVal
);
2094 LangStandard::lang_cxx17
, /*ApplyBuiltinTransfer=*/true, "operator()");
2096 std::string FreeFunctionLambdaCode
= R
"(
2106 FreeFunctionLambdaCode
,
2107 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2108 ASTContext
&ASTCtx
) {
2109 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p3"));
2110 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p3");
2112 EXPECT_THAT(Env
.getThisPointeeStorageLocation(), IsNull());
2114 LangStandard::lang_cxx17
, /*ApplyBuiltinTransfer=*/true, "operator()");
2117 TEST(TransferTest
, ConstructorInitializer
) {
2118 std::string Code
= R
"(
2122 target(int Foo) : Bar(Foo) {
2130 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2131 ASTContext
&ASTCtx
) {
2132 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2133 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2135 const auto *ThisLoc
= Env
.getThisPointeeStorageLocation();
2136 ASSERT_THAT(ThisLoc
, NotNull());
2138 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2139 ASSERT_THAT(FooDecl
, NotNull());
2141 const auto *FooVal
= cast
<IntegerValue
>(Env
.getValue(*FooDecl
));
2143 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
2144 ASSERT_THAT(QuxDecl
, NotNull());
2145 EXPECT_EQ(Env
.getValue(*QuxDecl
), FooVal
);
2149 TEST(TransferTest
, DefaultInitializer
) {
2150 std::string Code
= R
"(
2155 target(int Foo) : Bar(Foo) {
2163 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2164 ASTContext
&ASTCtx
) {
2165 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2166 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2168 const auto *ThisLoc
= Env
.getThisPointeeStorageLocation();
2169 ASSERT_THAT(ThisLoc
, NotNull());
2171 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2172 ASSERT_THAT(FooDecl
, NotNull());
2174 const auto *FooVal
= cast
<IntegerValue
>(Env
.getValue(*FooDecl
));
2176 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
2177 ASSERT_THAT(QuxDecl
, NotNull());
2178 EXPECT_EQ(Env
.getValue(*QuxDecl
), FooVal
);
2182 TEST(TransferTest
, DefaultInitializerReference
) {
2183 std::string Code
= R
"(
2188 target(int &Foo) : Bar(Foo) {
2196 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2197 ASTContext
&ASTCtx
) {
2198 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2199 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2201 const auto *ThisLoc
= Env
.getThisPointeeStorageLocation();
2202 ASSERT_THAT(ThisLoc
, NotNull());
2204 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2205 ASSERT_THAT(FooDecl
, NotNull());
2207 const auto *FooLoc
= Env
.getStorageLocation(*FooDecl
);
2209 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
2210 ASSERT_THAT(QuxDecl
, NotNull());
2212 const auto *QuxLoc
= Env
.getStorageLocation(*QuxDecl
);
2213 EXPECT_EQ(QuxLoc
, FooLoc
);
2217 TEST(TransferTest
, TemporaryObject
) {
2218 std::string Code
= R
"(
2231 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2232 ASTContext
&ASTCtx
) {
2233 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2234 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2236 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2237 ASSERT_THAT(FooDecl
, NotNull());
2239 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2240 ASSERT_THAT(BarDecl
, NotNull());
2242 const auto *FooLoc
=
2243 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2244 EXPECT_TRUE(isa
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
)));
2248 TEST(TransferTest
, ElidableConstructor
) {
2249 // This test is effectively the same as TransferTest.TemporaryObject, but
2250 // the code is compiled as C++14.
2251 std::string Code
= R
"(
2264 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2265 ASTContext
&ASTCtx
) {
2266 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2267 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2269 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2270 ASSERT_THAT(FooDecl
, NotNull());
2272 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2273 ASSERT_THAT(BarDecl
, NotNull());
2275 const auto *FooLoc
=
2276 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2277 EXPECT_TRUE(isa
<IntegerValue
>(getFieldValue(FooLoc
, *BarDecl
, Env
)));
2279 LangStandard::lang_cxx14
);
2282 TEST(TransferTest
, AssignmentOperator
) {
2283 std::string Code
= R
"(
2292 A &Rval = (Foo = Bar);
2300 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2301 ASTContext
&ASTCtx
) {
2302 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2303 ASSERT_THAT(FooDecl
, NotNull());
2305 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2306 ASSERT_THAT(BarDecl
, NotNull());
2308 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2309 ASSERT_THAT(BazDecl
, NotNull());
2311 // Before copy assignment.
2313 const Environment
&Env1
= getEnvironmentAtAnnotation(Results
, "p1");
2315 const auto *FooLoc1
=
2316 cast
<RecordStorageLocation
>(Env1
.getStorageLocation(*FooDecl
));
2317 const auto *BarLoc1
=
2318 cast
<RecordStorageLocation
>(Env1
.getStorageLocation(*BarDecl
));
2319 EXPECT_FALSE(recordsEqual(*FooLoc1
, *BarLoc1
, Env1
));
2321 const auto *FooBazVal1
=
2322 cast
<IntegerValue
>(getFieldValue(FooLoc1
, *BazDecl
, Env1
));
2323 const auto *BarBazVal1
=
2324 cast
<IntegerValue
>(getFieldValue(BarLoc1
, *BazDecl
, Env1
));
2325 EXPECT_NE(FooBazVal1
, BarBazVal1
);
2328 // After copy assignment.
2330 const Environment
&Env2
= getEnvironmentAtAnnotation(Results
, "p2");
2332 const auto *FooLoc2
=
2333 cast
<RecordStorageLocation
>(Env2
.getStorageLocation(*FooDecl
));
2334 const auto *BarLoc2
=
2335 cast
<RecordStorageLocation
>(Env2
.getStorageLocation(*BarDecl
));
2337 EXPECT_TRUE(recordsEqual(*FooLoc2
, *BarLoc2
, Env2
));
2338 EXPECT_EQ(&getLocForDecl(ASTCtx
, Env2
, "Rval"), FooLoc2
);
2340 const auto *FooBazVal2
=
2341 cast
<IntegerValue
>(getFieldValue(FooLoc2
, *BazDecl
, Env2
));
2342 const auto *BarBazVal2
=
2343 cast
<IntegerValue
>(getFieldValue(BarLoc2
, *BazDecl
, Env2
));
2344 EXPECT_EQ(FooBazVal2
, BarBazVal2
);
2347 // After value update.
2349 const Environment
&Env3
= getEnvironmentAtAnnotation(Results
, "p3");
2351 const auto *FooLoc3
=
2352 cast
<RecordStorageLocation
>(Env3
.getStorageLocation(*FooDecl
));
2353 const auto *BarLoc3
=
2354 cast
<RecordStorageLocation
>(Env3
.getStorageLocation(*BarDecl
));
2355 EXPECT_FALSE(recordsEqual(*FooLoc3
, *BarLoc3
, Env3
));
2357 const auto *FooBazVal3
=
2358 cast
<IntegerValue
>(getFieldValue(FooLoc3
, *BazDecl
, Env3
));
2359 const auto *BarBazVal3
=
2360 cast
<IntegerValue
>(getFieldValue(BarLoc3
, *BazDecl
, Env3
));
2361 EXPECT_NE(FooBazVal3
, BarBazVal3
);
2366 // It's legal for the assignment operator to take its source parameter by value.
2367 // Check that we handle this correctly. (This is a repro -- we used to
2368 // assert-fail on this.)
2369 TEST(TransferTest
, AssignmentOperator_ArgByValue
) {
2370 std::string Code
= R
"(
2385 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2386 ASTContext
&ASTCtx
) {
2387 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2388 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2390 const auto &FooLoc
=
2391 getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "Foo");
2392 const auto &BarLoc
=
2393 getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "Bar");
2395 const auto *FooBazVal
=
2396 cast
<IntegerValue
>(getFieldValue(&FooLoc
, *BazDecl
, Env
));
2397 const auto *BarBazVal
=
2398 cast
<IntegerValue
>(getFieldValue(&BarLoc
, *BazDecl
, Env
));
2399 EXPECT_EQ(FooBazVal
, BarBazVal
);
2403 TEST(TransferTest
, AssignmentOperatorFromBase
) {
2404 std::string Code
= R
"(
2408 struct Derived : public Base {
2409 using Base::operator=;
2412 void target(Base B, Derived D) {
2422 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2423 ASTContext
&ASTCtx
) {
2424 const Environment
&EnvBefore
=
2425 getEnvironmentAtAnnotation(Results
, "before");
2426 const Environment
&EnvAfter
=
2427 getEnvironmentAtAnnotation(Results
, "after");
2430 getLocForDecl
<RecordStorageLocation
>(ASTCtx
, EnvBefore
, "B");
2432 getLocForDecl
<RecordStorageLocation
>(ASTCtx
, EnvBefore
, "D");
2434 EXPECT_NE(getFieldValue(&BLoc
, "base", ASTCtx
, EnvBefore
),
2435 getFieldValue(&DLoc
, "base", ASTCtx
, EnvBefore
));
2436 EXPECT_EQ(getFieldValue(&BLoc
, "base", ASTCtx
, EnvAfter
),
2437 getFieldValue(&DLoc
, "base", ASTCtx
, EnvAfter
));
2439 EXPECT_EQ(getFieldValue(&DLoc
, "derived", ASTCtx
, EnvBefore
),
2440 getFieldValue(&DLoc
, "derived", ASTCtx
, EnvAfter
));
2444 TEST(TransferTest
, AssignmentOperatorFromCallResult
) {
2445 std::string Code
= R
"(
2456 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2457 ASTContext
&ASTCtx
) {
2458 // As of this writing, we don't produce a `Value` for the call
2459 // `ReturnA()`. The only condition we're testing for is that the
2460 // analysis should not crash in this case.
2464 TEST(TransferTest
, AssignmentOperatorWithInitAndInheritance
) {
2465 // This is a crash repro.
2466 std::string Code
= R
"(
2467 struct B { int Foo; };
2468 struct S : public B {};
2473 S1 = S2; // Only Dst has InitListExpr.
2474 S3 = S1; // Only Src has InitListExpr.
2480 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2481 ASTContext
&ASTCtx
) {});
2484 TEST(TransferTest
, AssignmentOperatorReturnsVoid
) {
2485 // This is a crash repro.
2486 std::string Code
= R
"(
2488 void operator=(S&& other);
2498 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2499 ASTContext
&ASTCtx
) {});
2502 TEST(TransferTest
, AssignmentOperatorReturnsByValue
) {
2503 // This is a crash repro.
2504 std::string Code
= R
"(
2506 S operator=(const S&);
2514 // Test that the returned value is modeled by assigning to another value.
2522 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2523 ASTContext
&ASTCtx
) {
2524 const ValueDecl
*S1Decl
= findValueDecl(ASTCtx
, "S1");
2525 const ValueDecl
*S2Decl
= findValueDecl(ASTCtx
, "S2");
2526 const ValueDecl
*S3Decl
= findValueDecl(ASTCtx
, "S3");
2528 const Environment
&EnvBefore
=
2529 getEnvironmentAtAnnotation(Results
, "before");
2531 EXPECT_FALSE(recordsEqual(
2532 *EnvBefore
.get
<RecordStorageLocation
>(*S1Decl
),
2533 *EnvBefore
.get
<RecordStorageLocation
>(*S2Decl
), EnvBefore
));
2534 EXPECT_FALSE(recordsEqual(
2535 *EnvBefore
.get
<RecordStorageLocation
>(*S2Decl
),
2536 *EnvBefore
.get
<RecordStorageLocation
>(*S3Decl
), EnvBefore
));
2538 const Environment
&EnvAfter
=
2539 getEnvironmentAtAnnotation(Results
, "after");
2541 EXPECT_TRUE(recordsEqual(*EnvAfter
.get
<RecordStorageLocation
>(*S1Decl
),
2542 *EnvAfter
.get
<RecordStorageLocation
>(*S2Decl
),
2544 EXPECT_TRUE(recordsEqual(*EnvAfter
.get
<RecordStorageLocation
>(*S2Decl
),
2545 *EnvAfter
.get
<RecordStorageLocation
>(*S3Decl
),
2550 TEST(TransferTest
, AssignmentOperatorReturnsDifferentTypeByRef
) {
2551 // This is a crash repro.
2552 std::string Code
= R
"(
2553 struct DifferentType {};
2555 DifferentType& operator=(const S&);
2565 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2566 ASTContext
&ASTCtx
) {});
2569 TEST(TransferTest
, AssignmentOperatorReturnsDifferentTypeByValue
) {
2570 // This is a crash repro.
2571 std::string Code
= R
"(
2572 struct DifferentType {};
2574 DifferentType operator=(const S&);
2584 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2585 ASTContext
&ASTCtx
) {});
2588 TEST(TransferTest
, InitListExprAsXValue
) {
2589 // This is a crash repro.
2590 std::string Code
= R
"(
2598 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2599 ASTContext
&ASTCtx
) {
2600 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2601 const auto &FooVal
= getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "Foo");
2602 ASSERT_TRUE(FooVal
.formula().isLiteral(false));
2606 TEST(TransferTest
, ArrayInitListExprOneRecordElement
) {
2607 // This is a crash repro.
2608 std::string Code
= R
"cc(
2611 void target() { S foo[] = {S()}; }
2615 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2616 ASTContext
&ASTCtx
) {
2617 // Just verify that it doesn't crash.
2621 TEST(TransferTest
, InitListExprAsUnion
) {
2622 // This is a crash repro.
2623 std::string Code
= R
"cc(
2631 constexpr target() : F{nullptr} {
2632 int *null = nullptr;
2633 F.b; // Make sure we reference 'b' so it is modeled.
2640 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2641 ASTContext
&ASTCtx
) {
2642 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2644 auto &FLoc
= getFieldLoc
<RecordStorageLocation
>(
2645 *Env
.getThisPointeeStorageLocation(), "F", ASTCtx
);
2646 auto *AVal
= cast
<PointerValue
>(getFieldValue(&FLoc
, "a", ASTCtx
, Env
));
2647 EXPECT_EQ(AVal
, &getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "null"));
2648 EXPECT_EQ(getFieldValue(&FLoc
, "b", ASTCtx
, Env
), nullptr);
2652 TEST(TransferTest
, EmptyInitListExprForUnion
) {
2653 // This is a crash repro.
2654 std::string Code
= R
"cc(
2662 // Empty initializer list means that `F` is aggregate-initialized.
2663 // For a union, this has the effect that the first member of the union
2664 // is copy-initialized from an empty initializer list; in this specific
2665 // case, this has the effect of initializing `a` with null.
2666 constexpr target() : F{} {
2667 int *null = nullptr;
2668 F.b; // Make sure we reference 'b' so it is modeled.
2675 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2676 ASTContext
&ASTCtx
) {
2677 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2679 auto &FLoc
= getFieldLoc
<RecordStorageLocation
>(
2680 *Env
.getThisPointeeStorageLocation(), "F", ASTCtx
);
2681 auto *AVal
= cast
<PointerValue
>(getFieldValue(&FLoc
, "a", ASTCtx
, Env
));
2682 EXPECT_EQ(AVal
, &getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "null"));
2683 EXPECT_EQ(getFieldValue(&FLoc
, "b", ASTCtx
, Env
), nullptr);
2687 TEST(TransferTest
, EmptyInitListExprForStruct
) {
2688 std::string Code
= R
"cc(
2696 constexpr target() : F{} {
2697 int *NullIntPtr = nullptr;
2698 bool *NullBoolPtr = nullptr;
2705 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2706 ASTContext
&ASTCtx
) {
2707 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2709 auto &FLoc
= getFieldLoc
<RecordStorageLocation
>(
2710 *Env
.getThisPointeeStorageLocation(), "F", ASTCtx
);
2711 auto *AVal
= cast
<PointerValue
>(getFieldValue(&FLoc
, "a", ASTCtx
, Env
));
2713 &getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "NullIntPtr"));
2714 auto *BVal
= cast
<PointerValue
>(getFieldValue(&FLoc
, "b", ASTCtx
, Env
));
2716 &getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "NullBoolPtr"));
2720 TEST(TransferTest
, CopyConstructor
) {
2721 std::string Code
= R
"(
2736 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2737 ASTContext
&ASTCtx
) {
2738 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2739 ASSERT_THAT(FooDecl
, NotNull());
2741 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2742 ASSERT_THAT(BarDecl
, NotNull());
2744 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2745 ASSERT_THAT(BazDecl
, NotNull());
2749 const Environment
&Env
=
2750 getEnvironmentAtAnnotation(Results
, "after_copy");
2752 const auto *FooLoc
=
2753 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2754 const auto *BarLoc
=
2755 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*BarDecl
));
2757 // The records compare equal.
2758 EXPECT_TRUE(recordsEqual(*FooLoc
, *BarLoc
, Env
));
2760 // In particular, the value of `Baz` in both records is the same.
2761 const auto *FooBazVal
=
2762 cast
<IntegerValue
>(getFieldValue(FooLoc
, *BazDecl
, Env
));
2763 const auto *BarBazVal
=
2764 cast
<IntegerValue
>(getFieldValue(BarLoc
, *BazDecl
, Env
));
2765 EXPECT_EQ(FooBazVal
, BarBazVal
);
2770 const Environment
&Env
=
2771 getEnvironmentAtAnnotation(Results
, "after_update");
2773 const auto *FooLoc
=
2774 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2775 const auto *BarLoc
=
2776 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*BarDecl
));
2778 EXPECT_FALSE(recordsEqual(*FooLoc
, *BarLoc
, Env
));
2780 const auto *FooBazVal
=
2781 cast
<IntegerValue
>(getFieldValue(FooLoc
, *BazDecl
, Env
));
2782 const auto *BarBazVal
=
2783 cast
<IntegerValue
>(getFieldValue(BarLoc
, *BazDecl
, Env
));
2784 EXPECT_NE(FooBazVal
, BarBazVal
);
2789 TEST(TransferTest
, CopyConstructorWithDefaultArgument
) {
2790 std::string Code
= R
"(
2794 A(const A& a, bool def = true) { Baz = a.Baz; }
2806 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2807 ASTContext
&ASTCtx
) {
2808 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2809 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2811 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2812 ASSERT_THAT(FooDecl
, NotNull());
2814 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2815 ASSERT_THAT(BarDecl
, NotNull());
2817 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2818 ASSERT_THAT(BazDecl
, NotNull());
2820 const auto *FooLoc
=
2821 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2822 const auto *BarLoc
=
2823 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*BarDecl
));
2824 EXPECT_TRUE(recordsEqual(*FooLoc
, *BarLoc
, Env
));
2826 const auto *FooBazVal
=
2827 cast
<IntegerValue
>(getFieldValue(FooLoc
, *BazDecl
, Env
));
2828 const auto *BarBazVal
=
2829 cast
<IntegerValue
>(getFieldValue(BarLoc
, *BazDecl
, Env
));
2830 EXPECT_EQ(FooBazVal
, BarBazVal
);
2834 TEST(TransferTest
, CopyConstructorWithParens
) {
2835 std::string Code
= R
"(
2849 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2850 ASTContext
&ASTCtx
) {
2851 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
2852 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2854 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2855 ASSERT_THAT(FooDecl
, NotNull());
2857 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2858 ASSERT_THAT(BarDecl
, NotNull());
2860 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2861 ASSERT_THAT(BazDecl
, NotNull());
2863 const auto *FooLoc
=
2864 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
2865 const auto *BarLoc
=
2866 cast
<RecordStorageLocation
>(Env
.getStorageLocation(*BarDecl
));
2867 EXPECT_TRUE(recordsEqual(*FooLoc
, *BarLoc
, Env
));
2869 const auto *FooBazVal
=
2870 cast
<IntegerValue
>(getFieldValue(FooLoc
, *BazDecl
, Env
));
2871 const auto *BarBazVal
=
2872 cast
<IntegerValue
>(getFieldValue(BarLoc
, *BazDecl
, Env
));
2873 EXPECT_EQ(FooBazVal
, BarBazVal
);
2877 TEST(TransferTest
, CopyConstructorWithInitializerListAsSyntacticSugar
) {
2878 std::string Code
= R
"(
2891 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2892 ASTContext
&ASTCtx
) {
2893 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
2895 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2897 const auto &FooLoc
=
2898 getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "Foo");
2899 const auto &BarLoc
=
2900 getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "Bar");
2902 const auto *FooBazVal
=
2903 cast
<IntegerValue
>(getFieldValue(&FooLoc
, *BazDecl
, Env
));
2904 const auto *BarBazVal
=
2905 cast
<IntegerValue
>(getFieldValue(&BarLoc
, *BazDecl
, Env
));
2906 EXPECT_EQ(FooBazVal
, BarBazVal
);
2910 TEST(TransferTest
, CopyConstructorArgIsRefReturnedByFunction
) {
2911 // This is a crash repro.
2912 std::string Code
= R
"(
2914 const S &returnsSRef();
2921 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2922 ASTContext
&ASTCtx
) {});
2925 TEST(TransferTest
, MoveConstructor
) {
2926 std::string Code
= R
"(
2929 template <typename T> struct remove_reference { using type = T; };
2930 template <typename T> struct remove_reference<T&> { using type = T; };
2931 template <typename T> struct remove_reference<T&&> { using type = T; };
2933 template <typename T>
2934 using remove_reference_t = typename remove_reference<T>::type;
2936 template <typename T>
2937 std::remove_reference_t<T>&& move(T&& x);
2950 Foo = std::move(Bar);
2956 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
2957 ASTContext
&ASTCtx
) {
2958 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p1", "p2"));
2959 const Environment
&Env1
= getEnvironmentAtAnnotation(Results
, "p1");
2960 const Environment
&Env2
= getEnvironmentAtAnnotation(Results
, "p2");
2962 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
2963 ASSERT_THAT(FooDecl
, NotNull());
2965 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
2966 ASSERT_THAT(BarDecl
, NotNull());
2968 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
2969 ASSERT_THAT(BazDecl
, NotNull());
2971 const auto *FooLoc1
=
2972 cast
<RecordStorageLocation
>(Env1
.getStorageLocation(*FooDecl
));
2973 const auto *BarLoc1
=
2974 cast
<RecordStorageLocation
>(Env1
.getStorageLocation(*BarDecl
));
2976 EXPECT_FALSE(recordsEqual(*FooLoc1
, *BarLoc1
, Env1
));
2978 const auto *FooBazVal1
=
2979 cast
<IntegerValue
>(getFieldValue(FooLoc1
, *BazDecl
, Env1
));
2980 const auto *BarBazVal1
=
2981 cast
<IntegerValue
>(getFieldValue(BarLoc1
, *BazDecl
, Env1
));
2982 EXPECT_NE(FooBazVal1
, BarBazVal1
);
2984 const auto *FooLoc2
=
2985 cast
<RecordStorageLocation
>(Env2
.getStorageLocation(*FooDecl
));
2986 EXPECT_TRUE(recordsEqual(*FooLoc2
, Env2
, *BarLoc1
, Env1
));
2988 const auto *FooBazVal2
=
2989 cast
<IntegerValue
>(getFieldValue(FooLoc1
, *BazDecl
, Env2
));
2990 EXPECT_EQ(FooBazVal2
, BarBazVal1
);
2994 TEST(TransferTest
, BindTemporary
) {
2995 std::string Code
= R
"(
2997 virtual ~A() = default;
3002 void target(A Foo) {
3003 int Bar = A(Foo).Baz;
3009 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3010 ASTContext
&ASTCtx
) {
3011 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3012 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
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 ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
3021 ASSERT_THAT(BazDecl
, NotNull());
3023 const auto &FooLoc
=
3024 *cast
<RecordStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
3025 const auto *BarVal
= cast
<IntegerValue
>(Env
.getValue(*BarDecl
));
3026 EXPECT_EQ(BarVal
, getFieldValue(&FooLoc
, *BazDecl
, Env
));
3030 TEST(TransferTest
, ResultObjectLocation
) {
3031 std::string Code
= R
"(
3033 virtual ~A() = default;
3041 using ast_matchers::binaryOperator
;
3042 using ast_matchers::cxxBindTemporaryExpr
;
3043 using ast_matchers::cxxTemporaryObjectExpr
;
3044 using ast_matchers::exprWithCleanups
;
3045 using ast_matchers::has
;
3046 using ast_matchers::hasOperatorName
;
3047 using ast_matchers::hasRHS
;
3048 using ast_matchers::match
;
3049 using ast_matchers::selectFirst
;
3050 using ast_matchers::traverse
;
3053 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3054 ASTContext
&ASTCtx
) {
3055 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3057 // The expression `0, A()` in the code above produces the following
3058 // structure, consisting of four prvalues of record type.
3059 // `Env.getResultObjectLocation()` should return the same location for
3061 auto MatchResult
= match(
3065 hasOperatorName(","),
3066 hasRHS(cxxBindTemporaryExpr(
3067 has(cxxTemporaryObjectExpr().bind(
3073 auto *TOE
= selectFirst
<CXXTemporaryObjectExpr
>("toe", MatchResult
);
3074 ASSERT_NE(TOE
, nullptr);
3075 auto *Comma
= selectFirst
<BinaryOperator
>("comma", MatchResult
);
3076 ASSERT_NE(Comma
, nullptr);
3077 auto *EWC
= selectFirst
<ExprWithCleanups
>("ewc", MatchResult
);
3078 ASSERT_NE(EWC
, nullptr);
3079 auto *BTE
= selectFirst
<CXXBindTemporaryExpr
>("bte", MatchResult
);
3080 ASSERT_NE(BTE
, nullptr);
3082 RecordStorageLocation
&Loc
= Env
.getResultObjectLocation(*TOE
);
3083 EXPECT_EQ(&Loc
, &Env
.getResultObjectLocation(*Comma
));
3084 EXPECT_EQ(&Loc
, &Env
.getResultObjectLocation(*EWC
));
3085 EXPECT_EQ(&Loc
, &Env
.getResultObjectLocation(*BTE
));
3089 TEST(TransferTest
, ResultObjectLocationForDefaultArgExpr
) {
3090 std::string Code
= R
"(
3096 void funcWithDefaultArg(Outer O = {});
3098 funcWithDefaultArg();
3103 using ast_matchers::cxxDefaultArgExpr
;
3104 using ast_matchers::match
;
3105 using ast_matchers::selectFirst
;
3108 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3109 ASTContext
&ASTCtx
) {
3110 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3112 auto *DefaultArg
= selectFirst
<CXXDefaultArgExpr
>(
3114 match(cxxDefaultArgExpr().bind("default_arg"), ASTCtx
));
3115 ASSERT_NE(DefaultArg
, nullptr);
3117 // The values for default arguments aren't modeled; we merely verify
3118 // that we can get a result object location for a default arg.
3119 Env
.getResultObjectLocation(*DefaultArg
);
3123 TEST(TransferTest
, ResultObjectLocationForDefaultInitExpr
) {
3124 std::string Code
= R
"(
3135 using ast_matchers::cxxCtorInitializer
;
3136 using ast_matchers::match
;
3137 using ast_matchers::selectFirst
;
3140 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3141 ASTContext
&ASTCtx
) {
3142 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3144 const ValueDecl
*SField
= findValueDecl(ASTCtx
, "s");
3146 auto *CtorInit
= selectFirst
<CXXCtorInitializer
>(
3148 match(cxxCtorInitializer().bind("ctor_initializer"), ASTCtx
));
3149 ASSERT_NE(CtorInit
, nullptr);
3151 auto *DefaultInit
= cast
<CXXDefaultInitExpr
>(CtorInit
->getInit());
3153 RecordStorageLocation
&Loc
= Env
.getResultObjectLocation(*DefaultInit
);
3155 EXPECT_EQ(&Loc
, Env
.getThisPointeeStorageLocation()->getChild(*SField
));
3159 // This test ensures that CXXOperatorCallExpr returning prvalues are correctly
3160 // handled by the transfer functions, especially that `getResultObjectLocation`
3161 // correctly returns a storage location for those.
3162 TEST(TransferTest
, ResultObjectLocationForCXXOperatorCallExpr
) {
3163 std::string Code
= R
"(
3174 using ast_matchers::cxxOperatorCallExpr
;
3175 using ast_matchers::match
;
3176 using ast_matchers::selectFirst
;
3177 using ast_matchers::traverse
;
3180 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3181 ASTContext
&ASTCtx
) {
3182 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3184 auto *CallExpr
= selectFirst
<CXXOperatorCallExpr
>(
3186 match(cxxOperatorCallExpr().bind("call_expr"), ASTCtx
));
3188 EXPECT_NE(&Env
.getResultObjectLocation(*CallExpr
), nullptr);
3192 TEST(TransferTest
, ResultObjectLocationForInitListExpr
) {
3193 std::string Code
= R
"cc(
3196 struct Outer { Inner I; };
3199 Outer O = { Inner() };
3203 using ast_matchers::asString
;
3204 using ast_matchers::cxxConstructExpr
;
3205 using ast_matchers::hasType
;
3206 using ast_matchers::match
;
3207 using ast_matchers::selectFirst
;
3208 using ast_matchers::traverse
;
3211 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3212 ASTContext
&ASTCtx
) {
3213 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3215 auto *Construct
= selectFirst
<CXXConstructExpr
>(
3218 cxxConstructExpr(hasType(asString("Inner"))).bind("construct"),
3222 &Env
.getResultObjectLocation(*Construct
),
3223 &getFieldLoc(getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "O"),
3228 TEST(TransferTest
, ResultObjectLocationForParenInitListExpr
) {
3229 std::string Code
= R
"cc(
3232 struct Outer { Inner I; };
3239 using ast_matchers::asString
;
3240 using ast_matchers::cxxConstructExpr
;
3241 using ast_matchers::hasType
;
3242 using ast_matchers::match
;
3243 using ast_matchers::selectFirst
;
3244 using ast_matchers::traverse
;
3247 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3248 ASTContext
&ASTCtx
) {
3249 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3251 auto *Construct
= selectFirst
<CXXConstructExpr
>(
3254 cxxConstructExpr(hasType(asString("Inner"))).bind("construct"),
3258 &Env
.getResultObjectLocation(*Construct
),
3259 &getFieldLoc(getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "O"),
3262 LangStandard::lang_cxx20
);
3265 // Check that the `std::strong_ordering` object returned by builtin `<=>` has a
3266 // correctly modeled result object location.
3267 TEST(TransferTest
, ResultObjectLocationForBuiltinSpaceshipOperator
) {
3268 std::string Code
= R
"(
3270 // This is the minimal definition required to get
3271 // `Sema::CheckComparisonCategoryType()` to accept this fake.
3272 struct strong_ordering {
3273 enum class ordering { less, equal, greater };
3275 static const strong_ordering less;
3276 static const strong_ordering equivalent;
3277 static const strong_ordering equal;
3278 static const strong_ordering greater;
3281 inline constexpr strong_ordering strong_ordering::less =
3282 { strong_ordering::ordering::less };
3283 inline constexpr strong_ordering strong_ordering::equal =
3284 { strong_ordering::ordering::equal };
3285 inline constexpr strong_ordering strong_ordering::equivalent =
3286 { strong_ordering::ordering::equal };
3287 inline constexpr strong_ordering strong_ordering::greater =
3288 { strong_ordering::ordering::greater };
3290 void target(int i, int j) {
3291 auto ordering = i <=> j;
3295 using ast_matchers::binaryOperator
;
3296 using ast_matchers::hasOperatorName
;
3297 using ast_matchers::match
;
3298 using ast_matchers::selectFirst
;
3299 using ast_matchers::traverse
;
3302 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3303 ASTContext
&ASTCtx
) {
3304 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3306 auto *Spaceship
= selectFirst
<BinaryOperator
>(
3308 match(binaryOperator(hasOperatorName("<=>")).bind("op"), ASTCtx
));
3311 &Env
.getResultObjectLocation(*Spaceship
),
3312 &getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "ordering"));
3314 LangStandard::lang_cxx20
);
3317 TEST(TransferTest
, ResultObjectLocationForStdInitializerListExpr
) {
3318 std::string Code
= R
"(
3320 template <typename T>
3321 struct initializer_list { const T *a, *b; };
3325 std::initializer_list<int> list = {1};
3330 using ast_matchers::cxxStdInitializerListExpr
;
3331 using ast_matchers::match
;
3332 using ast_matchers::selectFirst
;
3335 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3336 ASTContext
&ASTCtx
) {
3337 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3339 auto *StdInitList
= selectFirst
<CXXStdInitializerListExpr
>(
3341 match(cxxStdInitializerListExpr().bind("std_init_list"), ASTCtx
));
3342 ASSERT_NE(StdInitList
, nullptr);
3344 EXPECT_EQ(&Env
.getResultObjectLocation(*StdInitList
),
3345 &getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "list"));
3349 TEST(TransferTest
, ResultObjectLocationForStmtExpr
) {
3350 std::string Code
= R
"(
3357 using ast_matchers::cxxConstructExpr
;
3358 using ast_matchers::match
;
3359 using ast_matchers::selectFirst
;
3360 using ast_matchers::traverse
;
3363 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3364 ASTContext
&ASTCtx
) {
3365 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3367 auto *Construct
= selectFirst
<CXXConstructExpr
>(
3368 "construct", match(cxxConstructExpr().bind("construct"), ASTCtx
));
3370 EXPECT_EQ(&Env
.getResultObjectLocation(*Construct
),
3371 &getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "s"));
3375 TEST(TransferTest
, ResultObjectLocationForBuiltinBitCastExpr
) {
3376 std::string Code
= R
"(
3377 struct S { int i; };
3378 void target(int i) {
3379 S s = __builtin_bit_cast(S, i);
3383 using ast_matchers::explicitCastExpr
;
3384 using ast_matchers::match
;
3385 using ast_matchers::selectFirst
;
3386 using ast_matchers::traverse
;
3389 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3390 ASTContext
&ASTCtx
) {
3391 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3393 auto *BuiltinBitCast
= selectFirst
<BuiltinBitCastExpr
>(
3394 "cast", match(explicitCastExpr().bind("cast"), ASTCtx
));
3396 EXPECT_EQ(&Env
.getResultObjectLocation(*BuiltinBitCast
),
3397 &getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "s"));
3401 TEST(TransferTest
, ResultObjectLocationForAtomicExpr
) {
3402 std::string Code
= R
"(
3404 void target(_Atomic(S) *ptr) {
3405 S s = __c11_atomic_load(ptr, __ATOMIC_SEQ_CST);
3409 using ast_matchers::atomicExpr
;
3410 using ast_matchers::match
;
3411 using ast_matchers::selectFirst
;
3412 using ast_matchers::traverse
;
3415 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3416 ASTContext
&ASTCtx
) {
3417 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3419 auto *Atomic
= selectFirst
<AtomicExpr
>(
3420 "atomic", match(atomicExpr().bind("atomic"), ASTCtx
));
3422 EXPECT_EQ(&Env
.getResultObjectLocation(*Atomic
),
3423 &getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "s"));
3427 TEST(TransferTest
, ResultObjectLocationPropagatesThroughConditionalOperator
) {
3428 std::string Code
= R
"(
3433 void target(bool b) {
3434 A a = b ? A(0) : A(1);
3438 using ast_matchers::cxxConstructExpr
;
3439 using ast_matchers::equals
;
3440 using ast_matchers::hasArgument
;
3441 using ast_matchers::integerLiteral
;
3442 using ast_matchers::match
;
3443 using ast_matchers::selectFirst
;
3444 using ast_matchers::traverse
;
3447 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3448 ASTContext
&ASTCtx
) {
3449 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3451 auto *ConstructExpr0
= selectFirst
<CXXConstructExpr
>(
3453 match(cxxConstructExpr(hasArgument(0, integerLiteral(equals(0))))
3456 auto *ConstructExpr1
= selectFirst
<CXXConstructExpr
>(
3458 match(cxxConstructExpr(hasArgument(0, integerLiteral(equals(1))))
3462 auto &ALoc
= getLocForDecl
<StorageLocation
>(ASTCtx
, Env
, "a");
3463 EXPECT_EQ(&Env
.getResultObjectLocation(*ConstructExpr0
), &ALoc
);
3464 EXPECT_EQ(&Env
.getResultObjectLocation(*ConstructExpr1
), &ALoc
);
3468 TEST(TransferTest
, ResultObjectLocationDontVisitNestedRecordDecl
) {
3469 // This is a crash repro.
3470 // We used to crash because when propagating result objects, we would visit
3471 // nested record and function declarations, but we don't model fields used
3473 std::string Code
= R
"(
3475 struct S2 { S1 s1; };
3486 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3487 ASTContext
&ASTCtx
) {});
3490 TEST(TransferTest
, ResultObjectLocationDontVisitUnevaluatedContexts
) {
3491 // This is a crash repro.
3492 // We used to crash because when propagating result objects, we would visit
3493 // unevaluated contexts, but we don't model fields used only in these.
3495 auto testFunction
= [](llvm::StringRef Code
, llvm::StringRef TargetFun
) {
3498 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3499 ASTContext
&ASTCtx
) {},
3500 LangStandard::lang_gnucxx17
,
3501 /* ApplyBuiltinTransfer= */ true, TargetFun
);
3504 std::string Code
= R
"cc(
3505 // Definitions needed for `typeid`.
3508 class bad_typeid {};
3512 struct S2 { S1 s1; };
3514 // We test each type of unevaluated context from a different target
3515 // function. Some types of unevaluated contexts may actually cause the
3516 // field `s1` to be modeled, and we don't want this to "pollute
" the tests
3517 // for the other unevaluated contexts.
3518 void decltypeTarget() {
3519 decltype(S2{}) Dummy;
3521 void typeofTarget() {
3524 void typeidTarget() {
3525 #if __has_feature(cxx_rtti)
3529 void sizeofTarget() {
3532 void noexceptTarget() {
3537 testFunction(Code
, "decltypeTarget");
3538 testFunction(Code
, "typeofTarget");
3539 testFunction(Code
, "typeidTarget");
3540 testFunction(Code
, "sizeofTarget");
3541 testFunction(Code
, "noexceptTarget");
3544 TEST(TransferTest
, StaticCast
) {
3545 std::string Code
= R
"(
3546 void target(int Foo) {
3547 int Bar = static_cast<int>(Foo);
3553 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3554 ASTContext
&ASTCtx
) {
3555 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3556 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3558 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3559 ASSERT_THAT(FooDecl
, NotNull());
3561 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3562 ASSERT_THAT(BarDecl
, NotNull());
3564 const auto *FooVal
= Env
.getValue(*FooDecl
);
3565 const auto *BarVal
= Env
.getValue(*BarDecl
);
3566 EXPECT_TRUE(isa
<IntegerValue
>(FooVal
));
3567 EXPECT_TRUE(isa
<IntegerValue
>(BarVal
));
3568 EXPECT_EQ(FooVal
, BarVal
);
3572 TEST(TransferTest
, IntegralCast
) {
3573 std::string Code
= R
"(
3574 void target(int Foo) {
3581 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3582 ASTContext
&ASTCtx
) {
3583 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3585 const auto &FooVal
= getValueForDecl
<IntegerValue
>(ASTCtx
, Env
, "Foo");
3586 const auto &BarVal
= getValueForDecl
<IntegerValue
>(ASTCtx
, Env
, "Bar");
3587 EXPECT_EQ(&FooVal
, &BarVal
);
3591 TEST(TransferTest
, IntegraltoBooleanCast
) {
3592 std::string Code
= R
"(
3593 void target(int Foo) {
3600 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3601 ASTContext
&ASTCtx
) {
3602 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3604 const auto &FooVal
= getValueForDecl(ASTCtx
, Env
, "Foo");
3605 const auto &BarVal
= getValueForDecl(ASTCtx
, Env
, "Bar");
3606 EXPECT_TRUE(isa
<IntegerValue
>(FooVal
));
3607 EXPECT_TRUE(isa
<BoolValue
>(BarVal
));
3611 TEST(TransferTest
, IntegralToBooleanCastFromBool
) {
3612 std::string Code
= R
"(
3613 void target(bool Foo) {
3621 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3622 ASTContext
&ASTCtx
) {
3623 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3625 const auto &FooVal
= getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "Foo");
3626 const auto &BarVal
= getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "Bar");
3627 EXPECT_EQ(&FooVal
, &BarVal
);
3631 TEST(TransferTest
, WidenBoolValueInIntegerVariable
) {
3632 // This is a crash repro.
3633 // This test sets up a case where we perform widening on an integer variable
3634 // that contains a `BoolValue` for the previous iteration and an
3635 // `IntegerValue` for the current iteration. We used to crash on this because
3636 // `widenDistinctValues()` assumed that if the previous iteration had a
3637 // `BoolValue`, the current iteration would too.
3638 // FIXME: The real fix here is to make sure we never store `BoolValue`s in
3639 // integer variables; see also the comment in `widenDistinctValues()`.
3640 std::string Code
= R
"cc(
3646 for (; s; s = s->next)
3651 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
3655 TEST(TransferTest
, NullToPointerCast
) {
3656 std::string Code
= R
"(
3657 using my_nullptr_t = decltype(nullptr);
3660 int *FooX = nullptr;
3661 int *FooY = nullptr;
3662 bool **Bar = nullptr;
3664 my_nullptr_t Null = 0;
3670 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3671 ASTContext
&ASTCtx
) {
3672 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3673 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3675 const ValueDecl
*FooXDecl
= findValueDecl(ASTCtx
, "FooX");
3676 ASSERT_THAT(FooXDecl
, NotNull());
3678 const ValueDecl
*FooYDecl
= findValueDecl(ASTCtx
, "FooY");
3679 ASSERT_THAT(FooYDecl
, NotNull());
3681 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3682 ASSERT_THAT(BarDecl
, NotNull());
3684 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
3685 ASSERT_THAT(BazDecl
, NotNull());
3687 const ValueDecl
*NullDecl
= findValueDecl(ASTCtx
, "Null");
3688 ASSERT_THAT(NullDecl
, NotNull());
3690 const auto *FooXVal
= cast
<PointerValue
>(Env
.getValue(*FooXDecl
));
3691 const auto *FooYVal
= cast
<PointerValue
>(Env
.getValue(*FooYDecl
));
3692 const auto *BarVal
= cast
<PointerValue
>(Env
.getValue(*BarDecl
));
3693 const auto *BazVal
= cast
<PointerValue
>(Env
.getValue(*BazDecl
));
3694 const auto *NullVal
= cast
<PointerValue
>(Env
.getValue(*NullDecl
));
3696 EXPECT_EQ(FooXVal
, FooYVal
);
3697 EXPECT_NE(FooXVal
, BarVal
);
3698 EXPECT_NE(FooXVal
, BazVal
);
3699 EXPECT_NE(BarVal
, BazVal
);
3701 const StorageLocation
&FooPointeeLoc
= FooXVal
->getPointeeLoc();
3702 EXPECT_TRUE(isa
<ScalarStorageLocation
>(FooPointeeLoc
));
3703 EXPECT_THAT(Env
.getValue(FooPointeeLoc
), IsNull());
3705 const StorageLocation
&BarPointeeLoc
= BarVal
->getPointeeLoc();
3706 EXPECT_TRUE(isa
<ScalarStorageLocation
>(BarPointeeLoc
));
3707 EXPECT_THAT(Env
.getValue(BarPointeeLoc
), IsNull());
3709 const StorageLocation
&BazPointeeLoc
= BazVal
->getPointeeLoc();
3710 EXPECT_TRUE(isa
<RecordStorageLocation
>(BazPointeeLoc
));
3711 EXPECT_EQ(BazVal
, &Env
.fork().getOrCreateNullPointerValue(
3712 BazPointeeLoc
.getType()));
3714 const StorageLocation
&NullPointeeLoc
= NullVal
->getPointeeLoc();
3715 EXPECT_TRUE(isa
<ScalarStorageLocation
>(NullPointeeLoc
));
3716 EXPECT_THAT(Env
.getValue(NullPointeeLoc
), IsNull());
3720 TEST(TransferTest
, PointerToMemberVariable
) {
3721 std::string Code
= R
"(
3726 int S::*MemberPointer = &S::i;
3732 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3733 ASTContext
&ASTCtx
) {
3734 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3736 const ValueDecl
*MemberPointerDecl
=
3737 findValueDecl(ASTCtx
, "MemberPointer");
3738 ASSERT_THAT(MemberPointerDecl
, NotNull());
3739 ASSERT_THAT(Env
.getValue(*MemberPointerDecl
), IsNull());
3743 TEST(TransferTest
, PointerToMemberFunction
) {
3744 std::string Code
= R
"(
3749 void (S::*MemberPointer)() = &S::Method;
3755 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3756 ASTContext
&ASTCtx
) {
3757 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3759 const ValueDecl
*MemberPointerDecl
=
3760 findValueDecl(ASTCtx
, "MemberPointer");
3761 ASSERT_THAT(MemberPointerDecl
, NotNull());
3762 ASSERT_THAT(Env
.getValue(*MemberPointerDecl
), IsNull());
3766 TEST(TransferTest
, NullToMemberPointerCast
) {
3767 std::string Code
= R
"(
3770 int Foo::*MemberPointer = nullptr;
3776 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3777 ASTContext
&ASTCtx
) {
3778 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3779 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3781 const ValueDecl
*MemberPointerDecl
=
3782 findValueDecl(ASTCtx
, "MemberPointer");
3783 ASSERT_THAT(MemberPointerDecl
, NotNull());
3784 ASSERT_THAT(Env
.getValue(*MemberPointerDecl
), IsNull());
3788 TEST(TransferTest
, AddrOfValue
) {
3789 std::string Code
= R
"(
3798 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3799 ASTContext
&ASTCtx
) {
3800 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3801 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3803 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3804 ASSERT_THAT(FooDecl
, NotNull());
3806 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3807 ASSERT_THAT(BarDecl
, NotNull());
3809 const auto *FooLoc
=
3810 cast
<ScalarStorageLocation
>(Env
.getStorageLocation(*FooDecl
));
3811 const auto *BarVal
= cast
<PointerValue
>(Env
.getValue(*BarDecl
));
3812 EXPECT_EQ(&BarVal
->getPointeeLoc(), FooLoc
);
3816 TEST(TransferTest
, AddrOfReference
) {
3817 std::string Code
= R
"(
3818 void target(int *Foo) {
3825 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3826 ASTContext
&ASTCtx
) {
3827 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
3828 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3830 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3831 ASSERT_THAT(FooDecl
, NotNull());
3833 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3834 ASSERT_THAT(BarDecl
, NotNull());
3836 const auto *FooVal
= cast
<PointerValue
>(Env
.getValue(*FooDecl
));
3837 const auto *BarVal
= cast
<PointerValue
>(Env
.getValue(*BarDecl
));
3838 EXPECT_EQ(&BarVal
->getPointeeLoc(), &FooVal
->getPointeeLoc());
3842 TEST(TransferTest
, Preincrement
) {
3843 std::string Code
= R
"(
3844 void target(int I) {
3845 (void)0; // [[before]]
3852 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3853 ASTContext
&ASTCtx
) {
3854 const Environment
&EnvBefore
=
3855 getEnvironmentAtAnnotation(Results
, "before");
3856 const Environment
&EnvAfter
=
3857 getEnvironmentAtAnnotation(Results
, "after");
3859 EXPECT_EQ(&getLocForDecl(ASTCtx
, EnvAfter
, "IRef"),
3860 &getLocForDecl(ASTCtx
, EnvBefore
, "I"));
3862 const ValueDecl
*IDecl
= findValueDecl(ASTCtx
, "I");
3863 EXPECT_NE(EnvBefore
.getValue(*IDecl
), nullptr);
3864 EXPECT_EQ(EnvAfter
.getValue(*IDecl
), nullptr);
3868 TEST(TransferTest
, Postincrement
) {
3869 std::string Code
= R
"(
3870 void target(int I) {
3871 (void)0; // [[before]]
3878 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3879 ASTContext
&ASTCtx
) {
3880 const Environment
&EnvBefore
=
3881 getEnvironmentAtAnnotation(Results
, "before");
3882 const Environment
&EnvAfter
=
3883 getEnvironmentAtAnnotation(Results
, "after");
3885 EXPECT_EQ(&getValueForDecl(ASTCtx
, EnvBefore
, "I"),
3886 &getValueForDecl(ASTCtx
, EnvAfter
, "OldVal"));
3888 const ValueDecl
*IDecl
= findValueDecl(ASTCtx
, "I");
3889 EXPECT_EQ(EnvAfter
.getValue(*IDecl
), nullptr);
3893 // We test just one of the compound assignment operators because we know the
3894 // code for propagating the storage location is shared among all of them.
3895 TEST(TransferTest
, AddAssign
) {
3896 std::string Code
= R
"(
3897 void target(int I) {
3898 int &IRef = (I += 1);
3904 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3905 ASTContext
&ASTCtx
) {
3906 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3908 EXPECT_EQ(&getLocForDecl(ASTCtx
, Env
, "IRef"),
3909 &getLocForDecl(ASTCtx
, Env
, "I"));
3913 TEST(TransferTest
, CannotAnalyzeFunctionTemplate
) {
3914 std::string Code
= R
"(
3915 template <typename T>
3919 checkDataflowWithNoopAnalysis(Code
),
3920 llvm::FailedWithMessage("Cannot analyze templated declarations"));
3923 TEST(TransferTest
, CannotAnalyzeMethodOfClassTemplate
) {
3924 std::string Code
= R
"(
3925 template <typename T>
3931 checkDataflowWithNoopAnalysis(Code
),
3932 llvm::FailedWithMessage("Cannot analyze templated declarations"));
3935 TEST(TransferTest
, VarDeclInitAssignConditionalOperator
) {
3936 std::string Code
= R
"(
3941 void target(A Foo, A Bar, bool Cond) {
3942 A Baz = Cond ? A(Foo) : A(Bar);
3943 // Make sure A::i is modeled.
3950 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3951 ASTContext
&ASTCtx
) {
3952 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
3954 auto *FooIVal
= cast
<IntegerValue
>(getFieldValue(
3955 &getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "Foo"), "i",
3957 auto *BarIVal
= cast
<IntegerValue
>(getFieldValue(
3958 &getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "Bar"), "i",
3960 auto *BazIVal
= cast
<IntegerValue
>(getFieldValue(
3961 &getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "Baz"), "i",
3964 EXPECT_NE(BazIVal
, FooIVal
);
3965 EXPECT_NE(BazIVal
, BarIVal
);
3969 TEST(TransferTest
, VarDeclInDoWhile
) {
3970 std::string Code
= R
"(
3971 void target(int *Foo) {
3982 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
3983 ASTContext
&ASTCtx
) {
3984 const Environment
&EnvInLoop
=
3985 getEnvironmentAtAnnotation(Results
, "in_loop");
3986 const Environment
&EnvAfterLoop
=
3987 getEnvironmentAtAnnotation(Results
, "after_loop");
3989 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
3990 ASSERT_THAT(FooDecl
, NotNull());
3992 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
3993 ASSERT_THAT(BarDecl
, NotNull());
3995 const auto *FooVal
=
3996 cast
<PointerValue
>(EnvAfterLoop
.getValue(*FooDecl
));
3997 const auto *FooPointeeVal
=
3998 cast
<IntegerValue
>(EnvAfterLoop
.getValue(FooVal
->getPointeeLoc()));
4000 const auto *BarVal
= cast
<IntegerValue
>(EnvInLoop
.getValue(*BarDecl
));
4001 EXPECT_EQ(BarVal
, FooPointeeVal
);
4003 ASSERT_THAT(EnvAfterLoop
.getValue(*BarDecl
), IsNull());
4007 TEST(TransferTest
, UnreachableAfterWhileTrue
) {
4008 std::string Code
= R
"(
4017 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4018 ASTContext
&ASTCtx
) {
4019 // The node after the while-true is pruned because it is trivially
4020 // known to be unreachable.
4021 ASSERT_TRUE(Results
.empty());
4025 TEST(TransferTest
, AggregateInitialization
) {
4026 std::string BracesCode
= R
"(
4037 void target(int BarArg, int FooArg, int QuxArg) {
4038 B Quux{BarArg, {FooArg}, QuxArg};
4043 std::string BraceElisionCode
= R
"(
4054 void target(int BarArg, int FooArg, int QuxArg) {
4055 B Quux = {BarArg, FooArg, QuxArg};
4060 for (const std::string
&Code
: {BracesCode
, BraceElisionCode
}) {
4063 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4064 ASTContext
&ASTCtx
) {
4065 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4066 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4068 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4069 ASSERT_THAT(FooDecl
, NotNull());
4071 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4072 ASSERT_THAT(BarDecl
, NotNull());
4074 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
4075 ASSERT_THAT(BazDecl
, NotNull());
4077 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
4078 ASSERT_THAT(QuxDecl
, NotNull());
4080 const ValueDecl
*FooArgDecl
= findValueDecl(ASTCtx
, "FooArg");
4081 ASSERT_THAT(FooArgDecl
, NotNull());
4083 const ValueDecl
*BarArgDecl
= findValueDecl(ASTCtx
, "BarArg");
4084 ASSERT_THAT(BarArgDecl
, NotNull());
4086 const ValueDecl
*QuxArgDecl
= findValueDecl(ASTCtx
, "QuxArg");
4087 ASSERT_THAT(QuxArgDecl
, NotNull());
4089 const ValueDecl
*QuuxDecl
= findValueDecl(ASTCtx
, "Quux");
4090 ASSERT_THAT(QuuxDecl
, NotNull());
4092 const auto *FooArgVal
= cast
<IntegerValue
>(Env
.getValue(*FooArgDecl
));
4093 const auto *BarArgVal
= cast
<IntegerValue
>(Env
.getValue(*BarArgDecl
));
4094 const auto *QuxArgVal
= cast
<IntegerValue
>(Env
.getValue(*QuxArgDecl
));
4096 const auto &QuuxLoc
=
4097 *cast
<RecordStorageLocation
>(Env
.getStorageLocation(*QuuxDecl
));
4098 const auto &BazLoc
=
4099 *cast
<RecordStorageLocation
>(QuuxLoc
.getChild(*BazDecl
));
4101 EXPECT_EQ(getFieldValue(&QuuxLoc
, *BarDecl
, Env
), BarArgVal
);
4102 EXPECT_EQ(getFieldValue(&BazLoc
, *FooDecl
, Env
), FooArgVal
);
4103 EXPECT_EQ(getFieldValue(&QuuxLoc
, *QuxDecl
, Env
), QuxArgVal
);
4105 // Check that fields initialized in an initializer list are always
4106 // modeled in other instances of the same type.
4107 const auto &OtherBLoc
=
4108 getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "OtherB");
4109 EXPECT_THAT(OtherBLoc
.getChild(*BarDecl
), NotNull());
4110 EXPECT_THAT(OtherBLoc
.getChild(*BazDecl
), NotNull());
4111 EXPECT_THAT(OtherBLoc
.getChild(*QuxDecl
), NotNull());
4116 TEST(TransferTest
, AggregateInitializationReferenceField
) {
4117 std::string Code
= R
"(
4122 void target(int i) {
4129 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4130 ASTContext
&ASTCtx
) {
4131 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4133 const ValueDecl
*RefFieldDecl
= findValueDecl(ASTCtx
, "RefField");
4135 auto &ILoc
= getLocForDecl
<StorageLocation
>(ASTCtx
, Env
, "i");
4136 auto &SLoc
= getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "s");
4138 EXPECT_EQ(SLoc
.getChild(*RefFieldDecl
), &ILoc
);
4142 TEST(TransferTest
, AggregateInitialization_NotExplicitlyInitializedField
) {
4143 std::string Code
= R
"(
4149 void target(int i) {
4156 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4157 ASTContext
&ASTCtx
) {
4158 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4160 const ValueDecl
*I1FieldDecl
= findValueDecl(ASTCtx
, "i1");
4161 const ValueDecl
*I2FieldDecl
= findValueDecl(ASTCtx
, "i2");
4163 auto &SLoc
= getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "s");
4165 auto &IValue
= getValueForDecl
<IntegerValue
>(ASTCtx
, Env
, "i");
4167 *cast
<IntegerValue
>(getFieldValue(&SLoc
, *I1FieldDecl
, Env
));
4168 EXPECT_EQ(&I1Value
, &IValue
);
4170 *cast
<IntegerValue
>(getFieldValue(&SLoc
, *I2FieldDecl
, Env
));
4171 EXPECT_NE(&I2Value
, &IValue
);
4175 TEST(TransferTest
, AggregateInitializationFunctionPointer
) {
4176 // This is a repro for an assertion failure.
4177 // nullptr takes on the type of a const function pointer, but its type was
4178 // asserted to be equal to the *unqualified* type of Field, which no longer
4179 // included the const.
4180 std::string Code
= R
"(
4182 void (*const Field)();
4191 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4192 ASTContext
&ASTCtx
) {});
4195 TEST(TransferTest
, AssignToUnionMember
) {
4196 std::string Code
= R
"(
4201 void target(int Bar) {
4209 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4210 ASTContext
&ASTCtx
) {
4211 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4212 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4214 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
4215 ASSERT_THAT(BazDecl
, NotNull());
4216 ASSERT_TRUE(BazDecl
->getType()->isUnionType());
4218 auto BazFields
= BazDecl
->getType()->getAsRecordDecl()->fields();
4219 FieldDecl
*FooDecl
= nullptr;
4220 for (FieldDecl
*Field
: BazFields
) {
4221 if (Field
->getNameAsString() == "Foo") {
4224 FAIL() << "Unexpected field: " << Field
->getNameAsString();
4227 ASSERT_THAT(FooDecl
, NotNull());
4229 const auto *BazLoc
= dyn_cast_or_null
<RecordStorageLocation
>(
4230 Env
.getStorageLocation(*BazDecl
));
4231 ASSERT_THAT(BazLoc
, NotNull());
4233 const auto *FooVal
=
4234 cast
<IntegerValue
>(getFieldValue(BazLoc
, *FooDecl
, Env
));
4236 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4237 ASSERT_THAT(BarDecl
, NotNull());
4238 const auto *BarLoc
= Env
.getStorageLocation(*BarDecl
);
4239 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
4241 EXPECT_EQ(Env
.getValue(*BarLoc
), FooVal
);
4245 TEST(TransferTest
, AssignFromBoolLiteral
) {
4246 std::string Code
= R
"(
4255 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4256 ASTContext
&ASTCtx
) {
4257 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4258 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4260 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4261 ASSERT_THAT(FooDecl
, NotNull());
4263 const auto *FooVal
=
4264 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*FooDecl
));
4265 ASSERT_THAT(FooVal
, NotNull());
4267 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4268 ASSERT_THAT(BarDecl
, NotNull());
4270 const auto *BarVal
=
4271 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BarDecl
));
4272 ASSERT_THAT(BarVal
, NotNull());
4274 EXPECT_EQ(FooVal
, &Env
.getBoolLiteralValue(true));
4275 EXPECT_EQ(BarVal
, &Env
.getBoolLiteralValue(false));
4279 TEST(TransferTest
, AssignFromCompositeBoolExpression
) {
4281 std::string Code
= R
"(
4282 void target(bool Foo, bool Bar, bool Qux) {
4283 bool Baz = (Foo) && (Bar || Qux);
4289 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4290 ASTContext
&ASTCtx
) {
4291 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4292 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4294 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4295 ASSERT_THAT(FooDecl
, NotNull());
4297 const auto *FooVal
=
4298 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*FooDecl
));
4299 ASSERT_THAT(FooVal
, NotNull());
4301 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4302 ASSERT_THAT(BarDecl
, NotNull());
4304 const auto *BarVal
=
4305 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BarDecl
));
4306 ASSERT_THAT(BarVal
, NotNull());
4308 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
4309 ASSERT_THAT(QuxDecl
, NotNull());
4311 const auto *QuxVal
=
4312 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*QuxDecl
));
4313 ASSERT_THAT(QuxVal
, NotNull());
4315 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
4316 ASSERT_THAT(BazDecl
, NotNull());
4318 const auto *BazVal
=
4319 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BazDecl
));
4320 ASSERT_THAT(BazVal
, NotNull());
4321 auto &A
= Env
.arena();
4322 EXPECT_EQ(&BazVal
->formula(),
4323 &A
.makeAnd(FooVal
->formula(),
4324 A
.makeOr(BarVal
->formula(), QuxVal
->formula())));
4329 std::string Code
= R
"(
4330 void target(bool Foo, bool Bar, bool Qux) {
4331 bool Baz = (Foo && Qux) || (Bar);
4337 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4338 ASTContext
&ASTCtx
) {
4339 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4340 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4342 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4343 ASSERT_THAT(FooDecl
, NotNull());
4345 const auto *FooVal
=
4346 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*FooDecl
));
4347 ASSERT_THAT(FooVal
, NotNull());
4349 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4350 ASSERT_THAT(BarDecl
, NotNull());
4352 const auto *BarVal
=
4353 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BarDecl
));
4354 ASSERT_THAT(BarVal
, NotNull());
4356 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
4357 ASSERT_THAT(QuxDecl
, NotNull());
4359 const auto *QuxVal
=
4360 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*QuxDecl
));
4361 ASSERT_THAT(QuxVal
, NotNull());
4363 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
4364 ASSERT_THAT(BazDecl
, NotNull());
4366 const auto *BazVal
=
4367 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BazDecl
));
4368 ASSERT_THAT(BazVal
, NotNull());
4369 auto &A
= Env
.arena();
4370 EXPECT_EQ(&BazVal
->formula(),
4371 &A
.makeOr(A
.makeAnd(FooVal
->formula(), QuxVal
->formula()),
4372 BarVal
->formula()));
4377 std::string Code
= R
"(
4378 void target(bool A, bool B, bool C, bool D) {
4379 bool Foo = ((A && B) && C) && D;
4385 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4386 ASTContext
&ASTCtx
) {
4387 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4388 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4390 const ValueDecl
*ADecl
= findValueDecl(ASTCtx
, "A");
4391 ASSERT_THAT(ADecl
, NotNull());
4393 const auto *AVal
= dyn_cast_or_null
<BoolValue
>(Env
.getValue(*ADecl
));
4394 ASSERT_THAT(AVal
, NotNull());
4396 const ValueDecl
*BDecl
= findValueDecl(ASTCtx
, "B");
4397 ASSERT_THAT(BDecl
, NotNull());
4399 const auto *BVal
= dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BDecl
));
4400 ASSERT_THAT(BVal
, NotNull());
4402 const ValueDecl
*CDecl
= findValueDecl(ASTCtx
, "C");
4403 ASSERT_THAT(CDecl
, NotNull());
4405 const auto *CVal
= dyn_cast_or_null
<BoolValue
>(Env
.getValue(*CDecl
));
4406 ASSERT_THAT(CVal
, NotNull());
4408 const ValueDecl
*DDecl
= findValueDecl(ASTCtx
, "D");
4409 ASSERT_THAT(DDecl
, NotNull());
4411 const auto *DVal
= dyn_cast_or_null
<BoolValue
>(Env
.getValue(*DDecl
));
4412 ASSERT_THAT(DVal
, NotNull());
4414 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4415 ASSERT_THAT(FooDecl
, NotNull());
4417 const auto *FooVal
=
4418 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*FooDecl
));
4419 ASSERT_THAT(FooVal
, NotNull());
4420 auto &A
= Env
.arena();
4423 &A
.makeAnd(A
.makeAnd(A
.makeAnd(AVal
->formula(), BVal
->formula()),
4430 TEST(TransferTest
, AssignFromBoolNegation
) {
4431 std::string Code
= R
"(
4440 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4441 ASTContext
&ASTCtx
) {
4442 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4443 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4445 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4446 ASSERT_THAT(FooDecl
, NotNull());
4448 const auto *FooVal
=
4449 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*FooDecl
));
4450 ASSERT_THAT(FooVal
, NotNull());
4452 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4453 ASSERT_THAT(BarDecl
, NotNull());
4455 const auto *BarVal
=
4456 dyn_cast_or_null
<BoolValue
>(Env
.getValue(*BarDecl
));
4457 ASSERT_THAT(BarVal
, NotNull());
4458 auto &A
= Env
.arena();
4459 EXPECT_EQ(&BarVal
->formula(), &A
.makeNot(FooVal
->formula()));
4463 TEST(TransferTest
, BuiltinExpect
) {
4464 std::string Code
= R
"(
4465 void target(long Foo) {
4466 long Bar = __builtin_expect(Foo, true);
4472 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4473 ASTContext
&ASTCtx
) {
4474 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4475 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4477 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4478 ASSERT_THAT(FooDecl
, NotNull());
4480 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4481 ASSERT_THAT(BarDecl
, NotNull());
4483 EXPECT_EQ(Env
.getValue(*FooDecl
), Env
.getValue(*BarDecl
));
4487 // `__builtin_expect` takes and returns a `long` argument, so other types
4488 // involve casts. This verifies that we identify the input and output in that
4490 TEST(TransferTest
, BuiltinExpectBoolArg
) {
4491 std::string Code
= R
"(
4492 void target(bool Foo) {
4493 bool Bar = __builtin_expect(Foo, true);
4499 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4500 ASTContext
&ASTCtx
) {
4501 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4502 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4504 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4505 ASSERT_THAT(FooDecl
, NotNull());
4507 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4508 ASSERT_THAT(BarDecl
, NotNull());
4510 EXPECT_EQ(Env
.getValue(*FooDecl
), Env
.getValue(*BarDecl
));
4514 TEST(TransferTest
, BuiltinUnreachable
) {
4515 std::string Code
= R
"(
4516 void target(bool Foo) {
4521 __builtin_unreachable();
4528 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4529 ASTContext
&ASTCtx
) {
4530 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4531 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4533 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4534 ASSERT_THAT(FooDecl
, NotNull());
4536 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4537 ASSERT_THAT(BarDecl
, NotNull());
4539 // `__builtin_unreachable` promises that the code is
4540 // unreachable, so the compiler treats the "then" branch as the
4541 // only possible predecessor of this statement.
4542 EXPECT_EQ(Env
.getValue(*FooDecl
), Env
.getValue(*BarDecl
));
4546 TEST(TransferTest
, BuiltinTrap
) {
4547 std::string Code
= R
"(
4548 void target(bool Foo) {
4560 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4561 ASTContext
&ASTCtx
) {
4562 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4563 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4565 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4566 ASSERT_THAT(FooDecl
, NotNull());
4568 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4569 ASSERT_THAT(BarDecl
, NotNull());
4571 // `__builtin_trap` ensures program termination, so only the
4572 // "then" branch is a predecessor of this statement.
4573 EXPECT_EQ(Env
.getValue(*FooDecl
), Env
.getValue(*BarDecl
));
4577 TEST(TransferTest
, BuiltinDebugTrap
) {
4578 std::string Code
= R
"(
4579 void target(bool Foo) {
4584 __builtin_debugtrap();
4591 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4592 ASTContext
&ASTCtx
) {
4593 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4594 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4596 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4597 ASSERT_THAT(FooDecl
, NotNull());
4599 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4600 ASSERT_THAT(BarDecl
, NotNull());
4602 // `__builtin_debugtrap` doesn't ensure program termination.
4603 EXPECT_NE(Env
.getValue(*FooDecl
), Env
.getValue(*BarDecl
));
4607 TEST(TransferTest
, StaticIntSingleVarDecl
) {
4608 std::string Code
= R
"(
4616 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4617 ASTContext
&ASTCtx
) {
4618 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4619 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4621 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4622 ASSERT_THAT(FooDecl
, NotNull());
4624 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
4625 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
4627 const Value
*FooVal
= Env
.getValue(*FooLoc
);
4628 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
4632 TEST(TransferTest
, StaticIntGroupVarDecl
) {
4633 std::string Code
= R
"(
4635 static int Foo, Bar;
4642 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4643 ASTContext
&ASTCtx
) {
4644 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4645 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4647 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4648 ASSERT_THAT(FooDecl
, NotNull());
4650 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4651 ASSERT_THAT(BarDecl
, NotNull());
4653 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
4654 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
4656 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
4657 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(BarLoc
));
4659 const Value
*FooVal
= Env
.getValue(*FooLoc
);
4660 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
4662 const Value
*BarVal
= Env
.getValue(*BarLoc
);
4663 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(BarVal
));
4665 EXPECT_NE(FooVal
, BarVal
);
4669 TEST(TransferTest
, GlobalIntVarDecl
) {
4670 std::string Code
= R
"(
4681 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4682 ASTContext
&ASTCtx
) {
4683 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4684 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4686 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4687 ASSERT_THAT(BarDecl
, NotNull());
4689 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
4690 ASSERT_THAT(BazDecl
, NotNull());
4692 const Value
*BarVal
= cast
<IntegerValue
>(Env
.getValue(*BarDecl
));
4693 const Value
*BazVal
= cast
<IntegerValue
>(Env
.getValue(*BazDecl
));
4694 EXPECT_EQ(BarVal
, BazVal
);
4698 TEST(TransferTest
, StaticMemberIntVarDecl
) {
4699 std::string Code
= R
"(
4712 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4713 ASTContext
&ASTCtx
) {
4714 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4715 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4717 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4718 ASSERT_THAT(BarDecl
, NotNull());
4720 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
4721 ASSERT_THAT(BazDecl
, NotNull());
4723 const Value
*BarVal
= cast
<IntegerValue
>(Env
.getValue(*BarDecl
));
4724 const Value
*BazVal
= cast
<IntegerValue
>(Env
.getValue(*BazDecl
));
4725 EXPECT_EQ(BarVal
, BazVal
);
4729 TEST(TransferTest
, StaticMemberRefVarDecl
) {
4730 std::string Code
= R
"(
4743 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4744 ASTContext
&ASTCtx
) {
4745 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4746 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4748 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4749 ASSERT_THAT(BarDecl
, NotNull());
4751 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
4752 ASSERT_THAT(BazDecl
, NotNull());
4754 const Value
*BarVal
= cast
<IntegerValue
>(Env
.getValue(*BarDecl
));
4755 const Value
*BazVal
= cast
<IntegerValue
>(Env
.getValue(*BazDecl
));
4756 EXPECT_EQ(BarVal
, BazVal
);
4760 TEST(TransferTest
, AssignMemberBeforeCopy
) {
4761 std::string Code
= R
"(
4777 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4778 ASTContext
&ASTCtx
) {
4779 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
4780 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4782 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
4783 ASSERT_THAT(FooDecl
, NotNull());
4785 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4786 ASSERT_THAT(BarDecl
, NotNull());
4788 const ValueDecl
*A1Decl
= findValueDecl(ASTCtx
, "A1");
4789 ASSERT_THAT(A1Decl
, NotNull());
4791 const ValueDecl
*A2Decl
= findValueDecl(ASTCtx
, "A2");
4792 ASSERT_THAT(A2Decl
, NotNull());
4794 const auto *BarVal
= cast
<IntegerValue
>(Env
.getValue(*BarDecl
));
4797 *cast
<RecordStorageLocation
>(Env
.getStorageLocation(*A2Decl
));
4798 EXPECT_EQ(getFieldValue(&A2Loc
, *FooDecl
, Env
), BarVal
);
4802 TEST(TransferTest
, BooleanEquality
) {
4803 std::string Code
= R
"(
4804 void target(bool Bar) {
4817 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4818 ASTContext
&ASTCtx
) {
4819 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p-then", "p-else"));
4820 const Environment
&EnvThen
=
4821 getEnvironmentAtAnnotation(Results
, "p-then");
4822 const Environment
&EnvElse
=
4823 getEnvironmentAtAnnotation(Results
, "p-else");
4825 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4826 ASSERT_THAT(BarDecl
, NotNull());
4828 auto &BarValThen
= getFormula(*BarDecl
, EnvThen
);
4829 EXPECT_TRUE(EnvThen
.proves(BarValThen
));
4831 auto &BarValElse
= getFormula(*BarDecl
, EnvElse
);
4832 EXPECT_TRUE(EnvElse
.proves(EnvElse
.arena().makeNot(BarValElse
)));
4836 TEST(TransferTest
, BooleanInequality
) {
4837 std::string Code
= R
"(
4838 void target(bool Bar) {
4851 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4852 ASTContext
&ASTCtx
) {
4853 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p-then", "p-else"));
4854 const Environment
&EnvThen
=
4855 getEnvironmentAtAnnotation(Results
, "p-then");
4856 const Environment
&EnvElse
=
4857 getEnvironmentAtAnnotation(Results
, "p-else");
4859 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
4860 ASSERT_THAT(BarDecl
, NotNull());
4862 auto &BarValThen
= getFormula(*BarDecl
, EnvThen
);
4863 EXPECT_TRUE(EnvThen
.proves(EnvThen
.arena().makeNot(BarValThen
)));
4865 auto &BarValElse
= getFormula(*BarDecl
, EnvElse
);
4866 EXPECT_TRUE(EnvElse
.proves(BarValElse
));
4870 TEST(TransferTest
, PointerEquality
) {
4871 std::string Code
= R
"cc(
4877 int *p_other = &i_other;
4878 int *null = nullptr;
4880 bool p1_eq_p1 = (p1 == p1);
4881 bool p1_eq_p2 = (p1 == p2);
4882 bool p1_eq_p_other = (p1 == p_other);
4884 bool p1_eq_null = (p1 == null);
4885 bool p1_eq_nullptr = (p1 == nullptr);
4886 bool null_eq_nullptr = (null == nullptr);
4887 bool nullptr_eq_nullptr = (nullptr == nullptr);
4889 // We won't duplicate all of the tests above with `!=`, as we know that
4890 // the implementation simply negates the result of the `==` comparison.
4891 // Instaed, just spot-check one case.
4892 bool p1_ne_p1 = (p1 != p1);
4899 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4900 ASTContext
&ASTCtx
) {
4901 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4903 // Check the we have indeed set things up so that `p1` and `p2` have
4904 // different pointer values.
4905 EXPECT_NE(&getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "p1"),
4906 &getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "p2"));
4908 EXPECT_EQ(&getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "p1_eq_p1"),
4909 &Env
.getBoolLiteralValue(true));
4910 EXPECT_EQ(&getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "p1_eq_p2"),
4911 &Env
.getBoolLiteralValue(true));
4912 EXPECT_TRUE(isa
<AtomicBoolValue
>(
4913 getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "p1_eq_p_other")));
4915 EXPECT_TRUE(isa
<AtomicBoolValue
>(
4916 getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "p1_eq_null")));
4917 EXPECT_TRUE(isa
<AtomicBoolValue
>(
4918 getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "p1_eq_nullptr")));
4919 EXPECT_EQ(&getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "null_eq_nullptr"),
4920 &Env
.getBoolLiteralValue(true));
4922 &getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "nullptr_eq_nullptr"),
4923 &Env
.getBoolLiteralValue(true));
4925 EXPECT_EQ(&getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "p1_ne_p1"),
4926 &Env
.getBoolLiteralValue(false));
4930 TEST(TransferTest
, PointerEqualityUnionMembers
) {
4931 std::string Code
= R
"cc(
4938 bool i1_eq_i2 = (&u.i1 == &u.i2);
4945 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4946 ASTContext
&ASTCtx
) {
4947 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4949 // FIXME: By the standard, `u.i1` and `u.i2` should have the same
4950 // address, but we don't yet model this property of union members
4951 // correctly. The result is therefore weaker than it could be (just an
4952 // atom rather than a true literal), though not wrong.
4953 EXPECT_TRUE(isa
<AtomicBoolValue
>(
4954 getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "i1_eq_i2")));
4958 TEST(TransferTest
, IntegerLiteralEquality
) {
4959 std::string Code
= R
"(
4961 bool equal = (42 == 42);
4967 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4968 ASTContext
&ASTCtx
) {
4969 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
4972 getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "equal").formula();
4973 EXPECT_TRUE(Env
.proves(Equal
));
4977 TEST(TransferTest
, CorrelatedBranches
) {
4978 std::string Code
= R
"(
4979 void target(bool B, bool C) {
4997 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
4998 ASTContext
&ASTCtx
) {
4999 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p0", "p1", "p2"));
5001 const ValueDecl
*CDecl
= findValueDecl(ASTCtx
, "C");
5002 ASSERT_THAT(CDecl
, NotNull());
5005 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p0");
5006 const ValueDecl
*BDecl
= findValueDecl(ASTCtx
, "B");
5007 ASSERT_THAT(BDecl
, NotNull());
5008 auto &BVal
= getFormula(*BDecl
, Env
);
5010 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(BVal
)));
5014 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p1");
5015 auto &CVal
= getFormula(*CDecl
, Env
);
5016 EXPECT_TRUE(Env
.proves(CVal
));
5020 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p2");
5021 auto &CVal
= getFormula(*CDecl
, Env
);
5022 EXPECT_TRUE(Env
.proves(CVal
));
5027 TEST(TransferTest
, LoopWithAssignmentConverges
) {
5028 std::string Code
= R
"(
5040 // The key property that we are verifying is implicit in `runDataflow` --
5041 // namely, that the analysis succeeds, rather than hitting the maximum number
5045 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5046 ASTContext
&ASTCtx
) {
5047 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5048 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5050 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
5051 ASSERT_THAT(BarDecl
, NotNull());
5053 auto &BarVal
= getFormula(*BarDecl
, Env
);
5054 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(BarVal
)));
5058 TEST(TransferTest
, LoopWithStagedAssignments
) {
5059 std::string Code
= R
"(
5075 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5076 ASTContext
&ASTCtx
) {
5077 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5078 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5080 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
5081 ASSERT_THAT(BarDecl
, NotNull());
5082 const ValueDecl
*ErrDecl
= findValueDecl(ASTCtx
, "Err");
5083 ASSERT_THAT(ErrDecl
, NotNull());
5085 auto &BarVal
= getFormula(*BarDecl
, Env
);
5086 auto &ErrVal
= getFormula(*ErrDecl
, Env
);
5087 EXPECT_TRUE(Env
.proves(BarVal
));
5088 // An unsound analysis, for example only evaluating the loop once, can
5089 // conclude that `Err` is false. So, we test that this conclusion is not
5091 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(ErrVal
)));
5095 TEST(TransferTest
, LoopWithReferenceAssignmentConverges
) {
5096 std::string Code
= R
"(
5108 // The key property that we are verifying is that the analysis succeeds,
5109 // rather than hitting the maximum number of iterations.
5112 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5113 ASTContext
&ASTCtx
) {
5114 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5115 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5117 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
5118 ASSERT_THAT(BarDecl
, NotNull());
5120 auto &BarVal
= getFormula(*BarDecl
, Env
);
5121 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(BarVal
)));
5125 TEST(TransferTest
, LoopWithStructReferenceAssignmentConverges
) {
5126 std::string Code
= R
"(
5131 void target(Lookup val, bool b) {
5132 const Lookup* l = nullptr;
5141 // The key property that we are verifying is implicit in `runDataflow` --
5142 // namely, that the analysis succeeds, rather than hitting the maximum number
5146 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5147 ASTContext
&ASTCtx
) {
5148 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p-inner", "p-outer"));
5149 const Environment
&InnerEnv
=
5150 getEnvironmentAtAnnotation(Results
, "p-inner");
5151 const Environment
&OuterEnv
=
5152 getEnvironmentAtAnnotation(Results
, "p-outer");
5154 const ValueDecl
*ValDecl
= findValueDecl(ASTCtx
, "val");
5155 ASSERT_THAT(ValDecl
, NotNull());
5157 const ValueDecl
*LDecl
= findValueDecl(ASTCtx
, "l");
5158 ASSERT_THAT(LDecl
, NotNull());
5161 auto *LVal
= dyn_cast
<PointerValue
>(InnerEnv
.getValue(*LDecl
));
5162 ASSERT_THAT(LVal
, NotNull());
5164 EXPECT_EQ(&LVal
->getPointeeLoc(),
5165 InnerEnv
.getStorageLocation(*ValDecl
));
5168 LVal
= dyn_cast
<PointerValue
>(OuterEnv
.getValue(*LDecl
));
5169 ASSERT_THAT(LVal
, NotNull());
5171 // The loop body may not have been executed, so we should not conclude
5172 // that `l` points to `val`.
5173 EXPECT_NE(&LVal
->getPointeeLoc(),
5174 OuterEnv
.getStorageLocation(*ValDecl
));
5178 TEST(TransferTest
, LoopDereferencingChangingPointerConverges
) {
5179 std::string Code
= R
"cc(
5180 bool some_condition();
5182 void target(int i1, int i2) {
5186 if (some_condition())
5193 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code
), llvm::Succeeded());
5196 TEST(TransferTest
, LoopDereferencingChangingRecordPointerConverges
) {
5197 std::string Code
= R
"cc(
5202 bool some_condition();
5204 void target(Lookup l1, Lookup l2) {
5208 if (some_condition())
5215 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code
), llvm::Succeeded());
5218 TEST(TransferTest
, LoopWithShortCircuitedConditionConverges
) {
5219 std::string Code
= R
"cc(
5224 while (foo() || foo()) {
5229 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code
), llvm::Succeeded());
5232 TEST(TransferTest
, LoopCanProveInvariantForBoolean
) {
5233 // Check that we can prove `b` is always false in the loop.
5234 // This test exercises the logic in `widenDistinctValues()` that preserves
5235 // information if the boolean can be proved to be either true or false in both
5236 // the previous and current iteration.
5237 std::string Code
= R
"cc(
5240 bool b = return_int() == 0;
5245 b = return_int() == 0;
5252 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5253 ASTContext
&ASTCtx
) {
5254 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5255 auto &BVal
= getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "b");
5256 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(BVal
.formula())));
5260 TEST(TransferTest
, DoesNotCrashOnUnionThisExpr
) {
5261 std::string Code
= R
"cc(
5273 // This is a crash regression test when calling the transfer function on a
5274 // `CXXThisExpr` that refers to a union.
5277 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
5279 LangStandard::lang_cxx17
, /*ApplyBuiltinTransfer=*/true, "operator=");
5282 TEST(TransferTest
, DoesNotCrashOnNullChildren
) {
5283 std::string Code
= (CoroutineLibrary
+ R
"cc(
5284 task target() noexcept {
5289 // This is a crash regression test when calling `AdornedCFG::build` on a
5290 // statement (in this case, the `CoroutineBodyStmt`) with null children.
5293 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &,
5295 LangStandard::lang_cxx20
, /*ApplyBuiltinTransfer=*/true);
5298 TEST(TransferTest
, StructuredBindingAssignFromStructIntMembersToRefs
) {
5299 std::string Code
= R
"(
5309 auto &FooRef = Baz.Foo;
5310 auto &BarRef = Baz.Bar;
5311 auto &[BoundFooRef, BoundBarRef] = Baz;
5317 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5318 ASTContext
&ASTCtx
) {
5319 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5320 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5322 const ValueDecl
*FooRefDecl
= findValueDecl(ASTCtx
, "FooRef");
5323 ASSERT_THAT(FooRefDecl
, NotNull());
5325 const ValueDecl
*BarRefDecl
= findValueDecl(ASTCtx
, "BarRef");
5326 ASSERT_THAT(BarRefDecl
, NotNull());
5328 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
5329 ASSERT_THAT(QuxDecl
, NotNull());
5331 const ValueDecl
*BoundFooRefDecl
= findValueDecl(ASTCtx
, "BoundFooRef");
5332 ASSERT_THAT(BoundFooRefDecl
, NotNull());
5334 const ValueDecl
*BoundBarRefDecl
= findValueDecl(ASTCtx
, "BoundBarRef");
5335 ASSERT_THAT(BoundBarRefDecl
, NotNull());
5337 const StorageLocation
*FooRefLoc
= Env
.getStorageLocation(*FooRefDecl
);
5338 ASSERT_THAT(FooRefLoc
, NotNull());
5340 const StorageLocation
*BarRefLoc
= Env
.getStorageLocation(*BarRefDecl
);
5341 ASSERT_THAT(BarRefLoc
, NotNull());
5343 const Value
*QuxVal
= Env
.getValue(*QuxDecl
);
5344 ASSERT_THAT(QuxVal
, NotNull());
5346 const StorageLocation
*BoundFooRefLoc
=
5347 Env
.getStorageLocation(*BoundFooRefDecl
);
5348 EXPECT_EQ(BoundFooRefLoc
, FooRefLoc
);
5350 const StorageLocation
*BoundBarRefLoc
=
5351 Env
.getStorageLocation(*BoundBarRefDecl
);
5352 EXPECT_EQ(BoundBarRefLoc
, BarRefLoc
);
5354 EXPECT_EQ(Env
.getValue(*BoundFooRefDecl
), QuxVal
);
5358 TEST(TransferTest
, StructuredBindingAssignFromStructRefMembersToRefs
) {
5359 std::string Code
= R
"(
5365 void target(A Baz) {
5368 auto &FooRef = Baz.Foo;
5369 auto &BarRef = Baz.Bar;
5370 auto &[BoundFooRef, BoundBarRef] = Baz;
5376 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5377 ASTContext
&ASTCtx
) {
5378 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5379 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5381 const ValueDecl
*FooRefDecl
= findValueDecl(ASTCtx
, "FooRef");
5382 ASSERT_THAT(FooRefDecl
, NotNull());
5384 const ValueDecl
*BarRefDecl
= findValueDecl(ASTCtx
, "BarRef");
5385 ASSERT_THAT(BarRefDecl
, NotNull());
5387 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
5388 ASSERT_THAT(QuxDecl
, NotNull());
5390 const ValueDecl
*BoundFooRefDecl
= findValueDecl(ASTCtx
, "BoundFooRef");
5391 ASSERT_THAT(BoundFooRefDecl
, NotNull());
5393 const ValueDecl
*BoundBarRefDecl
= findValueDecl(ASTCtx
, "BoundBarRef");
5394 ASSERT_THAT(BoundBarRefDecl
, NotNull());
5396 const StorageLocation
*FooRefLoc
= Env
.getStorageLocation(*FooRefDecl
);
5397 ASSERT_THAT(FooRefLoc
, NotNull());
5399 const StorageLocation
*BarRefLoc
= Env
.getStorageLocation(*BarRefDecl
);
5400 ASSERT_THAT(BarRefLoc
, NotNull());
5402 const Value
*QuxVal
= Env
.getValue(*QuxDecl
);
5403 ASSERT_THAT(QuxVal
, NotNull());
5405 const StorageLocation
*BoundFooRefLoc
=
5406 Env
.getStorageLocation(*BoundFooRefDecl
);
5407 EXPECT_EQ(BoundFooRefLoc
, FooRefLoc
);
5409 const StorageLocation
*BoundBarRefLoc
=
5410 Env
.getStorageLocation(*BoundBarRefDecl
);
5411 EXPECT_EQ(BoundBarRefLoc
, BarRefLoc
);
5413 EXPECT_EQ(Env
.getValue(*BoundFooRefDecl
), QuxVal
);
5417 TEST(TransferTest
, StructuredBindingAssignFromStructIntMembersToInts
) {
5418 std::string Code
= R
"(
5428 auto &FooRef = Baz.Foo;
5429 auto &BarRef = Baz.Bar;
5430 auto [BoundFoo, BoundBar] = Baz;
5436 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5437 ASTContext
&ASTCtx
) {
5438 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5439 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5441 const ValueDecl
*FooRefDecl
= findValueDecl(ASTCtx
, "FooRef");
5442 ASSERT_THAT(FooRefDecl
, NotNull());
5444 const ValueDecl
*BarRefDecl
= findValueDecl(ASTCtx
, "BarRef");
5445 ASSERT_THAT(BarRefDecl
, NotNull());
5447 const ValueDecl
*BoundFooDecl
= findValueDecl(ASTCtx
, "BoundFoo");
5448 ASSERT_THAT(BoundFooDecl
, NotNull());
5450 const ValueDecl
*BoundBarDecl
= findValueDecl(ASTCtx
, "BoundBar");
5451 ASSERT_THAT(BoundBarDecl
, NotNull());
5453 const ValueDecl
*QuxDecl
= findValueDecl(ASTCtx
, "Qux");
5454 ASSERT_THAT(QuxDecl
, NotNull());
5456 const StorageLocation
*FooRefLoc
= Env
.getStorageLocation(*FooRefDecl
);
5457 ASSERT_THAT(FooRefLoc
, NotNull());
5459 const StorageLocation
*BarRefLoc
= Env
.getStorageLocation(*BarRefDecl
);
5460 ASSERT_THAT(BarRefLoc
, NotNull());
5462 const Value
*QuxVal
= Env
.getValue(*QuxDecl
);
5463 ASSERT_THAT(QuxVal
, NotNull());
5465 const StorageLocation
*BoundFooLoc
=
5466 Env
.getStorageLocation(*BoundFooDecl
);
5467 EXPECT_NE(BoundFooLoc
, FooRefLoc
);
5469 const StorageLocation
*BoundBarLoc
=
5470 Env
.getStorageLocation(*BoundBarDecl
);
5471 EXPECT_NE(BoundBarLoc
, BarRefLoc
);
5473 EXPECT_EQ(Env
.getValue(*BoundFooDecl
), QuxVal
);
5477 TEST(TransferTest
, StructuredBindingAssignFromTupleLikeType
) {
5478 std::string Code
= R
"(
5481 template <class> struct tuple_size;
5482 template <std::size_t, class> struct tuple_element;
5483 template <class...> class tuple;
5486 template <class T, T v>
5487 struct size_helper { static const T value = v; };
5490 template <class... T>
5491 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {};
5493 template <std::size_t I, class... T>
5494 struct tuple_element<I, tuple<T...>> {
5495 using type = __type_pack_element<I, T...>;
5498 template <class...> class tuple {};
5500 template <std::size_t I, class... T>
5501 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
5504 std::tuple<bool, int> makeTuple();
5506 void target(bool B) {
5507 auto [BoundFoo, BoundBar] = makeTuple();
5509 // Include if-then-else to test interaction of `BindingDecl` with join.
5523 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5524 ASTContext
&ASTCtx
) {
5525 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p1", "p2"));
5526 const Environment
&Env1
= getEnvironmentAtAnnotation(Results
, "p1");
5528 const ValueDecl
*BoundFooDecl
= findBindingDecl(ASTCtx
, "BoundFoo");
5529 ASSERT_THAT(BoundFooDecl
, NotNull());
5531 const ValueDecl
*BoundBarDecl
= findBindingDecl(ASTCtx
, "BoundBar");
5532 ASSERT_THAT(BoundBarDecl
, NotNull());
5534 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
5535 ASSERT_THAT(BazDecl
, NotNull());
5537 // BindingDecls always map to references -- either lvalue or rvalue, so
5538 // we still need to skip here.
5539 const Value
*BoundFooValue
= Env1
.getValue(*BoundFooDecl
);
5540 ASSERT_THAT(BoundFooValue
, NotNull());
5541 EXPECT_TRUE(isa
<BoolValue
>(BoundFooValue
));
5543 const Value
*BoundBarValue
= Env1
.getValue(*BoundBarDecl
);
5544 ASSERT_THAT(BoundBarValue
, NotNull());
5545 EXPECT_TRUE(isa
<IntegerValue
>(BoundBarValue
));
5547 // Test that a `DeclRefExpr` to a `BindingDecl` works as expected.
5548 EXPECT_EQ(Env1
.getValue(*BazDecl
), BoundFooValue
);
5550 const Environment
&Env2
= getEnvironmentAtAnnotation(Results
, "p2");
5552 // Test that `BoundFooDecl` retains the value we expect, after the join.
5553 BoundFooValue
= Env2
.getValue(*BoundFooDecl
);
5554 EXPECT_EQ(Env2
.getValue(*BazDecl
), BoundFooValue
);
5558 TEST(TransferTest
, StructuredBindingAssignRefFromTupleLikeType
) {
5559 std::string Code
= R
"(
5562 template <class> struct tuple_size;
5563 template <std::size_t, class> struct tuple_element;
5564 template <class...> class tuple;
5567 template <class T, T v>
5568 struct size_helper { static const T value = v; };
5571 template <class... T>
5572 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {};
5574 template <std::size_t I, class... T>
5575 struct tuple_element<I, tuple<T...>> {
5576 using type = __type_pack_element<I, T...>;
5579 template <class...> class tuple {};
5581 template <std::size_t I, class... T>
5582 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
5585 std::tuple<bool, int> &getTuple();
5587 void target(bool B) {
5588 auto &[BoundFoo, BoundBar] = getTuple();
5590 // Include if-then-else to test interaction of `BindingDecl` with join.
5604 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5605 ASTContext
&ASTCtx
) {
5606 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p1", "p2"));
5607 const Environment
&Env1
= getEnvironmentAtAnnotation(Results
, "p1");
5609 const ValueDecl
*BoundFooDecl
= findBindingDecl(ASTCtx
, "BoundFoo");
5610 ASSERT_THAT(BoundFooDecl
, NotNull());
5612 const ValueDecl
*BoundBarDecl
= findBindingDecl(ASTCtx
, "BoundBar");
5613 ASSERT_THAT(BoundBarDecl
, NotNull());
5615 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
5616 ASSERT_THAT(BazDecl
, NotNull());
5618 const Value
*BoundFooValue
= Env1
.getValue(*BoundFooDecl
);
5619 ASSERT_THAT(BoundFooValue
, NotNull());
5620 EXPECT_TRUE(isa
<BoolValue
>(BoundFooValue
));
5622 const Value
*BoundBarValue
= Env1
.getValue(*BoundBarDecl
);
5623 ASSERT_THAT(BoundBarValue
, NotNull());
5624 EXPECT_TRUE(isa
<IntegerValue
>(BoundBarValue
));
5626 // Test that a `DeclRefExpr` to a `BindingDecl` (with reference type)
5627 // works as expected. We don't test aliasing properties of the
5628 // reference, because we don't model `std::get` and so have no way to
5629 // equate separate references into the tuple.
5630 EXPECT_EQ(Env1
.getValue(*BazDecl
), BoundFooValue
);
5632 const Environment
&Env2
= getEnvironmentAtAnnotation(Results
, "p2");
5634 // Test that `BoundFooDecl` retains the value we expect, after the join.
5635 BoundFooValue
= Env2
.getValue(*BoundFooDecl
);
5636 EXPECT_EQ(Env2
.getValue(*BazDecl
), BoundFooValue
);
5640 TEST(TransferTest
, BinaryOperatorComma
) {
5641 std::string Code
= R
"(
5642 void target(int Foo, int Bar) {
5643 int &Baz = (Foo, Bar);
5649 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5650 ASTContext
&ASTCtx
) {
5651 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5652 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5654 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
5655 ASSERT_THAT(BarDecl
, NotNull());
5657 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
5658 ASSERT_THAT(BazDecl
, NotNull());
5660 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
5661 ASSERT_THAT(BarLoc
, NotNull());
5663 const StorageLocation
*BazLoc
= Env
.getStorageLocation(*BazDecl
);
5664 EXPECT_EQ(BazLoc
, BarLoc
);
5668 TEST(TransferTest
, ConditionalOperatorValue
) {
5669 std::string Code
= R
"(
5670 void target(bool Cond, bool B1, bool B2) {
5671 bool JoinSame = Cond ? B1 : B1;
5672 bool JoinDifferent = Cond ? B1 : B2;
5678 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5679 ASTContext
&ASTCtx
) {
5680 Environment Env
= getEnvironmentAtAnnotation(Results
, "p").fork();
5682 auto &B1
= getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "B1");
5683 auto &B2
= getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "B2");
5684 auto &JoinSame
= getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "JoinSame");
5685 auto &JoinDifferent
=
5686 getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "JoinDifferent");
5688 EXPECT_EQ(&JoinSame
, &B1
);
5690 const Formula
&JoinDifferentEqB1
=
5691 Env
.arena().makeEquals(JoinDifferent
.formula(), B1
.formula());
5692 EXPECT_TRUE(Env
.allows(JoinDifferentEqB1
));
5693 EXPECT_FALSE(Env
.proves(JoinDifferentEqB1
));
5695 const Formula
&JoinDifferentEqB2
=
5696 Env
.arena().makeEquals(JoinDifferent
.formula(), B2
.formula());
5697 EXPECT_TRUE(Env
.allows(JoinDifferentEqB2
));
5698 EXPECT_FALSE(Env
.proves(JoinDifferentEqB1
));
5702 TEST(TransferTest
, ConditionalOperatorLocation
) {
5703 std::string Code
= R
"(
5704 void target(bool Cond, int I1, int I2) {
5705 int &JoinSame = Cond ? I1 : I1;
5706 int &JoinDifferent = Cond ? I1 : I2;
5712 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5713 ASTContext
&ASTCtx
) {
5714 Environment Env
= getEnvironmentAtAnnotation(Results
, "p").fork();
5716 StorageLocation
&I1
= getLocForDecl(ASTCtx
, Env
, "I1");
5717 StorageLocation
&I2
= getLocForDecl(ASTCtx
, Env
, "I2");
5718 StorageLocation
&JoinSame
= getLocForDecl(ASTCtx
, Env
, "JoinSame");
5719 StorageLocation
&JoinDifferent
=
5720 getLocForDecl(ASTCtx
, Env
, "JoinDifferent");
5722 EXPECT_EQ(&JoinSame
, &I1
);
5724 EXPECT_NE(&JoinDifferent
, &I1
);
5725 EXPECT_NE(&JoinDifferent
, &I2
);
5729 TEST(TransferTest
, ConditionalOperatorOnConstantExpr
) {
5730 // This is a regression test: We used to crash when a `ConstantExpr` was used
5731 // in the branches of a conditional operator.
5732 std::string Code
= R
"cc(
5733 consteval bool identity(bool B) { return B; }
5734 void target(bool Cond) {
5735 bool JoinTrueTrue = Cond ? identity(true) : identity(true);
5736 bool JoinTrueFalse = Cond ? identity(true) : identity(false);
5742 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5743 ASTContext
&ASTCtx
) {
5744 Environment Env
= getEnvironmentAtAnnotation(Results
, "p").fork();
5746 auto &JoinTrueTrue
=
5747 getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "JoinTrueTrue");
5748 // FIXME: This test documents the current behavior, namely that we
5749 // don't actually use the constant result of the `ConstantExpr` and
5750 // instead treat it like a normal function call.
5751 EXPECT_EQ(JoinTrueTrue
.formula().kind(), Formula::Kind::AtomRef
);
5752 // EXPECT_TRUE(JoinTrueTrue.formula().literal());
5754 auto &JoinTrueFalse
=
5755 getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "JoinTrueFalse");
5756 EXPECT_EQ(JoinTrueFalse
.formula().kind(), Formula::Kind::AtomRef
);
5758 LangStandard::lang_cxx20
);
5761 TEST(TransferTest
, IfStmtBranchExtendsFlowCondition
) {
5762 std::string Code
= R
"(
5763 void target(bool Foo) {
5775 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5776 ASTContext
&ASTCtx
) {
5777 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("if_then", "if_else"));
5778 const Environment
&ThenEnv
=
5779 getEnvironmentAtAnnotation(Results
, "if_then");
5780 const Environment
&ElseEnv
=
5781 getEnvironmentAtAnnotation(Results
, "if_else");
5783 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5784 ASSERT_THAT(FooDecl
, NotNull());
5786 auto &ThenFooVal
= getFormula(*FooDecl
, ThenEnv
);
5787 EXPECT_TRUE(ThenEnv
.proves(ThenFooVal
));
5789 auto &ElseFooVal
= getFormula(*FooDecl
, ElseEnv
);
5790 EXPECT_TRUE(ElseEnv
.proves(ElseEnv
.arena().makeNot(ElseFooVal
)));
5794 TEST(TransferTest
, WhileStmtBranchExtendsFlowCondition
) {
5795 std::string Code
= R
"(
5796 void target(bool Foo) {
5807 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5808 ASTContext
&ASTCtx
) {
5809 ASSERT_THAT(Results
.keys(),
5810 UnorderedElementsAre("loop_body", "after_loop"));
5811 const Environment
&LoopBodyEnv
=
5812 getEnvironmentAtAnnotation(Results
, "loop_body");
5813 const Environment
&AfterLoopEnv
=
5814 getEnvironmentAtAnnotation(Results
, "after_loop");
5816 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5817 ASSERT_THAT(FooDecl
, NotNull());
5819 auto &LoopBodyFooVal
= getFormula(*FooDecl
, LoopBodyEnv
);
5820 EXPECT_TRUE(LoopBodyEnv
.proves(LoopBodyFooVal
));
5822 auto &AfterLoopFooVal
= getFormula(*FooDecl
, AfterLoopEnv
);
5824 AfterLoopEnv
.proves(AfterLoopEnv
.arena().makeNot(AfterLoopFooVal
)));
5828 TEST(TransferTest
, DoWhileStmtBranchExtendsFlowCondition
) {
5829 std::string Code
= R
"(
5830 void target(bool Foo) {
5843 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5844 ASTContext
&ASTCtx
) {
5845 ASSERT_THAT(Results
.keys(),
5846 UnorderedElementsAre("loop_body", "after_loop"));
5847 const Environment
&LoopBodyEnv
=
5848 getEnvironmentAtAnnotation(Results
, "loop_body");
5849 const Environment
&AfterLoopEnv
=
5850 getEnvironmentAtAnnotation(Results
, "after_loop");
5851 auto &A
= AfterLoopEnv
.arena();
5853 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5854 ASSERT_THAT(FooDecl
, NotNull());
5856 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
5857 ASSERT_THAT(BarDecl
, NotNull());
5859 auto &LoopBodyFooVal
= getFormula(*FooDecl
, LoopBodyEnv
);
5860 auto &LoopBodyBarVal
= getFormula(*BarDecl
, LoopBodyEnv
);
5862 LoopBodyEnv
.proves(A
.makeOr(LoopBodyBarVal
, LoopBodyFooVal
)));
5864 auto &AfterLoopFooVal
= getFormula(*FooDecl
, AfterLoopEnv
);
5865 auto &AfterLoopBarVal
= getFormula(*BarDecl
, AfterLoopEnv
);
5866 EXPECT_TRUE(AfterLoopEnv
.proves(A
.makeNot(AfterLoopFooVal
)));
5867 EXPECT_TRUE(AfterLoopEnv
.proves(A
.makeNot(AfterLoopBarVal
)));
5871 TEST(TransferTest
, ForStmtBranchExtendsFlowCondition
) {
5872 std::string Code
= R
"(
5873 void target(bool Foo) {
5884 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5885 ASTContext
&ASTCtx
) {
5886 ASSERT_THAT(Results
.keys(),
5887 UnorderedElementsAre("loop_body", "after_loop"));
5888 const Environment
&LoopBodyEnv
=
5889 getEnvironmentAtAnnotation(Results
, "loop_body");
5890 const Environment
&AfterLoopEnv
=
5891 getEnvironmentAtAnnotation(Results
, "after_loop");
5893 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5894 ASSERT_THAT(FooDecl
, NotNull());
5896 auto &LoopBodyFooVal
= getFormula(*FooDecl
, LoopBodyEnv
);
5897 EXPECT_TRUE(LoopBodyEnv
.proves(LoopBodyFooVal
));
5899 auto &AfterLoopFooVal
= getFormula(*FooDecl
, AfterLoopEnv
);
5901 AfterLoopEnv
.proves(AfterLoopEnv
.arena().makeNot(AfterLoopFooVal
)));
5905 TEST(TransferTest
, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition
) {
5906 std::string Code
= R
"(
5907 void target(bool Foo) {
5916 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5917 ASTContext
&ASTCtx
) {
5918 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("loop_body"));
5919 const Environment
&LoopBodyEnv
=
5920 getEnvironmentAtAnnotation(Results
, "loop_body");
5922 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5923 ASSERT_THAT(FooDecl
, NotNull());
5925 auto &LoopBodyFooVal
= getFormula(*FooDecl
, LoopBodyEnv
);
5926 EXPECT_FALSE(LoopBodyEnv
.proves(LoopBodyFooVal
));
5930 TEST(TransferTest
, ContextSensitiveOptionDisabled
) {
5931 std::string Code
= R
"(
5933 void SetBool(bool &Var) { Var = true; }
5936 bool Foo = GiveBool();
5943 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5944 ASTContext
&ASTCtx
) {
5945 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5946 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5948 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
5949 ASSERT_THAT(FooDecl
, NotNull());
5951 auto &FooVal
= getFormula(*FooDecl
, Env
);
5952 EXPECT_FALSE(Env
.proves(FooVal
));
5953 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(FooVal
)));
5955 {BuiltinOptions
{/*.ContextSensitiveOpts=*/std::nullopt
}});
5958 TEST(TransferTest
, ContextSensitiveReturnReference
) {
5959 std::string Code
= R
"(
5961 S& target(bool b, S &s) {
5968 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5969 ASTContext
&ASTCtx
) {
5970 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5972 const ValueDecl
*SDecl
= findValueDecl(ASTCtx
, "s");
5973 ASSERT_THAT(SDecl
, NotNull());
5975 auto *SLoc
= Env
.getStorageLocation(*SDecl
);
5976 ASSERT_THAT(SLoc
, NotNull());
5978 ASSERT_THAT(Env
.getReturnStorageLocation(), Eq(SLoc
));
5980 {BuiltinOptions
{ContextSensitiveOptions
{}}});
5983 // This test is a regression test, based on a real crash.
5984 TEST(TransferTest
, ContextSensitiveReturnReferenceWithConditionalOperator
) {
5985 std::string Code
= R
"(
5987 S& target(bool b, S &s) {
5994 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
5995 ASTContext
&ASTCtx
) {
5996 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
5997 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
5999 const ValueDecl
*SDecl
= findValueDecl(ASTCtx
, "s");
6000 ASSERT_THAT(SDecl
, NotNull());
6002 auto *SLoc
= Env
.getStorageLocation(*SDecl
);
6003 EXPECT_THAT(SLoc
, NotNull());
6005 auto *Loc
= Env
.getReturnStorageLocation();
6006 EXPECT_THAT(Loc
, NotNull());
6008 EXPECT_EQ(Loc
, SLoc
);
6010 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6013 TEST(TransferTest
, ContextSensitiveReturnOneOfTwoReferences
) {
6014 std::string Code
= R
"(
6016 S &callee(bool b, S &s1_parm, S &s2_parm) {
6022 void target(bool b) {
6027 S &return_dont_know = callee(b, s1, s2);
6033 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6034 ASTContext
&ASTCtx
) {
6035 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6037 const ValueDecl
*S1
= findValueDecl(ASTCtx
, "s1");
6038 ASSERT_THAT(S1
, NotNull());
6039 const ValueDecl
*S2
= findValueDecl(ASTCtx
, "s2");
6040 ASSERT_THAT(S2
, NotNull());
6041 const ValueDecl
*ReturnS1
= findValueDecl(ASTCtx
, "return_s1");
6042 ASSERT_THAT(ReturnS1
, NotNull());
6043 const ValueDecl
*ReturnS2
= findValueDecl(ASTCtx
, "return_s2");
6044 ASSERT_THAT(ReturnS2
, NotNull());
6045 const ValueDecl
*ReturnDontKnow
=
6046 findValueDecl(ASTCtx
, "return_dont_know");
6047 ASSERT_THAT(ReturnDontKnow
, NotNull());
6049 StorageLocation
*S1Loc
= Env
.getStorageLocation(*S1
);
6050 StorageLocation
*S2Loc
= Env
.getStorageLocation(*S2
);
6052 EXPECT_THAT(Env
.getStorageLocation(*ReturnS1
), Eq(S1Loc
));
6053 EXPECT_THAT(Env
.getStorageLocation(*ReturnS2
), Eq(S2Loc
));
6055 // In the case where we don't have a consistent storage location for
6056 // the return value, the framework creates a new storage location, which
6057 // should be different from the storage locations of `s1` and `s2`.
6058 EXPECT_THAT(Env
.getStorageLocation(*ReturnDontKnow
), Ne(S1Loc
));
6059 EXPECT_THAT(Env
.getStorageLocation(*ReturnDontKnow
), Ne(S2Loc
));
6061 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6064 TEST(TransferTest
, ContextSensitiveDepthZero
) {
6065 std::string Code
= R
"(
6067 void SetBool(bool &Var) { Var = true; }
6070 bool Foo = GiveBool();
6077 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6078 ASTContext
&ASTCtx
) {
6079 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6080 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6082 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6083 ASSERT_THAT(FooDecl
, NotNull());
6085 auto &FooVal
= getFormula(*FooDecl
, Env
);
6086 EXPECT_FALSE(Env
.proves(FooVal
));
6087 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(FooVal
)));
6089 {BuiltinOptions
{ContextSensitiveOptions
{/*.Depth=*/0}}});
6092 TEST(TransferTest
, ContextSensitiveSetTrue
) {
6093 std::string Code
= R
"(
6095 void SetBool(bool &Var) { Var = true; }
6098 bool Foo = GiveBool();
6105 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6106 ASTContext
&ASTCtx
) {
6107 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6108 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6110 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6111 ASSERT_THAT(FooDecl
, NotNull());
6113 auto &FooVal
= getFormula(*FooDecl
, Env
);
6114 EXPECT_TRUE(Env
.proves(FooVal
));
6116 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6119 TEST(TransferTest
, ContextSensitiveSetFalse
) {
6120 std::string Code
= R
"(
6122 void SetBool(bool &Var) { Var = false; }
6125 bool Foo = GiveBool();
6132 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6133 ASTContext
&ASTCtx
) {
6134 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6135 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6137 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6138 ASSERT_THAT(FooDecl
, NotNull());
6140 auto &FooVal
= getFormula(*FooDecl
, Env
);
6141 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(FooVal
)));
6143 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6146 TEST(TransferTest
, ContextSensitiveSetBothTrueAndFalse
) {
6147 std::string Code
= R
"(
6149 void SetBool(bool &Var, bool Val) { Var = Val; }
6152 bool Foo = GiveBool();
6153 bool Bar = GiveBool();
6155 SetBool(Bar, false);
6161 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6162 ASTContext
&ASTCtx
) {
6163 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6164 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6165 auto &A
= Env
.arena();
6167 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6168 ASSERT_THAT(FooDecl
, NotNull());
6170 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
6171 ASSERT_THAT(BarDecl
, NotNull());
6173 auto &FooVal
= getFormula(*FooDecl
, Env
);
6174 EXPECT_TRUE(Env
.proves(FooVal
));
6175 EXPECT_FALSE(Env
.proves(A
.makeNot(FooVal
)));
6177 auto &BarVal
= getFormula(*BarDecl
, Env
);
6178 EXPECT_FALSE(Env
.proves(BarVal
));
6179 EXPECT_TRUE(Env
.proves(A
.makeNot(BarVal
)));
6181 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6184 TEST(TransferTest
, ContextSensitiveSetTwoLayersDepthOne
) {
6185 std::string Code
= R
"(
6187 void SetBool1(bool &Var) { Var = true; }
6188 void SetBool2(bool &Var) { SetBool1(Var); }
6191 bool Foo = GiveBool();
6198 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6199 ASTContext
&ASTCtx
) {
6200 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6201 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6203 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6204 ASSERT_THAT(FooDecl
, NotNull());
6206 auto &FooVal
= getFormula(*FooDecl
, Env
);
6207 EXPECT_FALSE(Env
.proves(FooVal
));
6208 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(FooVal
)));
6210 {BuiltinOptions
{ContextSensitiveOptions
{/*.Depth=*/1}}});
6213 TEST(TransferTest
, ContextSensitiveSetTwoLayersDepthTwo
) {
6214 std::string Code
= R
"(
6216 void SetBool1(bool &Var) { Var = true; }
6217 void SetBool2(bool &Var) { SetBool1(Var); }
6220 bool Foo = GiveBool();
6227 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6228 ASTContext
&ASTCtx
) {
6229 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6230 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6232 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6233 ASSERT_THAT(FooDecl
, NotNull());
6235 auto &FooVal
= getFormula(*FooDecl
, Env
);
6236 EXPECT_TRUE(Env
.proves(FooVal
));
6238 {BuiltinOptions
{ContextSensitiveOptions
{/*.Depth=*/2}}});
6241 TEST(TransferTest
, ContextSensitiveSetThreeLayersDepthTwo
) {
6242 std::string Code
= R
"(
6244 void SetBool1(bool &Var) { Var = true; }
6245 void SetBool2(bool &Var) { SetBool1(Var); }
6246 void SetBool3(bool &Var) { SetBool2(Var); }
6249 bool Foo = GiveBool();
6256 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6257 ASTContext
&ASTCtx
) {
6258 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6259 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6261 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6262 ASSERT_THAT(FooDecl
, NotNull());
6264 auto &FooVal
= getFormula(*FooDecl
, Env
);
6265 EXPECT_FALSE(Env
.proves(FooVal
));
6266 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(FooVal
)));
6268 {BuiltinOptions
{ContextSensitiveOptions
{/*.Depth=*/2}}});
6271 TEST(TransferTest
, ContextSensitiveSetThreeLayersDepthThree
) {
6272 std::string Code
= R
"(
6274 void SetBool1(bool &Var) { Var = true; }
6275 void SetBool2(bool &Var) { SetBool1(Var); }
6276 void SetBool3(bool &Var) { SetBool2(Var); }
6279 bool Foo = GiveBool();
6286 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6287 ASTContext
&ASTCtx
) {
6288 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6289 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6291 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6292 ASSERT_THAT(FooDecl
, NotNull());
6294 auto &FooVal
= getFormula(*FooDecl
, Env
);
6295 EXPECT_TRUE(Env
.proves(FooVal
));
6297 {BuiltinOptions
{ContextSensitiveOptions
{/*.Depth=*/3}}});
6300 TEST(TransferTest
, ContextSensitiveMutualRecursion
) {
6301 std::string Code
= R
"(
6302 bool Pong(bool X, bool Y);
6304 bool Ping(bool X, bool Y) {
6312 bool Pong(bool X, bool Y) {
6321 bool Foo = Ping(false, false);
6327 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6328 ASTContext
&ASTCtx
) {
6329 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6330 // The analysis doesn't crash...
6331 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6333 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6334 ASSERT_THAT(FooDecl
, NotNull());
6336 auto &FooVal
= getFormula(*FooDecl
, Env
);
6337 // ... but it also can't prove anything here.
6338 EXPECT_FALSE(Env
.proves(FooVal
));
6339 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(FooVal
)));
6341 {BuiltinOptions
{ContextSensitiveOptions
{/*.Depth=*/4}}});
6344 TEST(TransferTest
, ContextSensitiveSetMultipleLines
) {
6345 std::string Code
= R
"(
6346 void SetBools(bool &Var1, bool &Var2) {
6360 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6361 ASTContext
&ASTCtx
) {
6362 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6363 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6365 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6366 ASSERT_THAT(FooDecl
, NotNull());
6368 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
6369 ASSERT_THAT(BarDecl
, NotNull());
6371 auto &FooVal
= getFormula(*FooDecl
, Env
);
6372 EXPECT_TRUE(Env
.proves(FooVal
));
6373 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(FooVal
)));
6375 auto &BarVal
= getFormula(*BarDecl
, Env
);
6376 EXPECT_FALSE(Env
.proves(BarVal
));
6377 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(BarVal
)));
6379 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6382 TEST(TransferTest
, ContextSensitiveSetMultipleBlocks
) {
6383 std::string Code
= R
"(
6384 void IfCond(bool Cond, bool &Then, bool &Else) {
6396 IfCond(Foo, Bar, Baz);
6402 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6403 ASTContext
&ASTCtx
) {
6404 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6405 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6407 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
6408 ASSERT_THAT(BarDecl
, NotNull());
6410 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
6411 ASSERT_THAT(BazDecl
, NotNull());
6413 auto &BarVal
= getFormula(*BarDecl
, Env
);
6414 EXPECT_FALSE(Env
.proves(BarVal
));
6415 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(BarVal
)));
6417 auto &BazVal
= getFormula(*BazDecl
, Env
);
6418 EXPECT_TRUE(Env
.proves(BazVal
));
6419 EXPECT_FALSE(Env
.proves(Env
.arena().makeNot(BazVal
)));
6421 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6424 TEST(TransferTest
, ContextSensitiveReturnVoid
) {
6425 std::string Code
= R
"(
6426 void Noop() { return; }
6435 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6436 ASTContext
&ASTCtx
) {
6437 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6438 // This just tests that the analysis doesn't crash.
6440 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6443 TEST(TransferTest
, ContextSensitiveReturnTrue
) {
6444 std::string Code
= R
"(
6445 bool GiveBool() { return true; }
6448 bool Foo = GiveBool();
6454 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6455 ASTContext
&ASTCtx
) {
6456 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6457 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6459 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6460 ASSERT_THAT(FooDecl
, NotNull());
6462 auto &FooVal
= getFormula(*FooDecl
, Env
);
6463 EXPECT_TRUE(Env
.proves(FooVal
));
6465 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6468 TEST(TransferTest
, ContextSensitiveReturnFalse
) {
6469 std::string Code
= R
"(
6470 bool GiveBool() { return false; }
6473 bool Foo = GiveBool();
6479 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6480 ASTContext
&ASTCtx
) {
6481 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6482 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6484 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6485 ASSERT_THAT(FooDecl
, NotNull());
6487 auto &FooVal
= getFormula(*FooDecl
, Env
);
6488 EXPECT_TRUE(Env
.proves(Env
.arena().makeNot(FooVal
)));
6490 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6493 TEST(TransferTest
, ContextSensitiveReturnArg
) {
6494 std::string Code
= R
"(
6496 bool GiveBack(bool Arg) { return Arg; }
6499 bool Foo = GiveBool();
6500 bool Bar = GiveBack(Foo);
6501 bool Baz = Foo == Bar;
6507 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6508 ASTContext
&ASTCtx
) {
6509 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6510 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6512 const ValueDecl
*BazDecl
= findValueDecl(ASTCtx
, "Baz");
6513 ASSERT_THAT(BazDecl
, NotNull());
6515 auto &BazVal
= getFormula(*BazDecl
, Env
);
6516 EXPECT_TRUE(Env
.proves(BazVal
));
6518 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6521 TEST(TransferTest
, ContextSensitiveReturnInt
) {
6522 std::string Code
= R
"(
6523 int identity(int x) { return x; }
6526 int y = identity(42);
6532 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6533 ASTContext
&ASTCtx
) {
6534 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6535 // This just tests that the analysis doesn't crash.
6537 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6540 TEST(TransferTest
, ContextSensitiveReturnRecord
) {
6541 std::string Code
= R
"(
6546 S makeS(bool BVal) { return {BVal}; }
6549 S FalseS = makeS(false);
6550 S TrueS = makeS(true);
6556 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6557 ASTContext
&ASTCtx
) {
6558 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6561 getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "FalseS");
6563 getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "TrueS");
6565 EXPECT_EQ(getFieldValue(&FalseSLoc
, "B", ASTCtx
, Env
),
6566 &Env
.getBoolLiteralValue(false));
6567 EXPECT_EQ(getFieldValue(&TrueSLoc
, "B", ASTCtx
, Env
),
6568 &Env
.getBoolLiteralValue(true));
6570 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6573 TEST(TransferTest
, ContextSensitiveReturnSelfReferentialRecord
) {
6574 std::string Code
= R
"(
6576 S() { self = this; }
6581 // RVO guarantees that this will be constructed directly into `MyS`.
6592 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6593 ASTContext
&ASTCtx
) {
6594 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6596 auto &MySLoc
= getLocForDecl
<RecordStorageLocation
>(ASTCtx
, Env
, "MyS");
6599 cast
<PointerValue
>(getFieldValue(&MySLoc
, "self", ASTCtx
, Env
));
6600 EXPECT_EQ(&SelfVal
->getPointeeLoc(), &MySLoc
);
6602 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6605 TEST(TransferTest
, ContextSensitiveMethodLiteral
) {
6606 std::string Code
= R
"(
6609 bool giveBool() { return true; }
6614 bool Foo = MyObj.giveBool();
6620 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6621 ASTContext
&ASTCtx
) {
6622 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6623 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6625 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6626 ASSERT_THAT(FooDecl
, NotNull());
6628 auto &FooVal
= getFormula(*FooDecl
, Env
);
6629 EXPECT_TRUE(Env
.proves(FooVal
));
6631 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6634 TEST(TransferTest
, ContextSensitiveMethodGetter
) {
6635 std::string Code
= R
"(
6638 bool getField() { return Field; }
6646 bool Foo = MyObj.getField();
6652 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6653 ASTContext
&ASTCtx
) {
6654 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6655 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6657 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6658 ASSERT_THAT(FooDecl
, NotNull());
6660 auto &FooVal
= getFormula(*FooDecl
, Env
);
6661 EXPECT_TRUE(Env
.proves(FooVal
));
6663 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6666 TEST(TransferTest
, ContextSensitiveMethodSetter
) {
6667 std::string Code
= R
"(
6670 void setField(bool Val) { Field = Val; }
6677 MyObj.setField(true);
6678 bool Foo = MyObj.Field;
6684 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6685 ASTContext
&ASTCtx
) {
6686 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6687 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6689 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6690 ASSERT_THAT(FooDecl
, NotNull());
6692 auto &FooVal
= getFormula(*FooDecl
, Env
);
6693 EXPECT_TRUE(Env
.proves(FooVal
));
6695 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6698 TEST(TransferTest
, ContextSensitiveMethodGetterAndSetter
) {
6699 std::string Code
= R
"(
6702 bool getField() { return Field; }
6703 void setField(bool Val) { Field = Val; }
6711 MyObj.setField(true);
6712 bool Foo = MyObj.getField();
6718 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6719 ASTContext
&ASTCtx
) {
6720 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6721 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6723 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6724 ASSERT_THAT(FooDecl
, NotNull());
6726 auto &FooVal
= getFormula(*FooDecl
, Env
);
6727 EXPECT_TRUE(Env
.proves(FooVal
));
6729 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6733 TEST(TransferTest
, ContextSensitiveMethodTwoLayersVoid
) {
6734 std::string Code
= R
"(
6737 void Inner() { MyField = true; }
6738 void Outer() { Inner(); }
6746 bool Foo = MyObj.MyField;
6752 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6753 ASTContext
&ASTCtx
) {
6754 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6756 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6758 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6759 ASSERT_THAT(FooDecl
, NotNull());
6761 auto &FooVal
= getFormula(*FooDecl
, Env
);
6762 EXPECT_TRUE(Env
.proves(FooVal
));
6764 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6767 TEST(TransferTest
, ContextSensitiveMethodTwoLayersReturn
) {
6768 std::string Code
= R
"(
6771 bool Inner() { return MyField; }
6772 bool Outer() { return Inner(); }
6779 MyObj.MyField = true;
6780 bool Foo = MyObj.Outer();
6786 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6787 ASTContext
&ASTCtx
) {
6788 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6790 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6792 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6793 ASSERT_THAT(FooDecl
, NotNull());
6795 auto &FooVal
= getFormula(*FooDecl
, Env
);
6796 EXPECT_TRUE(Env
.proves(FooVal
));
6798 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6801 TEST(TransferTest
, ContextSensitiveConstructorBody
) {
6802 std::string Code
= R
"(
6805 MyClass() { MyField = true; }
6812 bool Foo = MyObj.MyField;
6818 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6819 ASTContext
&ASTCtx
) {
6820 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6821 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6823 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6824 ASSERT_THAT(FooDecl
, NotNull());
6826 auto &FooVal
= getFormula(*FooDecl
, Env
);
6827 EXPECT_TRUE(Env
.proves(FooVal
));
6829 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6832 TEST(TransferTest
, ContextSensitiveConstructorInitializer
) {
6833 std::string Code
= R
"(
6836 MyClass() : MyField(true) {}
6843 bool Foo = MyObj.MyField;
6849 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6850 ASTContext
&ASTCtx
) {
6851 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6852 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6854 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6855 ASSERT_THAT(FooDecl
, NotNull());
6857 auto &FooVal
= getFormula(*FooDecl
, Env
);
6858 EXPECT_TRUE(Env
.proves(FooVal
));
6860 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6863 TEST(TransferTest
, ContextSensitiveConstructorDefault
) {
6864 std::string Code
= R
"(
6867 MyClass() = default;
6869 bool MyField = true;
6874 bool Foo = MyObj.MyField;
6880 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6881 ASTContext
&ASTCtx
) {
6882 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6883 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6885 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
6886 ASSERT_THAT(FooDecl
, NotNull());
6888 auto &FooVal
= getFormula(*FooDecl
, Env
);
6889 EXPECT_TRUE(Env
.proves(FooVal
));
6891 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6894 TEST(TransferTest
, ContextSensitiveSelfReferentialClass
) {
6895 // Test that the `this` pointer seen in the constructor has the same value
6896 // as the address of the variable the object is constructed into.
6897 std::string Code
= R
"(
6900 MyClass() : Self(this) {}
6906 MyClass *SelfPtr = MyObj.Self;
6912 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6913 ASTContext
&ASTCtx
) {
6914 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
6916 const ValueDecl
*MyObjDecl
= findValueDecl(ASTCtx
, "MyObj");
6917 ASSERT_THAT(MyObjDecl
, NotNull());
6919 const ValueDecl
*SelfDecl
= findValueDecl(ASTCtx
, "SelfPtr");
6920 ASSERT_THAT(SelfDecl
, NotNull());
6922 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6923 auto &SelfVal
= *cast
<PointerValue
>(Env
.getValue(*SelfDecl
));
6924 EXPECT_EQ(Env
.getStorageLocation(*MyObjDecl
), &SelfVal
.getPointeeLoc());
6926 {BuiltinOptions
{ContextSensitiveOptions
{}}});
6929 TEST(TransferTest
, UnnamedBitfieldInitializer
) {
6930 std::string Code
= R
"(
6946 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6947 ASTContext
&ASTCtx
) {
6948 // This doesn't need a body because this test was crashing the framework
6949 // before handling correctly Unnamed bitfields in `InitListExpr`.
6953 // Repro for a crash that used to occur with chained short-circuiting logical
6955 TEST(TransferTest
, ChainedLogicalOps
) {
6956 std::string Code
= R
"(
6958 bool b = true || false || false || false;
6965 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
6966 ASTContext
&ASTCtx
) {
6967 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
6968 auto &B
= getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "b").formula();
6969 EXPECT_TRUE(Env
.proves(B
));
6973 // Repro for a crash that used to occur when we call a `noreturn` function
6974 // within one of the operands of a `&&` or `||` operator.
6975 TEST(TransferTest
, NoReturnFunctionInsideShortCircuitedBooleanOp
) {
6976 std::string Code
= R
"(
6977 __attribute__((noreturn)) int doesnt_return();
6978 bool some_condition();
6979 void target(bool b1, bool b2) {
6980 // Neither of these should crash. In addition, if we don't terminate the
6981 // program, we know that the operators need to trigger the short-circuit
6982 // logic, so `NoreturnOnRhsOfAnd` will be false and `NoreturnOnRhsOfOr`
6984 bool NoreturnOnRhsOfAnd = b1 && doesnt_return() > 0;
6985 bool NoreturnOnRhsOfOr = b2 || doesnt_return() > 0;
6987 // Calling a `noreturn` function on the LHS of an `&&` or `||` makes the
6988 // entire expression unreachable. So we know that in both of the following
6989 // cases, if `target()` terminates, the `else` branch was taken.
6990 bool NoreturnOnLhsMakesAndUnreachable = false;
6991 if (some_condition())
6992 doesnt_return() > 0 && some_condition();
6994 NoreturnOnLhsMakesAndUnreachable = true;
6996 bool NoreturnOnLhsMakesOrUnreachable = false;
6997 if (some_condition())
6998 doesnt_return() > 0 || some_condition();
7000 NoreturnOnLhsMakesOrUnreachable = true;
7007 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
7008 ASTContext
&ASTCtx
) {
7009 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
7010 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
7011 auto &A
= Env
.arena();
7013 // Check that [[p]] is reachable with a non-false flow condition.
7014 EXPECT_FALSE(Env
.proves(A
.makeLiteral(false)));
7016 auto &B1
= getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "b1").formula();
7017 EXPECT_TRUE(Env
.proves(A
.makeNot(B1
)));
7019 auto &NoreturnOnRhsOfAnd
=
7020 getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "NoreturnOnRhsOfAnd").formula();
7021 EXPECT_TRUE(Env
.proves(A
.makeNot(NoreturnOnRhsOfAnd
)));
7023 auto &B2
= getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "b2").formula();
7024 EXPECT_TRUE(Env
.proves(B2
));
7026 auto &NoreturnOnRhsOfOr
=
7027 getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "NoreturnOnRhsOfOr")
7029 EXPECT_TRUE(Env
.proves(NoreturnOnRhsOfOr
));
7031 auto &NoreturnOnLhsMakesAndUnreachable
= getValueForDecl
<BoolValue
>(
7032 ASTCtx
, Env
, "NoreturnOnLhsMakesAndUnreachable").formula();
7033 EXPECT_TRUE(Env
.proves(NoreturnOnLhsMakesAndUnreachable
));
7035 auto &NoreturnOnLhsMakesOrUnreachable
= getValueForDecl
<BoolValue
>(
7036 ASTCtx
, Env
, "NoreturnOnLhsMakesOrUnreachable").formula();
7037 EXPECT_TRUE(Env
.proves(NoreturnOnLhsMakesOrUnreachable
));
7041 TEST(TransferTest
, NewExpressions
) {
7042 std::string Code
= R
"(
7044 int *p = new int(42);
7050 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
7051 ASTContext
&ASTCtx
) {
7052 const Environment
&Env
=
7053 getEnvironmentAtAnnotation(Results
, "after_new");
7055 auto &P
= getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "p");
7057 EXPECT_THAT(Env
.getValue(P
.getPointeeLoc()), NotNull());
7061 TEST(TransferTest
, NewExpressions_Structs
) {
7062 std::string Code
= R
"(
7072 Outer *p = new Outer;
7073 // Access the fields to make sure the analysis actually generates children
7074 // for them in the `RecordStorageLocation`.
7075 p->OuterField.InnerField;
7081 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
7082 ASTContext
&ASTCtx
) {
7083 const Environment
&Env
=
7084 getEnvironmentAtAnnotation(Results
, "after_new");
7086 const ValueDecl
*OuterField
= findValueDecl(ASTCtx
, "OuterField");
7087 const ValueDecl
*InnerField
= findValueDecl(ASTCtx
, "InnerField");
7089 auto &P
= getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "p");
7091 auto &OuterLoc
= cast
<RecordStorageLocation
>(P
.getPointeeLoc());
7092 auto &OuterFieldLoc
=
7093 *cast
<RecordStorageLocation
>(OuterLoc
.getChild(*OuterField
));
7094 auto &InnerFieldLoc
= *OuterFieldLoc
.getChild(*InnerField
);
7096 EXPECT_THAT(Env
.getValue(InnerFieldLoc
), NotNull());
7100 TEST(TransferTest
, FunctionToPointerDecayHasValue
) {
7101 std::string Code
= R
"(
7102 struct A { static void static_member_func(); };
7104 // To check that we're treating function-to-pointer decay correctly,
7105 // create two pointers, then verify they refer to the same storage
7107 // We need to do the test this way because even if an initializer (in this
7108 // case, the function-to-pointer decay) does not create a value, we still
7109 // create a value for the variable.
7110 void (*non_member_p1)() = target;
7111 void (*non_member_p2)() = target;
7113 // Do the same thing but for a static member function.
7114 void (*member_p1)() = A::static_member_func;
7115 void (*member_p2)() = A::static_member_func;
7121 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
7122 ASTContext
&ASTCtx
) {
7123 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
7126 getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "non_member_p1");
7128 getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "non_member_p2");
7129 EXPECT_EQ(&NonMemberP1
.getPointeeLoc(), &NonMemberP2
.getPointeeLoc());
7132 getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "member_p1");
7134 getValueForDecl
<PointerValue
>(ASTCtx
, Env
, "member_p2");
7135 EXPECT_EQ(&MemberP1
.getPointeeLoc(), &MemberP2
.getPointeeLoc());
7139 // Check that a builtin function is not associated with a value. (It's only
7140 // possible to call builtin functions directly, not take their address.)
7141 TEST(TransferTest
, BuiltinFunctionModeled
) {
7142 std::string Code
= R
"(
7144 __builtin_expect(0, 0);
7150 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
7151 ASTContext
&ASTCtx
) {
7152 using ast_matchers::selectFirst
;
7153 using ast_matchers::match
;
7154 using ast_matchers::traverse
;
7155 using ast_matchers::implicitCastExpr
;
7156 using ast_matchers::hasCastKind
;
7158 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
7160 auto *ImplicitCast
= selectFirst
<ImplicitCastExpr
>(
7162 match(traverse(TK_AsIs
,
7163 implicitCastExpr(hasCastKind(CK_BuiltinFnToFnPtr
))
7164 .bind("implicit_cast")),
7167 ASSERT_THAT(ImplicitCast
, NotNull());
7168 EXPECT_THAT(Env
.getValue(*ImplicitCast
), IsNull());
7172 // Check that a callee of a member operator call is modeled as a `PointerValue`.
7173 // Member operator calls are unusual in that their callee is a pointer that
7174 // stems from a `FunctionToPointerDecay`. In calls to non-operator non-static
7175 // member functions, the callee is a `MemberExpr` (which does not have pointer
7177 // We want to make sure that we produce a pointer value for the callee in this
7178 // specific scenario and that its storage location is durable (for convergence).
7179 TEST(TransferTest
, MemberOperatorCallModelsPointerForCallee
) {
7180 std::string Code
= R
"(
7182 bool operator!=(S s);
7193 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
7194 ASTContext
&ASTCtx
) {
7195 using ast_matchers::selectFirst
;
7196 using ast_matchers::match
;
7197 using ast_matchers::traverse
;
7198 using ast_matchers::cxxOperatorCallExpr
;
7200 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
7202 auto Matches
= match(
7203 traverse(TK_AsIs
, cxxOperatorCallExpr().bind("call")), ASTCtx
);
7205 ASSERT_EQ(Matches
.size(), 2UL);
7207 auto *Call1
= Matches
[0].getNodeAs
<CXXOperatorCallExpr
>("call");
7208 auto *Call2
= Matches
[1].getNodeAs
<CXXOperatorCallExpr
>("call");
7210 ASSERT_THAT(Call1
, NotNull());
7211 ASSERT_THAT(Call2
, NotNull());
7213 EXPECT_EQ(cast
<ImplicitCastExpr
>(Call1
->getCallee())->getCastKind(),
7214 CK_FunctionToPointerDecay
);
7215 EXPECT_EQ(cast
<ImplicitCastExpr
>(Call2
->getCallee())->getCastKind(),
7216 CK_FunctionToPointerDecay
);
7218 auto *Ptr1
= cast
<PointerValue
>(Env
.getValue(*Call1
->getCallee()));
7219 auto *Ptr2
= cast
<PointerValue
>(Env
.getValue(*Call2
->getCallee()));
7221 ASSERT_EQ(&Ptr1
->getPointeeLoc(), &Ptr2
->getPointeeLoc());
7225 // Check that fields of anonymous records are modeled.
7226 TEST(TransferTest
, AnonymousStruct
) {
7227 std::string Code
= R
"(
7241 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
7242 ASTContext
&ASTCtx
) {
7243 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
7244 const ValueDecl
*SDecl
= findValueDecl(ASTCtx
, "s");
7245 const ValueDecl
*BDecl
= findValueDecl(ASTCtx
, "b");
7246 const IndirectFieldDecl
*IndirectField
=
7247 findIndirectFieldDecl(ASTCtx
, "b");
7249 auto *S
= cast
<RecordStorageLocation
>(Env
.getStorageLocation(*SDecl
));
7250 auto &AnonStruct
= *cast
<RecordStorageLocation
>(
7251 S
->getChild(*cast
<ValueDecl
>(IndirectField
->chain().front())));
7253 auto *B
= cast
<BoolValue
>(getFieldValue(&AnonStruct
, *BDecl
, Env
));
7254 ASSERT_TRUE(Env
.proves(B
->formula()));
7258 TEST(TransferTest
, AnonymousStructWithInitializer
) {
7259 std::string Code
= R
"(
7272 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
7273 ASTContext
&ASTCtx
) {
7274 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
7275 const ValueDecl
*BDecl
= findValueDecl(ASTCtx
, "b");
7276 const IndirectFieldDecl
*IndirectField
=
7277 findIndirectFieldDecl(ASTCtx
, "b");
7280 cast
<RecordStorageLocation
>(Env
.getThisPointeeStorageLocation());
7281 auto &AnonStruct
= *cast
<RecordStorageLocation
>(ThisLoc
->getChild(
7282 *cast
<ValueDecl
>(IndirectField
->chain().front())));
7284 auto *B
= cast
<BoolValue
>(getFieldValue(&AnonStruct
, *BDecl
, Env
));
7285 ASSERT_TRUE(Env
.proves(B
->formula()));
7289 TEST(TransferTest
, AnonymousStructWithReferenceField
) {
7290 std::string Code
= R
"(
7304 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
7305 ASTContext
&ASTCtx
) {
7306 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
7307 const ValueDecl
*GlobalIDecl
= findValueDecl(ASTCtx
, "global_i");
7308 const ValueDecl
*IDecl
= findValueDecl(ASTCtx
, "i");
7309 const IndirectFieldDecl
*IndirectField
=
7310 findIndirectFieldDecl(ASTCtx
, "i");
7313 cast
<RecordStorageLocation
>(Env
.getThisPointeeStorageLocation());
7314 auto &AnonStruct
= *cast
<RecordStorageLocation
>(ThisLoc
->getChild(
7315 *cast
<ValueDecl
>(IndirectField
->chain().front())));
7317 ASSERT_EQ(AnonStruct
.getChild(*IDecl
),
7318 Env
.getStorageLocation(*GlobalIDecl
));
7322 TEST(TransferTest
, EvaluateBlockWithUnreachablePreds
) {
7323 // This is a crash repro.
7324 // `false` block may not have been processed when we try to evaluate the `||`
7325 // after visiting `true`, because it is not necessary (and therefore the edge
7326 // is marked unreachable). Trying to get the analysis state via
7327 // `getEnvironment` for the subexpression still should not crash.
7328 std::string Code
= R
"(
7330 if ((i < 0 && true) || false) {
7338 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
7339 ASTContext
&ASTCtx
) {});
7342 TEST(TransferTest
, LambdaCaptureByCopy
) {
7343 std::string Code
= R
"(
7344 void target(int Foo, int Bar) {
7351 runDataflowOnLambda(
7353 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
7354 ASTContext
&ASTCtx
) {
7355 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
7356 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
7358 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
7359 ASSERT_THAT(FooDecl
, NotNull());
7361 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
7362 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
7364 const Value
*FooVal
= Env
.getValue(*FooLoc
);
7365 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
7367 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
7368 ASSERT_THAT(BarDecl
, NotNull());
7370 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
7371 EXPECT_THAT(BarLoc
, IsNull());
7375 TEST(TransferTest
, LambdaCaptureByReference
) {
7376 std::string Code
= R
"(
7377 void target(int Foo, int Bar) {
7384 runDataflowOnLambda(
7386 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
7387 ASTContext
&ASTCtx
) {
7388 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
7389 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
7391 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
7392 ASSERT_THAT(FooDecl
, NotNull());
7394 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
7395 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
7397 const Value
*FooVal
= Env
.getValue(*FooLoc
);
7398 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
7400 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
7401 ASSERT_THAT(BarDecl
, NotNull());
7403 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
7404 EXPECT_THAT(BarLoc
, IsNull());
7408 TEST(TransferTest
, LambdaCaptureWithInitializer
) {
7409 std::string Code
= R
"(
7410 void target(int Bar) {
7417 runDataflowOnLambda(
7419 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
7420 ASTContext
&ASTCtx
) {
7421 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
7422 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
7424 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
7425 ASSERT_THAT(FooDecl
, NotNull());
7427 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
7428 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
7430 const Value
*FooVal
= Env
.getValue(*FooLoc
);
7431 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
7433 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
7434 ASSERT_THAT(BarDecl
, NotNull());
7436 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
7437 EXPECT_THAT(BarLoc
, IsNull());
7441 TEST(TransferTest
, LambdaCaptureByCopyImplicit
) {
7442 std::string Code
= R
"(
7443 void target(int Foo, int Bar) {
7450 runDataflowOnLambda(
7452 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
7453 ASTContext
&ASTCtx
) {
7454 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
7455 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
7457 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
7458 ASSERT_THAT(FooDecl
, NotNull());
7460 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
7461 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
7463 const Value
*FooVal
= Env
.getValue(*FooLoc
);
7464 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
7466 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
7467 ASSERT_THAT(BarDecl
, NotNull());
7469 // There is no storage location for `Bar` because it isn't used in the
7470 // body of the lambda.
7471 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
7472 EXPECT_THAT(BarLoc
, IsNull());
7476 TEST(TransferTest
, LambdaCaptureByReferenceImplicit
) {
7477 std::string Code
= R
"(
7478 void target(int Foo, int Bar) {
7485 runDataflowOnLambda(
7487 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
7488 ASTContext
&ASTCtx
) {
7489 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
7490 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
7492 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
7493 ASSERT_THAT(FooDecl
, NotNull());
7495 const StorageLocation
*FooLoc
= Env
.getStorageLocation(*FooDecl
);
7496 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
7498 const Value
*FooVal
= Env
.getValue(*FooLoc
);
7499 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
7501 const ValueDecl
*BarDecl
= findValueDecl(ASTCtx
, "Bar");
7502 ASSERT_THAT(BarDecl
, NotNull());
7504 // There is no storage location for `Bar` because it isn't used in the
7505 // body of the lambda.
7506 const StorageLocation
*BarLoc
= Env
.getStorageLocation(*BarDecl
);
7507 EXPECT_THAT(BarLoc
, IsNull());
7511 TEST(TransferTest
, LambdaCaptureThis
) {
7512 std::string Code
= R
"(
7524 runDataflowOnLambda(
7526 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
7527 ASTContext
&ASTCtx
) {
7528 ASSERT_THAT(Results
.keys(), UnorderedElementsAre("p"));
7529 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
7531 const RecordStorageLocation
*ThisPointeeLoc
=
7532 Env
.getThisPointeeStorageLocation();
7533 ASSERT_THAT(ThisPointeeLoc
, NotNull());
7535 const ValueDecl
*FooDecl
= findValueDecl(ASTCtx
, "Foo");
7536 ASSERT_THAT(FooDecl
, NotNull());
7538 const StorageLocation
*FooLoc
= ThisPointeeLoc
->getChild(*FooDecl
);
7539 ASSERT_TRUE(isa_and_nonnull
<ScalarStorageLocation
>(FooLoc
));
7541 const Value
*FooVal
= Env
.getValue(*FooLoc
);
7542 EXPECT_TRUE(isa_and_nonnull
<IntegerValue
>(FooVal
));
7546 // This test verifies correct modeling of a relational dependency that goes
7547 // through unmodeled functions (the simple `cond()` in this case).
7548 TEST(TransferTest
, ConditionalRelation
) {
7549 std::string Code
= R
"(
7566 [](const llvm::StringMap
<DataflowAnalysisState
<NoopLattice
>> &Results
,
7567 ASTContext
&ASTCtx
) {
7568 const Environment
&Env
= getEnvironmentAtAnnotation(Results
, "p");
7569 auto &A
= Env
.arena();
7570 auto &VarA
= getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "a").formula();
7571 auto &VarB
= getValueForDecl
<BoolValue
>(ASTCtx
, Env
, "b").formula();
7573 EXPECT_FALSE(Env
.allows(A
.makeAnd(VarA
, A
.makeNot(VarB
))));
7577 // This is a crash repro.
7578 // We used to crash while transferring `S().i` because Clang contained a bug
7579 // causing the AST to be malformed.
7580 TEST(TransferTest
, AnonymousUnionMemberExprInTemplate
) {
7581 using ast_matchers::functionDecl
;
7582 using ast_matchers::hasName
;
7583 using ast_matchers::unless
;
7585 std::string Code
= R
"cc(
7597 template void target<int>();
7599 auto Matcher
= functionDecl(hasName("target"), unless(isTemplated()));
7600 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code
, Matcher
),