[RISCV] Fix the cost of `llvm.vector.reduce.and` (#119160)
[llvm-project.git] / clang / unittests / Analysis / FlowSensitive / TransferTest.cpp
blob0f731f4532535ea6206656dbc842a1b0df2d7fd6
1 //===- unittests/Analysis/FlowSensitive/TransferTest.cpp ------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "TestingSupport.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/Decl.h"
12 #include "clang/ASTMatchers/ASTMatchers.h"
13 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
14 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
15 #include "clang/Analysis/FlowSensitive/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"
26 #include <optional>
27 #include <string>
28 #include <string_view>
29 #include <utility>
31 namespace clang {
32 namespace dataflow {
33 namespace {
34 AST_MATCHER(FunctionDecl, isTemplated) { return Node.isTemplated(); }
35 } // namespace
36 } // namespace dataflow
37 } // namespace clang
39 namespace {
41 using namespace clang;
42 using namespace dataflow;
43 using namespace test;
44 using ::testing::Eq;
45 using ::testing::IsNull;
46 using ::testing::Ne;
47 using ::testing::NotNull;
48 using ::testing::UnorderedElementsAre;
50 // Declares a minimal coroutine library.
51 constexpr llvm::StringRef CoroutineLibrary = R"cc(
52 struct promise;
53 struct task;
55 namespace std {
56 template <class, class...>
57 struct coroutine_traits {};
58 template <>
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 {}; }
67 } // namespace std
69 struct awaitable {
70 bool await_ready() const noexcept;
71 void await_suspend(std::coroutine_handle<promise>) const noexcept;
72 void await_resume() const noexcept;
74 struct task {};
75 struct promise {
76 task get_return_object();
77 awaitable initial_suspend();
78 awaitable final_suspend() noexcept;
79 void unhandled_exception();
80 void return_void();
82 )cc";
84 void runDataflow(
85 llvm::StringRef Code,
86 std::function<
87 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
88 ASTContext &)>
89 VerifyResults,
90 DataflowAnalysisOptions Options,
91 LangStandard::Kind Std = LangStandard::lang_cxx17,
92 llvm::StringRef TargetFun = "target") {
93 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code, VerifyResults, Options,
94 Std, TargetFun),
95 llvm::Succeeded());
98 void runDataflow(
99 llvm::StringRef Code,
100 std::function<
101 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
102 ASTContext &)>
103 VerifyResults,
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>()},
109 Std, TargetFun);
112 void runDataflowOnLambda(
113 llvm::StringRef Code,
114 std::function<
115 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
116 ASTContext &)>
117 VerifyResults,
118 DataflowAnalysisOptions Options,
119 LangStandard::Kind Std = LangStandard::lang_cxx17) {
120 ASSERT_THAT_ERROR(
121 checkDataflowWithNoopAnalysis(
122 Code,
123 ast_matchers::hasDeclContext(
124 ast_matchers::cxxRecordDecl(ast_matchers::isLambda())),
125 VerifyResults, Options, Std),
126 llvm::Succeeded());
129 void runDataflowOnLambda(
130 llvm::StringRef Code,
131 std::function<
132 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
133 ASTContext &)>
134 VerifyResults,
135 LangStandard::Kind Std = LangStandard::lang_cxx17,
136 bool ApplyBuiltinTransfer = true) {
137 runDataflowOnLambda(Code, std::move(VerifyResults),
138 {ApplyBuiltinTransfer ? BuiltinOptions{}
139 : std::optional<BuiltinOptions>()},
140 Std);
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;
150 auto TargetNodes =
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);
160 const auto *Target =
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);
170 const auto *Target =
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);
180 const auto *Target =
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"(
188 void target() {
189 int Foo;
190 // [[p]]
193 runDataflow(
194 Code,
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"(
211 void target() {
212 bool Foo;
213 // [[p]]
216 runDataflow(
217 Code,
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"(
236 void target() {
237 int Foo;
238 // [[p]]
241 runDataflow(
242 Code,
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"(
261 struct A;
263 void target() {
264 A* Foo;
265 // [[p]]
268 runDataflow(
269 Code,
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"(
290 struct S { int X; };
291 S GlobalS;
292 struct A { S &Unmodeled = GlobalS; };
293 struct B { A F3; };
294 struct C { B F2; };
295 struct D { C F1; };
297 void target() {
298 D Bar;
299 A &Foo = Bar.F1.F2.F3;
300 int Zab = Foo.Unmodeled.X;
301 // [[p]]
304 runDataflow(
305 Code,
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;
321 } else {
322 FAIL() << "Unexpected field: " << Field->getNameAsString();
325 ASSERT_THAT(UnmodeledDecl, NotNull());
327 const auto *FooLoc =
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"(
342 struct A {
343 int Bar;
346 void target() {
347 A Foo;
348 (void)Foo.Bar;
349 // [[p]]
352 runDataflow(
353 Code,
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") {
368 BarDecl = Field;
369 } else {
370 FAIL() << "Unexpected field: " << Field->getNameAsString();
373 ASSERT_THAT(BarDecl, NotNull());
375 const auto *FooLoc =
376 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
377 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
381 TEST(TransferTest, StructVarDeclWithInit) {
382 std::string Code = R"(
383 struct A {
384 int Bar;
387 A Gen();
389 void target() {
390 A Foo = Gen();
391 (void)Foo.Bar;
392 // [[p]]
395 runDataflow(
396 Code,
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") {
411 BarDecl = Field;
412 } else {
413 FAIL() << "Unexpected field: " << Field->getNameAsString();
416 ASSERT_THAT(BarDecl, NotNull());
418 const auto *FooLoc =
419 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
420 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
424 TEST(TransferTest, StructArrayVarDecl) {
425 std::string Code = R"(
426 struct A {};
428 void target() {
429 A Array[2];
430 // [[p]]
433 runDataflow(
434 Code,
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"(
448 class A {
449 public:
450 int Bar;
453 void target() {
454 A Foo;
455 (void)Foo.Bar;
456 // [[p]]
459 runDataflow(
460 Code,
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") {
475 BarDecl = Field;
476 } else {
477 FAIL() << "Unexpected field: " << Field->getNameAsString();
480 ASSERT_THAT(BarDecl, NotNull());
482 const auto *FooLoc =
483 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
484 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));
488 TEST(TransferTest, ReferenceVarDecl) {
489 std::string Code = R"(
490 struct A {};
492 A &getA();
494 void target() {
495 A &Foo = getA();
496 // [[p]]
499 runDataflow(
500 Code,
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"(
516 struct A;
518 struct B {};
520 struct C {
521 A &FooRef;
522 A *FooPtr;
523 B &BazRef;
524 B *BazPtr;
527 struct A {
528 C &Bar;
531 A &getA();
533 void target() {
534 A &Foo = getA();
535 (void)Foo.Bar.FooRef;
536 (void)Foo.Bar.FooPtr;
537 (void)Foo.Bar.BazRef;
538 (void)Foo.Bar.BazPtr;
539 // [[p]]
542 runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>>
543 &Results,
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") {
559 BarDecl = Field;
560 } else {
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") {
577 FooRefDecl = Field;
578 } else if (Field->getNameAsString() == "FooPtr") {
579 FooPtrDecl = Field;
580 } else if (Field->getNameAsString() == "BazRef") {
581 BazRefDecl = Field;
582 } else if (Field->getNameAsString() == "BazPtr") {
583 BazPtrDecl = Field;
584 } else {
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());
593 const auto &FooLoc =
594 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));
596 const auto &BarLoc =
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)),
604 nullptr);
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)),
613 nullptr);
615 EXPECT_TRUE(isa<PointerValue>(getFieldValue(&BarLoc, *BazPtrDecl, Env)));
619 TEST(TransferTest, PointerVarDecl) {
620 std::string Code = R"(
621 struct A {};
623 A *getA();
625 void target() {
626 A *Foo = getA();
627 // [[p]]
630 runDataflow(
631 Code,
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"(
651 struct A;
653 struct B {};
655 struct C {
656 A &FooRef;
657 A *FooPtr;
658 B &BazRef;
659 B *BazPtr;
662 struct A {
663 C *Bar;
666 A *getA();
668 void target() {
669 A *Foo = getA();
670 (void)Foo->Bar->FooRef;
671 (void)Foo->Bar->FooPtr;
672 (void)Foo->Bar->BazRef;
673 (void)Foo->Bar->BazPtr;
674 // [[p]]
677 runDataflow(
678 Code,
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>()
690 ->getPointeeType()
691 ->isStructureType());
692 const auto FooFields = FooDecl->getType()
693 ->getAs<PointerType>()
694 ->getPointeeType()
695 ->getAsRecordDecl()
696 ->fields();
698 FieldDecl *BarDecl = nullptr;
699 for (FieldDecl *Field : FooFields) {
700 if (Field->getNameAsString() == "Bar") {
701 BarDecl = Field;
702 } else {
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>()
711 ->getPointeeType()
712 ->isStructureType());
713 const auto BarFields = BarDecl->getType()
714 ->getAs<PointerType>()
715 ->getPointeeType()
716 ->getAsRecordDecl()
717 ->fields();
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") {
725 FooRefDecl = Field;
726 } else if (Field->getNameAsString() == "FooPtr") {
727 FooPtrDecl = Field;
728 } else if (Field->getNameAsString() == "BazRef") {
729 BazRefDecl = Field;
730 } else if (Field->getNameAsString() == "BazPtr") {
731 BazPtrDecl = Field;
732 } else {
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());
741 const auto &FooLoc =
742 *cast<ScalarStorageLocation>(Env.getStorageLocation(*FooDecl));
743 const auto &FooVal = *cast<PointerValue>(Env.getValue(FooLoc));
744 const auto &FooPointeeLoc =
745 cast<RecordStorageLocation>(FooVal.getPointeeLoc());
747 const auto &BarVal =
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);
758 EXPECT_TRUE(
759 isa<PointerValue>(getFieldValue(&BarPointeeLoc, *BazPtrDecl, Env)));
763 TEST(TransferTest, DirectlySelfReferentialReference) {
764 std::string Code = R"(
765 struct target {
766 target() {
767 (void)0;
768 // [[p]]
770 target &self = *this;
773 runDataflow(
774 Code,
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"(
787 void target() {
788 int Foo, Bar;
789 (void)0;
790 // [[p]]
793 runDataflow(
794 Code,
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) {
823 int Foo;
824 // [[p1]]
825 if (B) {
826 int Bar;
827 // [[p2]]
828 } else {
829 int Baz;
830 // [[p3]]
832 (void)0;
833 // [[p4]]
836 runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>>
837 &Results,
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"(
876 void target() {
877 int Foo;
878 int Bar;
879 (Bar) = (Foo);
880 // [[p]]
883 runDataflow(
884 Code,
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"(
905 void target() {
906 int Foo = 1;
907 // [[before]]
908 Foo = 2;
909 // [[after]]
912 runDataflow(
913 Code,
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"(
930 void target() {
931 int Foo;
932 int Bar = Foo;
933 // [[p]]
936 runDataflow(
937 Code,
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"(
958 void target() {
959 int Foo;
960 int Bar;
961 int Baz = (Bar = Foo);
962 // [[p]]
965 runDataflow(
966 Code,
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"(
991 void target() {
992 int Foo;
993 int *Bar;
994 *(Bar) = Foo;
995 int Baz = *(Bar);
996 // [[p]]
999 runDataflow(
1000 Code,
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"(
1027 void target() {
1028 int Foo;
1029 int Bar;
1030 int &Baz = Foo;
1031 // [[p1]]
1032 Baz = Bar;
1033 int Qux = Baz;
1034 int &Quux = Baz;
1035 // [[p2]]
1038 runDataflow(
1039 Code,
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) {
1079 (void)0;
1080 // [[p]]
1083 runDataflow(
1084 Code,
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"(
1112 struct A {
1113 int Bar;
1116 void target(A Foo) {
1117 (void)Foo.Bar;
1118 // [[p]]
1121 runDataflow(
1122 Code,
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") {
1137 BarDecl = Field;
1138 } else {
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"(
1152 struct A {};
1154 void target(A &Foo) {
1155 (void)0;
1156 // [[p]]
1159 runDataflow(
1160 Code,
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"(
1176 struct A {};
1178 void target(A *Foo) {
1179 (void)0;
1180 // [[p]]
1183 runDataflow(
1184 Code,
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"(
1204 struct A {
1205 int Bar;
1208 void target(A Foo) {
1209 int Baz = Foo.Bar;
1210 // [[p]]
1213 runDataflow(
1214 Code,
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") {
1229 BarDecl = Field;
1230 } else {
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"(
1250 struct A {
1251 int Bar;
1252 enum E { ONE, TWO };
1255 void target(A Foo) {
1256 A::E Baz = Foo.ONE;
1257 // [[p]]
1260 // Minimal expectations -- we're just testing that it doesn't crash, since
1261 // enums aren't interpreted.
1262 runDataflow(
1263 Code,
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"(
1272 class A {
1273 int ADefault;
1274 protected:
1275 int AProtected;
1276 private:
1277 int APrivate;
1278 public:
1279 int APublic;
1281 private:
1282 friend void target();
1285 class B : public A {
1286 int BDefault;
1287 protected:
1288 int BProtected;
1289 private:
1290 int BPrivate;
1292 private:
1293 friend void target();
1296 void target() {
1297 B Foo;
1298 (void)Foo.ADefault;
1299 (void)Foo.AProtected;
1300 (void)Foo.APrivate;
1301 (void)Foo.APublic;
1302 (void)Foo.BDefault;
1303 (void)Foo.BProtected;
1304 (void)Foo.BPrivate;
1305 // [[p]]
1308 runDataflow(
1309 Code,
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;
1331 } else {
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;
1357 } else {
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());
1367 ASSERT_TRUE(
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") {
1390 BarDecl = Field;
1391 } else {
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"(
1405 struct A {
1406 int Bar;
1408 struct B : public A {
1411 void target() {
1412 B Foo;
1413 (void)Foo.Bar;
1414 // [[p]]
1417 runDataflow(Code, derivedBaseMemberExpectations);
1420 TEST(TransferTest, DerivedBaseMemberPrivateFriend) {
1421 // Include an access to `Foo.Bar` to verify the analysis doesn't crash on that
1422 // access.
1423 std::string Code = R"(
1424 struct A {
1425 private:
1426 friend void target();
1427 int Bar;
1429 struct B : public A {
1432 void target() {
1433 B Foo;
1434 (void)Foo.Bar;
1435 // [[p]]
1438 runDataflow(Code, derivedBaseMemberExpectations);
1441 TEST(TransferTest, ClassMember) {
1442 std::string Code = R"(
1443 class A {
1444 public:
1445 int Bar;
1448 void target(A Foo) {
1449 int Baz = Foo.Bar;
1450 // [[p]]
1453 runDataflow(
1454 Code,
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") {
1469 BarDecl = Field;
1470 } else {
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"(
1494 class A {
1495 public:
1496 A(int I) : Bar(I) {}
1497 int Bar;
1500 class B : public A {
1501 public:
1502 B(int I) : A(I) {
1503 (void)0;
1504 // [[p]]
1508 ASSERT_THAT_ERROR(
1509 checkDataflow<NoopAnalysis>(
1510 AnalysisInputs<NoopAnalysis>(
1511 Code, cxxConstructorDecl(ofClass(hasName("B"))),
1512 [](ASTContext &C, Environment &) { return NoopAnalysis(C); })
1513 .withASTBuildArgs(
1514 {"-fsyntax-only", "-fno-delayed-template-parsing",
1515 "-std=" + std::string(LangStandard::getLangStandardForKind(
1516 LangStandard::lang_cxx17)
1517 .getName())}),
1518 /*VerifyResults=*/
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
1524 // properties.
1525 EXPECT_THAT(Results.keys(), UnorderedElementsAre("p"));
1527 llvm::Succeeded());
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
1533 // constructor.
1534 std::string Code = R"(
1535 struct target {
1536 target() {
1538 // [[p]]
1539 // Mention the field so it is modeled;
1540 Val;
1543 int Val;
1546 runDataflow(
1547 Code,
1548 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
1549 ASTContext &ASTCtx) {
1550 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
1551 EXPECT_EQ(getFieldValue(Env.getThisPointeeStorageLocation(), "Val",
1552 ASTCtx, Env),
1553 nullptr);
1557 TEST(TransferTest, FieldsDontHaveValuesInConstructorWithBaseClass) {
1558 // See above, but for a class with a base class.
1559 std::string Code = R"(
1560 struct Base {
1561 int BaseVal;
1564 struct target : public Base {
1565 target() {
1567 // [[p]]
1568 // Mention the fields so they are modeled.
1569 BaseVal;
1570 Val;
1573 int Val;
1576 runDataflow(
1577 Code,
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",
1584 ASTCtx, Env),
1585 nullptr);
1586 EXPECT_EQ(getFieldValue(Env.getThisPointeeStorageLocation(), "Val",
1587 ASTCtx, Env),
1588 nullptr);
1592 TEST(TransferTest, StructModeledFieldsWithAccessor) {
1593 std::string Code = R"(
1594 class S {
1595 int *Ptr;
1596 int *PtrNonConst;
1597 int Int;
1598 int IntWithInc;
1599 int IntNotAccessed;
1600 int IntRef;
1601 public:
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; }
1612 void target() {
1613 S s;
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.
1627 s.returnVoid();
1628 // [[p]]
1631 runDataflow(
1632 Code,
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
1643 // modeled.
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`.
1657 namespace std {
1658 class type_info {};
1659 class bad_typeid {};
1660 } // namespace std
1662 struct NonPolymorphic {};
1664 struct Polymorphic {
1665 virtual ~Polymorphic() = default;
1668 struct S {
1669 NonPolymorphic *NonPoly;
1670 Polymorphic *Poly;
1673 void target(S &s) {
1674 typeid(*s.NonPoly);
1675 typeid(*s.Poly);
1676 // [[p]]
1679 runDataflow(
1680 Code,
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);
1688 EXPECT_THAT(Fields,
1689 UnorderedElementsAre(findValueDecl(ASTCtx, "Poly")));
1693 TEST(TransferTest, StructModeledFieldsWithComplicatedInheritance) {
1694 std::string Code = R"(
1695 struct Base1 {
1696 int base1_1;
1697 int base1_2;
1699 struct Intermediate : Base1 {
1700 int intermediate_1;
1701 int intermediate_2;
1703 struct Base2 {
1704 int base2_1;
1705 int base2_2;
1707 struct MostDerived : public Intermediate, Base2 {
1708 int most_derived_1;
1709 int most_derived_2;
1712 void target() {
1713 MostDerived MD;
1714 MD.base1_2 = 1;
1715 MD.intermediate_2 = 1;
1716 MD.base2_2 = 1;
1717 MD.most_derived_2 = 1;
1718 // [[p]]
1721 runDataflow(
1722 Code,
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"(
1743 struct Base1 {
1744 int base1;
1746 struct Intermediate : Base1 {
1747 int intermediate;
1749 struct Base2 {
1750 int base2;
1752 struct MostDerived : public Intermediate, Base2 {
1753 int most_derived;
1756 void target() {
1757 MostDerived MD = {};
1758 // [[p]]
1761 runDataflow(
1762 Code,
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)),
1773 NotNull());
1774 ASSERT_THAT(cast<IntegerValue>(
1775 getFieldValue(&MD, *findValueDecl(ASTCtx, "intermediate"), Env)),
1776 NotNull());
1777 ASSERT_THAT(cast<IntegerValue>(
1778 getFieldValue(&MD, *findValueDecl(ASTCtx, "base2"), Env)),
1779 NotNull());
1780 ASSERT_THAT(cast<IntegerValue>(
1781 getFieldValue(&MD, *findValueDecl(ASTCtx, "most_derived"), Env)),
1782 NotNull());
1786 TEST(TransferTest, ReferenceMember) {
1787 std::string Code = R"(
1788 struct A {
1789 int &Bar;
1792 void target(A Foo) {
1793 int Baz = Foo.Bar;
1794 // [[p]]
1797 runDataflow(
1798 Code,
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") {
1813 BarDecl = Field;
1814 } else {
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"(
1834 struct A {
1835 int Bar;
1837 struct B {
1838 int Baz;
1841 B Qux;
1843 void target() {
1844 int Foo = Bar;
1845 int Quux = Qux.Baz;
1846 // [[p]]
1850 runDataflow(
1851 Code,
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") {
1883 BazDecl = Field;
1884 } else {
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"(
1904 class A {
1905 int Bar;
1907 class B {
1908 public:
1909 int Baz;
1912 B Qux;
1914 void target() {
1915 int Foo = Bar;
1916 int Quux = Qux.Baz;
1917 // [[p]]
1921 runDataflow(
1922 Code,
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") {
1953 BazDecl = Field;
1954 } else {
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"(
1974 union A {
1975 int Foo;
1976 int Bar;
1978 void target() {
1979 A a;
1980 // Mention the fields to ensure they're included in the analysis.
1981 (void)a.Foo;
1982 (void)a.Bar;
1983 // [[p]]
1987 runDataflow(
1988 Code,
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"(
2021 struct A {
2022 void frob() {
2023 [this]() {
2024 int Foo = Bar;
2025 // [[p1]]
2026 }();
2029 int Bar;
2032 runDataflow(
2033 ThisCaptureCode,
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"(
2059 struct A {
2060 void frob() {
2061 [&]() {
2062 int Foo = Bar;
2063 // [[p2]]
2064 }();
2067 int Bar;
2070 runDataflow(
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"(
2097 void foo() {
2098 int Bar;
2099 [&]() {
2100 int Foo = Bar;
2101 // [[p3]]
2102 }();
2105 runDataflow(
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"(
2119 struct target {
2120 int Bar;
2122 target(int Foo) : Bar(Foo) {
2123 int Qux = Bar;
2124 // [[p]]
2128 runDataflow(
2129 Code,
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"(
2151 struct target {
2152 int Bar;
2153 int Baz = Bar;
2155 target(int Foo) : Bar(Foo) {
2156 int Qux = Baz;
2157 // [[p]]
2161 runDataflow(
2162 Code,
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"(
2184 struct target {
2185 int &Bar;
2186 int &Baz = Bar;
2188 target(int &Foo) : Bar(Foo) {
2189 int &Qux = Baz;
2190 // [[p]]
2194 runDataflow(
2195 Code,
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"(
2219 struct A {
2220 int Bar;
2223 void target() {
2224 A Foo = A();
2225 (void)Foo.Bar;
2226 // [[p]]
2229 runDataflow(
2230 Code,
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"(
2252 struct A {
2253 int Bar;
2256 void target() {
2257 A Foo = A();
2258 (void)Foo.Bar;
2259 // [[p]]
2262 runDataflow(
2263 Code,
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"(
2284 struct A {
2285 int Baz;
2288 void target() {
2289 A Foo = { 1 };
2290 A Bar = { 2 };
2291 // [[p1]]
2292 A &Rval = (Foo = Bar);
2293 // [[p2]]
2294 Foo.Baz = 3;
2295 // [[p3]]
2298 runDataflow(
2299 Code,
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"(
2371 struct A {
2372 int Baz;
2373 A &operator=(A);
2376 void target() {
2377 A Foo = { 1 };
2378 A Bar = { 2 };
2379 Foo = Bar;
2380 // [[p]]
2383 runDataflow(
2384 Code,
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"(
2405 struct Base {
2406 int base;
2408 struct Derived : public Base {
2409 using Base::operator=;
2410 int derived;
2412 void target(Base B, Derived D) {
2413 D.base = 1;
2414 D.derived = 1;
2415 // [[before]]
2416 D = B;
2417 // [[after]]
2420 runDataflow(
2421 Code,
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");
2429 auto &BLoc =
2430 getLocForDecl<RecordStorageLocation>(ASTCtx, EnvBefore, "B");
2431 auto &DLoc =
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"(
2446 struct A {};
2447 A ReturnA();
2449 void target() {
2450 A MyA;
2451 MyA = ReturnA();
2454 runDataflow(
2455 Code,
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 {};
2469 void target() {
2470 S S1 = { 1 };
2471 S S2;
2472 S S3;
2473 S1 = S2; // Only Dst has InitListExpr.
2474 S3 = S1; // Only Src has InitListExpr.
2475 // [[p]]
2478 runDataflow(
2479 Code,
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"(
2487 struct S {
2488 void operator=(S&& other);
2490 void target() {
2491 S s;
2492 s = S();
2493 // [[p]]
2496 runDataflow(
2497 Code,
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"(
2505 struct S {
2506 S operator=(const S&);
2507 int i;
2509 void target() {
2510 S S1 = { 1 };
2511 S S2 = { 2 };
2512 S S3 = { 3 };
2513 // [[before]]
2514 // Test that the returned value is modeled by assigning to another value.
2515 S1 = (S2 = S3);
2516 (void)0;
2517 // [[after]]
2520 runDataflow(
2521 Code,
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),
2543 EnvAfter));
2544 EXPECT_TRUE(recordsEqual(*EnvAfter.get<RecordStorageLocation>(*S2Decl),
2545 *EnvAfter.get<RecordStorageLocation>(*S3Decl),
2546 EnvAfter));
2550 TEST(TransferTest, AssignmentOperatorReturnsDifferentTypeByRef) {
2551 // This is a crash repro.
2552 std::string Code = R"(
2553 struct DifferentType {};
2554 struct S {
2555 DifferentType& operator=(const S&);
2557 void target() {
2558 S s;
2559 s = S();
2560 // [[p]]
2563 runDataflow(
2564 Code,
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 {};
2573 struct S {
2574 DifferentType operator=(const S&);
2576 void target() {
2577 S s;
2578 s = S();
2579 // [[p]]
2582 runDataflow(
2583 Code,
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"(
2591 void target() {
2592 bool&& Foo{false};
2593 // [[p]]
2596 runDataflow(
2597 Code,
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(
2609 struct S {};
2611 void target() { S foo[] = {S()}; }
2612 )cc";
2613 runDataflow(
2614 Code,
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(
2624 class target {
2625 union {
2626 int *a;
2627 bool *b;
2628 } F;
2630 public:
2631 constexpr target() : F{nullptr} {
2632 int *null = nullptr;
2633 F.b; // Make sure we reference 'b' so it is modeled.
2634 // [[p]]
2637 )cc";
2638 runDataflow(
2639 Code,
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(
2655 class target {
2656 union {
2657 int *a;
2658 bool *b;
2659 } F;
2661 public:
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.
2669 // [[p]]
2672 )cc";
2673 runDataflow(
2674 Code,
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(
2689 class target {
2690 struct {
2691 int *a;
2692 bool *b;
2693 } F;
2695 public:
2696 constexpr target() : F{} {
2697 int *NullIntPtr = nullptr;
2698 bool *NullBoolPtr = nullptr;
2699 // [[p]]
2702 )cc";
2703 runDataflow(
2704 Code,
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));
2712 EXPECT_EQ(AVal,
2713 &getValueForDecl<PointerValue>(ASTCtx, Env, "NullIntPtr"));
2714 auto *BVal = cast<PointerValue>(getFieldValue(&FLoc, "b", ASTCtx, Env));
2715 EXPECT_EQ(BVal,
2716 &getValueForDecl<PointerValue>(ASTCtx, Env, "NullBoolPtr"));
2720 TEST(TransferTest, CopyConstructor) {
2721 std::string Code = R"(
2722 struct A {
2723 int Baz;
2726 void target() {
2727 A Foo = { 1 };
2728 A Bar = Foo;
2729 // [[after_copy]]
2730 Foo.Baz = 2;
2731 // [[after_update]]
2734 runDataflow(
2735 Code,
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());
2747 // after_copy
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);
2768 // after_update
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"(
2791 struct A {
2792 int Baz;
2793 A() = default;
2794 A(const A& a, bool def = true) { Baz = a.Baz; }
2797 void target() {
2798 A Foo;
2799 (void)Foo.Baz;
2800 A Bar = Foo;
2801 // [[p]]
2804 runDataflow(
2805 Code,
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"(
2836 struct A {
2837 int Baz;
2840 void target() {
2841 A Foo;
2842 (void)Foo.Baz;
2843 A Bar((A(Foo)));
2844 // [[p]]
2847 runDataflow(
2848 Code,
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"(
2879 struct A {
2880 int Baz;
2882 void target() {
2883 A Foo = {3};
2884 (void)Foo.Baz;
2885 A Bar = {A(Foo)};
2886 // [[p]]
2889 runDataflow(
2890 Code,
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"(
2913 struct S {};
2914 const S &returnsSRef();
2915 void target() {
2916 S s(returnsSRef());
2919 runDataflow(
2920 Code,
2921 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
2922 ASTContext &ASTCtx) {});
2925 TEST(TransferTest, MoveConstructor) {
2926 std::string Code = R"(
2927 namespace std {
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);
2939 } // namespace std
2941 struct A {
2942 int Baz;
2945 void target() {
2946 A Foo;
2947 A Bar;
2948 (void)Foo.Baz;
2949 // [[p1]]
2950 Foo = std::move(Bar);
2951 // [[p2]]
2954 runDataflow(
2955 Code,
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"(
2996 struct A {
2997 virtual ~A() = default;
2999 int Baz;
3002 void target(A Foo) {
3003 int Bar = A(Foo).Baz;
3004 // [[p]]
3007 runDataflow(
3008 Code,
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"(
3032 struct A {
3033 virtual ~A() = default;
3036 void target() {
3037 0, A();
3038 (void)0; // [[p]]
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;
3051 runDataflow(
3052 Code,
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
3060 // all of these.
3061 auto MatchResult = match(
3062 traverse(TK_AsIs,
3063 exprWithCleanups(
3064 has(binaryOperator(
3065 hasOperatorName(","),
3066 hasRHS(cxxBindTemporaryExpr(
3067 has(cxxTemporaryObjectExpr().bind(
3068 "toe")))
3069 .bind("bte")))
3070 .bind("comma")))
3071 .bind("ewc")),
3072 ASTCtx);
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"(
3091 struct Inner {};
3092 struct Outer {
3093 Inner I = {};
3096 void funcWithDefaultArg(Outer O = {});
3097 void target() {
3098 funcWithDefaultArg();
3099 // [[p]]
3103 using ast_matchers::cxxDefaultArgExpr;
3104 using ast_matchers::match;
3105 using ast_matchers::selectFirst;
3106 runDataflow(
3107 Code,
3108 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3109 ASTContext &ASTCtx) {
3110 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3112 auto *DefaultArg = selectFirst<CXXDefaultArgExpr>(
3113 "default_arg",
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"(
3125 struct S {};
3126 struct target {
3127 target () {
3128 (void)0;
3129 // [[p]]
3131 S s = {};
3135 using ast_matchers::cxxCtorInitializer;
3136 using ast_matchers::match;
3137 using ast_matchers::selectFirst;
3138 runDataflow(
3139 Code,
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>(
3147 "ctor_initializer",
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"(
3164 struct A {
3165 A operator+(int);
3168 void target() {
3169 A a;
3170 a + 3;
3171 (void)0; // [[p]]
3174 using ast_matchers::cxxOperatorCallExpr;
3175 using ast_matchers::match;
3176 using ast_matchers::selectFirst;
3177 using ast_matchers::traverse;
3178 runDataflow(
3179 Code,
3180 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3181 ASTContext &ASTCtx) {
3182 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3184 auto *CallExpr = selectFirst<CXXOperatorCallExpr>(
3185 "call_expr",
3186 match(cxxOperatorCallExpr().bind("call_expr"), ASTCtx));
3188 EXPECT_NE(&Env.getResultObjectLocation(*CallExpr), nullptr);
3192 TEST(TransferTest, ResultObjectLocationForInitListExpr) {
3193 std::string Code = R"cc(
3194 struct Inner {};
3196 struct Outer { Inner I; };
3198 void target() {
3199 Outer O = { Inner() };
3200 // [[p]]
3202 )cc";
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;
3209 runDataflow(
3210 Code,
3211 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3212 ASTContext &ASTCtx) {
3213 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3215 auto *Construct = selectFirst<CXXConstructExpr>(
3216 "construct",
3217 match(
3218 cxxConstructExpr(hasType(asString("Inner"))).bind("construct"),
3219 ASTCtx));
3221 EXPECT_EQ(
3222 &Env.getResultObjectLocation(*Construct),
3223 &getFieldLoc(getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "O"),
3224 "I", ASTCtx));
3228 TEST(TransferTest, ResultObjectLocationForParenInitListExpr) {
3229 std::string Code = R"cc(
3230 struct Inner {};
3232 struct Outer { Inner I; };
3234 void target() {
3235 Outer O((Inner()));
3236 // [[p]]
3238 )cc";
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;
3245 runDataflow(
3246 Code,
3247 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3248 ASTContext &ASTCtx) {
3249 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3251 auto *Construct = selectFirst<CXXConstructExpr>(
3252 "construct",
3253 match(
3254 cxxConstructExpr(hasType(asString("Inner"))).bind("construct"),
3255 ASTCtx));
3257 EXPECT_EQ(
3258 &Env.getResultObjectLocation(*Construct),
3259 &getFieldLoc(getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "O"),
3260 "I", ASTCtx));
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"(
3269 namespace std {
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 };
3274 ordering o;
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;
3292 // [[p]]
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;
3300 runDataflow(
3301 Code,
3302 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3303 ASTContext &ASTCtx) {
3304 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3306 auto *Spaceship = selectFirst<BinaryOperator>(
3307 "op",
3308 match(binaryOperator(hasOperatorName("<=>")).bind("op"), ASTCtx));
3310 EXPECT_EQ(
3311 &Env.getResultObjectLocation(*Spaceship),
3312 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "ordering"));
3314 LangStandard::lang_cxx20);
3317 TEST(TransferTest, ResultObjectLocationForStdInitializerListExpr) {
3318 std::string Code = R"(
3319 namespace std {
3320 template <typename T>
3321 struct initializer_list { const T *a, *b; };
3322 } // namespace std
3324 void target() {
3325 std::initializer_list<int> list = {1};
3326 // [[p]]
3330 using ast_matchers::cxxStdInitializerListExpr;
3331 using ast_matchers::match;
3332 using ast_matchers::selectFirst;
3333 runDataflow(
3334 Code,
3335 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3336 ASTContext &ASTCtx) {
3337 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3339 auto *StdInitList = selectFirst<CXXStdInitializerListExpr>(
3340 "std_init_list",
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"(
3351 struct S {};
3352 void target() {
3353 S s = ({ S(); });
3354 // [[p]]
3357 using ast_matchers::cxxConstructExpr;
3358 using ast_matchers::match;
3359 using ast_matchers::selectFirst;
3360 using ast_matchers::traverse;
3361 runDataflow(
3362 Code,
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);
3380 // [[p]]
3383 using ast_matchers::explicitCastExpr;
3384 using ast_matchers::match;
3385 using ast_matchers::selectFirst;
3386 using ast_matchers::traverse;
3387 runDataflow(
3388 Code,
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"(
3403 struct S {};
3404 void target(_Atomic(S) *ptr) {
3405 S s = __c11_atomic_load(ptr, __ATOMIC_SEQ_CST);
3406 // [[p]]
3409 using ast_matchers::atomicExpr;
3410 using ast_matchers::match;
3411 using ast_matchers::selectFirst;
3412 using ast_matchers::traverse;
3413 runDataflow(
3414 Code,
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"(
3429 struct A {
3430 A(int);
3433 void target(bool b) {
3434 A a = b ? A(0) : A(1);
3435 (void)0; // [[p]]
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;
3445 runDataflow(
3446 Code,
3447 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
3448 ASTContext &ASTCtx) {
3449 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
3451 auto *ConstructExpr0 = selectFirst<CXXConstructExpr>(
3452 "construct",
3453 match(cxxConstructExpr(hasArgument(0, integerLiteral(equals(0))))
3454 .bind("construct"),
3455 ASTCtx));
3456 auto *ConstructExpr1 = selectFirst<CXXConstructExpr>(
3457 "construct",
3458 match(cxxConstructExpr(hasArgument(0, integerLiteral(equals(1))))
3459 .bind("construct"),
3460 ASTCtx));
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
3472 // only in these.
3473 std::string Code = R"(
3474 struct S1 {};
3475 struct S2 { S1 s1; };
3476 void target() {
3477 struct Nested {
3478 void f() {
3479 S2 s2 = { S1() };
3484 runDataflow(
3485 Code,
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) {
3496 runDataflow(
3497 Code,
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`.
3506 namespace std {
3507 class type_info {};
3508 class bad_typeid {};
3509 } // namespace std
3511 struct S1 {};
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() {
3522 typeof(S2{}) Dummy;
3524 void typeidTarget() {
3525 #if __has_feature(cxx_rtti)
3526 typeid(S2{});
3527 #endif
3529 void sizeofTarget() {
3530 sizeof(S2{});
3532 void noexceptTarget() {
3533 noexcept(S2{});
3535 )cc";
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);
3548 // [[p]]
3551 runDataflow(
3552 Code,
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) {
3575 long Bar = Foo;
3576 // [[p]]
3579 runDataflow(
3580 Code,
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) {
3594 bool Bar = Foo;
3595 // [[p]]
3598 runDataflow(
3599 Code,
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) {
3614 int Zab = Foo;
3615 bool Bar = Zab;
3616 // [[p]]
3619 runDataflow(
3620 Code,
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(
3641 struct S {
3642 int i;
3643 S *next;
3645 void target(S *s) {
3646 for (; s; s = s->next)
3647 s->i = false;
3649 )cc";
3650 runDataflow(Code,
3651 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
3652 ASTContext &) {});
3655 TEST(TransferTest, NullToPointerCast) {
3656 std::string Code = R"(
3657 using my_nullptr_t = decltype(nullptr);
3658 struct Baz {};
3659 void target() {
3660 int *FooX = nullptr;
3661 int *FooY = nullptr;
3662 bool **Bar = nullptr;
3663 Baz *Baz = nullptr;
3664 my_nullptr_t Null = 0;
3665 // [[p]]
3668 runDataflow(
3669 Code,
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"(
3722 struct S {
3723 int i;
3725 void target() {
3726 int S::*MemberPointer = &S::i;
3727 // [[p]]
3730 runDataflow(
3731 Code,
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"(
3745 struct S {
3746 void Method();
3748 void target() {
3749 void (S::*MemberPointer)() = &S::Method;
3750 // [[p]]
3753 runDataflow(
3754 Code,
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"(
3768 struct Foo {};
3769 void target() {
3770 int Foo::*MemberPointer = nullptr;
3771 // [[p]]
3774 runDataflow(
3775 Code,
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"(
3790 void target() {
3791 int Foo;
3792 int *Bar = &Foo;
3793 // [[p]]
3796 runDataflow(
3797 Code,
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) {
3819 int *Bar = &(*Foo);
3820 // [[p]]
3823 runDataflow(
3824 Code,
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]]
3846 int &IRef = ++I;
3847 // [[after]]
3850 runDataflow(
3851 Code,
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]]
3872 int OldVal = I++;
3873 // [[after]]
3876 runDataflow(
3877 Code,
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);
3899 // [[p]]
3902 runDataflow(
3903 Code,
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>
3916 void target() {}
3918 ASSERT_THAT_ERROR(
3919 checkDataflowWithNoopAnalysis(Code),
3920 llvm::FailedWithMessage("Cannot analyze templated declarations"));
3923 TEST(TransferTest, CannotAnalyzeMethodOfClassTemplate) {
3924 std::string Code = R"(
3925 template <typename T>
3926 struct A {
3927 void target() {}
3930 ASSERT_THAT_ERROR(
3931 checkDataflowWithNoopAnalysis(Code),
3932 llvm::FailedWithMessage("Cannot analyze templated declarations"));
3935 TEST(TransferTest, VarDeclInitAssignConditionalOperator) {
3936 std::string Code = R"(
3937 struct A {
3938 int i;
3941 void target(A Foo, A Bar, bool Cond) {
3942 A Baz = Cond ? A(Foo) : A(Bar);
3943 // Make sure A::i is modeled.
3944 Baz.i;
3945 /*[[p]]*/
3948 runDataflow(
3949 Code,
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",
3956 ASTCtx, Env));
3957 auto *BarIVal = cast<IntegerValue>(getFieldValue(
3958 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar"), "i",
3959 ASTCtx, Env));
3960 auto *BazIVal = cast<IntegerValue>(getFieldValue(
3961 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Baz"), "i",
3962 ASTCtx, Env));
3964 EXPECT_NE(BazIVal, FooIVal);
3965 EXPECT_NE(BazIVal, BarIVal);
3969 TEST(TransferTest, VarDeclInDoWhile) {
3970 std::string Code = R"(
3971 void target(int *Foo) {
3972 do {
3973 int Bar = *Foo;
3974 // [[in_loop]]
3975 } while (false);
3976 (void)0;
3977 // [[after_loop]]
3980 runDataflow(
3981 Code,
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"(
4009 void target() {
4010 while (true) {}
4011 (void)0;
4012 /*[[p]]*/
4015 runDataflow(
4016 Code,
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"(
4027 struct A {
4028 int Foo;
4031 struct B {
4032 int Bar;
4033 A Baz;
4034 int Qux;
4037 void target(int BarArg, int FooArg, int QuxArg) {
4038 B Quux{BarArg, {FooArg}, QuxArg};
4039 B OtherB;
4040 /*[[p]]*/
4043 std::string BraceElisionCode = R"(
4044 struct A {
4045 int Foo;
4048 struct B {
4049 int Bar;
4050 A Baz;
4051 int Qux;
4054 void target(int BarArg, int FooArg, int QuxArg) {
4055 B Quux = {BarArg, FooArg, QuxArg};
4056 B OtherB;
4057 /*[[p]]*/
4060 for (const std::string &Code : {BracesCode, BraceElisionCode}) {
4061 runDataflow(
4062 Code,
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"(
4118 struct S {
4119 int &RefField;
4122 void target(int i) {
4123 S s = { i };
4124 /*[[p]]*/
4127 runDataflow(
4128 Code,
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"(
4144 struct S {
4145 int i1;
4146 int i2;
4149 void target(int i) {
4150 S s = { i };
4151 /*[[p]]*/
4154 runDataflow(
4155 Code,
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");
4166 auto &I1Value =
4167 *cast<IntegerValue>(getFieldValue(&SLoc, *I1FieldDecl, Env));
4168 EXPECT_EQ(&I1Value, &IValue);
4169 auto &I2Value =
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"(
4181 struct S {
4182 void (*const Field)();
4185 void target() {
4186 S s{nullptr};
4189 runDataflow(
4190 Code,
4191 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4192 ASTContext &ASTCtx) {});
4195 TEST(TransferTest, AssignToUnionMember) {
4196 std::string Code = R"(
4197 union A {
4198 int Foo;
4201 void target(int Bar) {
4202 A Baz;
4203 Baz.Foo = Bar;
4204 // [[p]]
4207 runDataflow(
4208 Code,
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") {
4222 FooDecl = Field;
4223 } else {
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"(
4247 void target() {
4248 bool Foo = true;
4249 bool Bar = false;
4250 // [[p]]
4253 runDataflow(
4254 Code,
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);
4284 // [[p]]
4287 runDataflow(
4288 Code,
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);
4332 // [[p]]
4335 runDataflow(
4336 Code,
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;
4380 // [[p]]
4383 runDataflow(
4384 Code,
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();
4421 EXPECT_EQ(
4422 &FooVal->formula(),
4423 &A.makeAnd(A.makeAnd(A.makeAnd(AVal->formula(), BVal->formula()),
4424 CVal->formula()),
4425 DVal->formula()));
4430 TEST(TransferTest, AssignFromBoolNegation) {
4431 std::string Code = R"(
4432 void target() {
4433 bool Foo = true;
4434 bool Bar = !(Foo);
4435 // [[p]]
4438 runDataflow(
4439 Code,
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);
4467 /*[[p]]*/
4470 runDataflow(
4471 Code,
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
4489 // case.
4490 TEST(TransferTest, BuiltinExpectBoolArg) {
4491 std::string Code = R"(
4492 void target(bool Foo) {
4493 bool Bar = __builtin_expect(Foo, true);
4494 /*[[p]]*/
4497 runDataflow(
4498 Code,
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) {
4517 bool Bar = false;
4518 if (Foo)
4519 Bar = Foo;
4520 else
4521 __builtin_unreachable();
4522 (void)0;
4523 /*[[p]]*/
4526 runDataflow(
4527 Code,
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) {
4549 bool Bar = false;
4550 if (Foo)
4551 Bar = Foo;
4552 else
4553 __builtin_trap();
4554 (void)0;
4555 /*[[p]]*/
4558 runDataflow(
4559 Code,
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) {
4580 bool Bar = false;
4581 if (Foo)
4582 Bar = Foo;
4583 else
4584 __builtin_debugtrap();
4585 (void)0;
4586 /*[[p]]*/
4589 runDataflow(
4590 Code,
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"(
4609 void target() {
4610 static int Foo;
4611 // [[p]]
4614 runDataflow(
4615 Code,
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"(
4634 void target() {
4635 static int Foo, Bar;
4636 (void)0;
4637 // [[p]]
4640 runDataflow(
4641 Code,
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"(
4671 static int Foo;
4673 void target() {
4674 int Bar = Foo;
4675 int Baz = Foo;
4676 // [[p]]
4679 runDataflow(
4680 Code,
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"(
4700 struct A {
4701 static int Foo;
4704 void target(A a) {
4705 int Bar = a.Foo;
4706 int Baz = a.Foo;
4707 // [[p]]
4710 runDataflow(
4711 Code,
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"(
4731 struct A {
4732 static int &Foo;
4735 void target(A a) {
4736 int Bar = a.Foo;
4737 int Baz = a.Foo;
4738 // [[p]]
4741 runDataflow(
4742 Code,
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"(
4762 struct A {
4763 int Foo;
4766 void target() {
4767 A A1;
4768 A A2;
4769 int Bar;
4770 A1.Foo = Bar;
4771 A2 = A1;
4772 // [[p]]
4775 runDataflow(
4776 Code,
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));
4796 const auto &A2Loc =
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) {
4805 bool Foo = true;
4806 if (Bar == Foo) {
4807 (void)0;
4808 /*[[p-then]]*/
4809 } else {
4810 (void)0;
4811 /*[[p-else]]*/
4815 runDataflow(
4816 Code,
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) {
4839 bool Foo = true;
4840 if (Bar != Foo) {
4841 (void)0;
4842 /*[[p-then]]*/
4843 } else {
4844 (void)0;
4845 /*[[p-else]]*/
4849 runDataflow(
4850 Code,
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(
4872 void target() {
4873 int i = 0;
4874 int i_other = 0;
4875 int *p1 = &i;
4876 int *p2 = &i;
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);
4894 (void)0; // [[p]]
4896 )cc";
4897 runDataflow(
4898 Code,
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));
4921 EXPECT_EQ(
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(
4932 union U {
4933 int i1;
4934 int i2;
4936 void target() {
4937 U u;
4938 bool i1_eq_i2 = (&u.i1 == &u.i2);
4940 (void)0; // [[p]]
4942 )cc";
4943 runDataflow(
4944 Code,
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"(
4960 void target() {
4961 bool equal = (42 == 42);
4962 // [[p]]
4965 runDataflow(
4966 Code,
4967 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
4968 ASTContext &ASTCtx) {
4969 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
4971 auto &Equal =
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) {
4980 if (B) {
4981 return;
4983 (void)0;
4984 /*[[p0]]*/
4985 if (C) {
4986 B = true;
4987 /*[[p1]]*/
4989 if (B) {
4990 (void)0;
4991 /*[[p2]]*/
4995 runDataflow(
4996 Code,
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"(
5029 bool foo();
5031 void target() {
5032 do {
5033 bool Bar = foo();
5034 if (Bar) break;
5035 (void)Bar;
5036 /*[[p]]*/
5037 } while (true);
5040 // The key property that we are verifying is implicit in `runDataflow` --
5041 // namely, that the analysis succeeds, rather than hitting the maximum number
5042 // of iterations.
5043 runDataflow(
5044 Code,
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"(
5060 bool foo();
5062 void target() {
5063 bool Bar = false;
5064 bool Err = false;
5065 while (foo()) {
5066 if (Bar)
5067 Err = true;
5068 Bar = true;
5069 /*[[p]]*/
5073 runDataflow(
5074 Code,
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
5090 // reached.
5091 EXPECT_FALSE(Env.proves(Env.arena().makeNot(ErrVal)));
5095 TEST(TransferTest, LoopWithReferenceAssignmentConverges) {
5096 std::string Code = R"(
5097 bool &foo();
5099 void target() {
5100 do {
5101 bool& Bar = foo();
5102 if (Bar) break;
5103 (void)Bar;
5104 /*[[p]]*/
5105 } while (true);
5108 // The key property that we are verifying is that the analysis succeeds,
5109 // rather than hitting the maximum number of iterations.
5110 runDataflow(
5111 Code,
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"(
5127 struct Lookup {
5128 int x;
5131 void target(Lookup val, bool b) {
5132 const Lookup* l = nullptr;
5133 while (b) {
5134 l = &val;
5135 /*[[p-inner]]*/
5137 (void)0;
5138 /*[[p-outer]]*/
5141 // The key property that we are verifying is implicit in `runDataflow` --
5142 // namely, that the analysis succeeds, rather than hitting the maximum number
5143 // of iterations.
5144 runDataflow(
5145 Code,
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());
5160 // Inner.
5161 auto *LVal = dyn_cast<PointerValue>(InnerEnv.getValue(*LDecl));
5162 ASSERT_THAT(LVal, NotNull());
5164 EXPECT_EQ(&LVal->getPointeeLoc(),
5165 InnerEnv.getStorageLocation(*ValDecl));
5167 // Outer.
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) {
5183 int *p = &i1;
5184 while (true) {
5185 (void)*p;
5186 if (some_condition())
5187 p = &i1;
5188 else
5189 p = &i2;
5192 )cc";
5193 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded());
5196 TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) {
5197 std::string Code = R"cc(
5198 struct Lookup {
5199 int x;
5202 bool some_condition();
5204 void target(Lookup l1, Lookup l2) {
5205 Lookup *l = &l1;
5206 while (true) {
5207 (void)l->x;
5208 if (some_condition())
5209 l = &l1;
5210 else
5211 l = &l2;
5214 )cc";
5215 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded());
5218 TEST(TransferTest, LoopWithShortCircuitedConditionConverges) {
5219 std::string Code = R"cc(
5220 bool foo();
5222 void target() {
5223 bool c = false;
5224 while (foo() || foo()) {
5225 c = true;
5228 )cc";
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(
5238 int return_int();
5239 void target() {
5240 bool b = return_int() == 0;
5241 if (b) return;
5242 while (true) {
5244 // [[p]]
5245 b = return_int() == 0;
5246 if (b) return;
5249 )cc";
5250 runDataflow(
5251 Code,
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(
5262 union Union {
5263 int A;
5264 float B;
5267 void foo() {
5268 Union A;
5269 Union B;
5270 A = B;
5272 )cc";
5273 // This is a crash regression test when calling the transfer function on a
5274 // `CXXThisExpr` that refers to a union.
5275 runDataflow(
5276 Code,
5277 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
5278 ASTContext &) {},
5279 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator=");
5282 TEST(TransferTest, DoesNotCrashOnNullChildren) {
5283 std::string Code = (CoroutineLibrary + R"cc(
5284 task target() noexcept {
5285 co_return;
5287 )cc")
5288 .str();
5289 // This is a crash regression test when calling `AdornedCFG::build` on a
5290 // statement (in this case, the `CoroutineBodyStmt`) with null children.
5291 runDataflow(
5292 Code,
5293 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
5294 ASTContext &) {},
5295 LangStandard::lang_cxx20, /*ApplyBuiltinTransfer=*/true);
5298 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToRefs) {
5299 std::string Code = R"(
5300 struct A {
5301 int Foo;
5302 int Bar;
5305 void target() {
5306 int Qux;
5307 A Baz;
5308 Baz.Foo = Qux;
5309 auto &FooRef = Baz.Foo;
5310 auto &BarRef = Baz.Bar;
5311 auto &[BoundFooRef, BoundBarRef] = Baz;
5312 // [[p]]
5315 runDataflow(
5316 Code,
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"(
5360 struct A {
5361 int &Foo;
5362 int &Bar;
5365 void target(A Baz) {
5366 int Qux;
5367 Baz.Foo = Qux;
5368 auto &FooRef = Baz.Foo;
5369 auto &BarRef = Baz.Bar;
5370 auto &[BoundFooRef, BoundBarRef] = Baz;
5371 // [[p]]
5374 runDataflow(
5375 Code,
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"(
5419 struct A {
5420 int Foo;
5421 int Bar;
5424 void target() {
5425 int Qux;
5426 A Baz;
5427 Baz.Foo = Qux;
5428 auto &FooRef = Baz.Foo;
5429 auto &BarRef = Baz.Bar;
5430 auto [BoundFoo, BoundBar] = Baz;
5431 // [[p]]
5434 runDataflow(
5435 Code,
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"(
5479 namespace std {
5480 using size_t = int;
5481 template <class> struct tuple_size;
5482 template <std::size_t, class> struct tuple_element;
5483 template <class...> class tuple;
5485 namespace {
5486 template <class T, T v>
5487 struct size_helper { static const T value = v; };
5488 } // namespace
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...>);
5502 } // namespace std
5504 std::tuple<bool, int> makeTuple();
5506 void target(bool B) {
5507 auto [BoundFoo, BoundBar] = makeTuple();
5508 bool Baz;
5509 // Include if-then-else to test interaction of `BindingDecl` with join.
5510 if (B) {
5511 Baz = BoundFoo;
5512 (void)BoundBar;
5513 // [[p1]]
5514 } else {
5515 Baz = BoundFoo;
5517 (void)0;
5518 // [[p2]]
5521 runDataflow(
5522 Code,
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"(
5560 namespace std {
5561 using size_t = int;
5562 template <class> struct tuple_size;
5563 template <std::size_t, class> struct tuple_element;
5564 template <class...> class tuple;
5566 namespace {
5567 template <class T, T v>
5568 struct size_helper { static const T value = v; };
5569 } // namespace
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...>);
5583 } // namespace std
5585 std::tuple<bool, int> &getTuple();
5587 void target(bool B) {
5588 auto &[BoundFoo, BoundBar] = getTuple();
5589 bool Baz;
5590 // Include if-then-else to test interaction of `BindingDecl` with join.
5591 if (B) {
5592 Baz = BoundFoo;
5593 (void)BoundBar;
5594 // [[p1]]
5595 } else {
5596 Baz = BoundFoo;
5598 (void)0;
5599 // [[p2]]
5602 runDataflow(
5603 Code,
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);
5644 // [[p]]
5647 runDataflow(
5648 Code,
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;
5673 // [[p]]
5676 runDataflow(
5677 Code,
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;
5707 // [[p]]
5710 runDataflow(
5711 Code,
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);
5737 // [[p]]
5739 )cc";
5740 runDataflow(
5741 Code,
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) {
5764 if (Foo) {
5765 (void)0;
5766 // [[if_then]]
5767 } else {
5768 (void)0;
5769 // [[if_else]]
5773 runDataflow(
5774 Code,
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) {
5797 while (Foo) {
5798 (void)0;
5799 // [[loop_body]]
5801 (void)0;
5802 // [[after_loop]]
5805 runDataflow(
5806 Code,
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);
5823 EXPECT_TRUE(
5824 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal)));
5828 TEST(TransferTest, DoWhileStmtBranchExtendsFlowCondition) {
5829 std::string Code = R"(
5830 void target(bool Foo) {
5831 bool Bar = true;
5832 do {
5833 (void)0;
5834 // [[loop_body]]
5835 Bar = false;
5836 } while (Foo);
5837 (void)0;
5838 // [[after_loop]]
5841 runDataflow(
5842 Code,
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);
5861 EXPECT_TRUE(
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) {
5874 for (; Foo;) {
5875 (void)0;
5876 // [[loop_body]]
5878 (void)0;
5879 // [[after_loop]]
5882 runDataflow(
5883 Code,
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);
5900 EXPECT_TRUE(
5901 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal)));
5905 TEST(TransferTest, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition) {
5906 std::string Code = R"(
5907 void target(bool Foo) {
5908 for (;;) {
5909 (void)0;
5910 // [[loop_body]]
5914 runDataflow(
5915 Code,
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"(
5932 bool GiveBool();
5933 void SetBool(bool &Var) { Var = true; }
5935 void target() {
5936 bool Foo = GiveBool();
5937 SetBool(Foo);
5938 // [[p]]
5941 runDataflow(
5942 Code,
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"(
5960 class S {};
5961 S& target(bool b, S &s) {
5962 return s;
5963 // [[p]]
5966 runDataflow(
5967 Code,
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"(
5986 class S {};
5987 S& target(bool b, S &s) {
5988 return b ? s : s;
5989 // [[p]]
5992 runDataflow(
5993 Code,
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"(
6015 class S {};
6016 S &callee(bool b, S &s1_parm, S &s2_parm) {
6017 if (b)
6018 return s1_parm;
6019 else
6020 return s2_parm;
6022 void target(bool b) {
6023 S s1;
6024 S s2;
6025 S &return_s1 = s1;
6026 S &return_s2 = s2;
6027 S &return_dont_know = callee(b, s1, s2);
6028 // [[p]]
6031 runDataflow(
6032 Code,
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"(
6066 bool GiveBool();
6067 void SetBool(bool &Var) { Var = true; }
6069 void target() {
6070 bool Foo = GiveBool();
6071 SetBool(Foo);
6072 // [[p]]
6075 runDataflow(
6076 Code,
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"(
6094 bool GiveBool();
6095 void SetBool(bool &Var) { Var = true; }
6097 void target() {
6098 bool Foo = GiveBool();
6099 SetBool(Foo);
6100 // [[p]]
6103 runDataflow(
6104 Code,
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"(
6121 bool GiveBool();
6122 void SetBool(bool &Var) { Var = false; }
6124 void target() {
6125 bool Foo = GiveBool();
6126 SetBool(Foo);
6127 // [[p]]
6130 runDataflow(
6131 Code,
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"(
6148 bool GiveBool();
6149 void SetBool(bool &Var, bool Val) { Var = Val; }
6151 void target() {
6152 bool Foo = GiveBool();
6153 bool Bar = GiveBool();
6154 SetBool(Foo, true);
6155 SetBool(Bar, false);
6156 // [[p]]
6159 runDataflow(
6160 Code,
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"(
6186 bool GiveBool();
6187 void SetBool1(bool &Var) { Var = true; }
6188 void SetBool2(bool &Var) { SetBool1(Var); }
6190 void target() {
6191 bool Foo = GiveBool();
6192 SetBool2(Foo);
6193 // [[p]]
6196 runDataflow(
6197 Code,
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"(
6215 bool GiveBool();
6216 void SetBool1(bool &Var) { Var = true; }
6217 void SetBool2(bool &Var) { SetBool1(Var); }
6219 void target() {
6220 bool Foo = GiveBool();
6221 SetBool2(Foo);
6222 // [[p]]
6225 runDataflow(
6226 Code,
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"(
6243 bool GiveBool();
6244 void SetBool1(bool &Var) { Var = true; }
6245 void SetBool2(bool &Var) { SetBool1(Var); }
6246 void SetBool3(bool &Var) { SetBool2(Var); }
6248 void target() {
6249 bool Foo = GiveBool();
6250 SetBool3(Foo);
6251 // [[p]]
6254 runDataflow(
6255 Code,
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"(
6273 bool GiveBool();
6274 void SetBool1(bool &Var) { Var = true; }
6275 void SetBool2(bool &Var) { SetBool1(Var); }
6276 void SetBool3(bool &Var) { SetBool2(Var); }
6278 void target() {
6279 bool Foo = GiveBool();
6280 SetBool3(Foo);
6281 // [[p]]
6284 runDataflow(
6285 Code,
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) {
6305 if (X) {
6306 return Y;
6307 } else {
6308 return Pong(!X, Y);
6312 bool Pong(bool X, bool Y) {
6313 if (Y) {
6314 return X;
6315 } else {
6316 return Ping(X, !Y);
6320 void target() {
6321 bool Foo = Ping(false, false);
6322 // [[p]]
6325 runDataflow(
6326 Code,
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) {
6347 Var1 = true;
6348 Var2 = false;
6351 void target() {
6352 bool Foo = false;
6353 bool Bar = true;
6354 SetBools(Foo, Bar);
6355 // [[p]]
6358 runDataflow(
6359 Code,
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) {
6385 if (Cond) {
6386 Then = true;
6387 } else {
6388 Else = true;
6392 void target() {
6393 bool Foo = false;
6394 bool Bar = false;
6395 bool Baz = false;
6396 IfCond(Foo, Bar, Baz);
6397 // [[p]]
6400 runDataflow(
6401 Code,
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; }
6428 void target() {
6429 Noop();
6430 // [[p]]
6433 runDataflow(
6434 Code,
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; }
6447 void target() {
6448 bool Foo = GiveBool();
6449 // [[p]]
6452 runDataflow(
6453 Code,
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; }
6472 void target() {
6473 bool Foo = GiveBool();
6474 // [[p]]
6477 runDataflow(
6478 Code,
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"(
6495 bool GiveBool();
6496 bool GiveBack(bool Arg) { return Arg; }
6498 void target() {
6499 bool Foo = GiveBool();
6500 bool Bar = GiveBack(Foo);
6501 bool Baz = Foo == Bar;
6502 // [[p]]
6505 runDataflow(
6506 Code,
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; }
6525 void target() {
6526 int y = identity(42);
6527 // [[p]]
6530 runDataflow(
6531 Code,
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"(
6542 struct S {
6543 bool B;
6546 S makeS(bool BVal) { return {BVal}; }
6548 void target() {
6549 S FalseS = makeS(false);
6550 S TrueS = makeS(true);
6551 // [[p]]
6554 runDataflow(
6555 Code,
6556 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
6557 ASTContext &ASTCtx) {
6558 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
6560 auto &FalseSLoc =
6561 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "FalseS");
6562 auto &TrueSLoc =
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"(
6575 struct S {
6576 S() { self = this; }
6577 S *self;
6580 S makeS() {
6581 // RVO guarantees that this will be constructed directly into `MyS`.
6582 return S();
6585 void target() {
6586 S MyS = makeS();
6587 // [[p]]
6590 runDataflow(
6591 Code,
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");
6598 auto *SelfVal =
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"(
6607 class MyClass {
6608 public:
6609 bool giveBool() { return true; }
6612 void target() {
6613 MyClass MyObj;
6614 bool Foo = MyObj.giveBool();
6615 // [[p]]
6618 runDataflow(
6619 Code,
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"(
6636 class MyClass {
6637 public:
6638 bool getField() { return Field; }
6640 bool Field;
6643 void target() {
6644 MyClass MyObj;
6645 MyObj.Field = true;
6646 bool Foo = MyObj.getField();
6647 // [[p]]
6650 runDataflow(
6651 Code,
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"(
6668 class MyClass {
6669 public:
6670 void setField(bool Val) { Field = Val; }
6672 bool Field;
6675 void target() {
6676 MyClass MyObj;
6677 MyObj.setField(true);
6678 bool Foo = MyObj.Field;
6679 // [[p]]
6682 runDataflow(
6683 Code,
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"(
6700 class MyClass {
6701 public:
6702 bool getField() { return Field; }
6703 void setField(bool Val) { Field = Val; }
6705 private:
6706 bool Field;
6709 void target() {
6710 MyClass MyObj;
6711 MyObj.setField(true);
6712 bool Foo = MyObj.getField();
6713 // [[p]]
6716 runDataflow(
6717 Code,
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"(
6735 class MyClass {
6736 public:
6737 void Inner() { MyField = true; }
6738 void Outer() { Inner(); }
6740 bool MyField;
6743 void target() {
6744 MyClass MyObj;
6745 MyObj.Outer();
6746 bool Foo = MyObj.MyField;
6747 // [[p]]
6750 runDataflow(
6751 Code,
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"(
6769 class MyClass {
6770 public:
6771 bool Inner() { return MyField; }
6772 bool Outer() { return Inner(); }
6774 bool MyField;
6777 void target() {
6778 MyClass MyObj;
6779 MyObj.MyField = true;
6780 bool Foo = MyObj.Outer();
6781 // [[p]]
6784 runDataflow(
6785 Code,
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"(
6803 class MyClass {
6804 public:
6805 MyClass() { MyField = true; }
6807 bool MyField;
6810 void target() {
6811 MyClass MyObj;
6812 bool Foo = MyObj.MyField;
6813 // [[p]]
6816 runDataflow(
6817 Code,
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"(
6834 class MyClass {
6835 public:
6836 MyClass() : MyField(true) {}
6838 bool MyField;
6841 void target() {
6842 MyClass MyObj;
6843 bool Foo = MyObj.MyField;
6844 // [[p]]
6847 runDataflow(
6848 Code,
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"(
6865 class MyClass {
6866 public:
6867 MyClass() = default;
6869 bool MyField = true;
6872 void target() {
6873 MyClass MyObj;
6874 bool Foo = MyObj.MyField;
6875 // [[p]]
6878 runDataflow(
6879 Code,
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"(
6898 class MyClass {
6899 public:
6900 MyClass() : Self(this) {}
6901 MyClass *Self;
6904 void target() {
6905 MyClass MyObj;
6906 MyClass *SelfPtr = MyObj.Self;
6907 // [[p]]
6910 runDataflow(
6911 Code,
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"(
6931 struct B {};
6932 struct A {
6933 unsigned a;
6934 unsigned : 4;
6935 unsigned c;
6936 B b;
6938 void target() {
6939 A a = {};
6940 A test = a;
6941 (void)test.c;
6944 runDataflow(
6945 Code,
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
6954 // operators.
6955 TEST(TransferTest, ChainedLogicalOps) {
6956 std::string Code = R"(
6957 bool target() {
6958 bool b = true || false || false || false;
6959 // [[p]]
6960 return b;
6963 runDataflow(
6964 Code,
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`
6983 // will be true.
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();
6993 else
6994 NoreturnOnLhsMakesAndUnreachable = true;
6996 bool NoreturnOnLhsMakesOrUnreachable = false;
6997 if (some_condition())
6998 doesnt_return() > 0 || some_condition();
6999 else
7000 NoreturnOnLhsMakesOrUnreachable = true;
7002 // [[p]]
7005 runDataflow(
7006 Code,
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")
7028 .formula();
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"(
7043 void target() {
7044 int *p = new int(42);
7045 // [[after_new]]
7048 runDataflow(
7049 Code,
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"(
7063 struct Inner {
7064 int InnerField;
7067 struct Outer {
7068 Inner OuterField;
7071 void target() {
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;
7076 // [[after_new]]
7079 runDataflow(
7080 Code,
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(); };
7103 void target() {
7104 // To check that we're treating function-to-pointer decay correctly,
7105 // create two pointers, then verify they refer to the same storage
7106 // location.
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;
7116 // [[p]]
7119 runDataflow(
7120 Code,
7121 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
7122 ASTContext &ASTCtx) {
7123 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
7125 auto &NonMemberP1 =
7126 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p1");
7127 auto &NonMemberP2 =
7128 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p2");
7129 EXPECT_EQ(&NonMemberP1.getPointeeLoc(), &NonMemberP2.getPointeeLoc());
7131 auto &MemberP1 =
7132 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p1");
7133 auto &MemberP2 =
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"(
7143 void target() {
7144 __builtin_expect(0, 0);
7145 // [[p]]
7148 runDataflow(
7149 Code,
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>(
7161 "implicit_cast",
7162 match(traverse(TK_AsIs,
7163 implicitCastExpr(hasCastKind(CK_BuiltinFnToFnPtr))
7164 .bind("implicit_cast")),
7165 ASTCtx));
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
7176 // type).
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"(
7181 struct S {
7182 bool operator!=(S s);
7184 void target() {
7185 S s;
7186 (void)(s != s);
7187 (void)(s != s);
7188 // [[p]]
7191 runDataflow(
7192 Code,
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"(
7228 struct S {
7229 struct {
7230 bool b;
7233 void target() {
7234 S s;
7235 s.b = true;
7236 // [[p]]
7239 runDataflow(
7240 Code,
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"(
7260 struct target {
7261 target() {
7262 (void)0;
7263 // [[p]]
7265 struct {
7266 bool b = true;
7270 runDataflow(
7271 Code,
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");
7279 auto *ThisLoc =
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"(
7291 int global_i = 0;
7292 struct target {
7293 target() {
7294 (void)0;
7295 // [[p]]
7297 struct {
7298 int &i = global_i;
7302 runDataflow(
7303 Code,
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");
7312 auto *ThisLoc =
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"(
7329 int target(int i) {
7330 if ((i < 0 && true) || false) {
7331 return 0;
7333 return 0;
7336 runDataflow(
7337 Code,
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) {
7345 [Foo]() {
7346 (void)0;
7347 // [[p]]
7348 }();
7351 runDataflowOnLambda(
7352 Code,
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) {
7378 [&Foo]() {
7379 (void)0;
7380 // [[p]]
7381 }();
7384 runDataflowOnLambda(
7385 Code,
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) {
7411 [Foo=Bar]() {
7412 (void)0;
7413 // [[p]]
7414 }();
7417 runDataflowOnLambda(
7418 Code,
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) {
7444 [=]() {
7445 Foo;
7446 // [[p]]
7447 }();
7450 runDataflowOnLambda(
7451 Code,
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) {
7479 [&]() {
7480 Foo;
7481 // [[p]]
7482 }();
7485 runDataflowOnLambda(
7486 Code,
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"(
7513 struct Bar {
7514 int Foo;
7516 void target() {
7517 [this]() {
7518 Foo;
7519 // [[p]]
7520 }();
7524 runDataflowOnLambda(
7525 Code,
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"(
7550 bool cond();
7551 void target() {
7552 bool a = true;
7553 bool b = true;
7554 if (cond()) {
7555 a = false;
7556 if (cond()) {
7557 b = false;
7560 (void)0;
7561 // [[p]]
7564 runDataflow(
7565 Code,
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(
7586 struct S {
7587 struct {
7588 int i;
7592 template <class>
7593 void target() {
7594 S().i;
7597 template void target<int>();
7598 )cc";
7599 auto Matcher = functionDecl(hasName("target"), unless(isTemplated()));
7600 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code, Matcher),
7601 llvm::Succeeded());
7604 } // namespace