xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp (revision 963f40051a4216936b47dad56765d60b64b7840d)
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 //===----------------------------------------------------------------------===//
8 
9 #include "NoopAnalysis.h"
10 #include "TestingSupport.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/AST/Decl.h"
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 #include "clang/ASTMatchers/ASTMatchers.h"
15 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
16 #include "clang/Analysis/FlowSensitive/StorageLocation.h"
17 #include "clang/Analysis/FlowSensitive/Value.h"
18 #include "llvm/ADT/ArrayRef.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/Support/Casting.h"
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 #include <cassert>
24 #include <string>
25 #include <utility>
26 
27 namespace {
28 
29 using namespace clang;
30 using namespace dataflow;
31 using ::testing::_;
32 using ::testing::ElementsAre;
33 using ::testing::IsNull;
34 using ::testing::NotNull;
35 using ::testing::Pair;
36 
37 class TransferTest : public ::testing::Test {
38 protected:
39   template <typename Matcher>
40   void runDataflow(llvm::StringRef Code, Matcher Match) {
41     test::checkDataflow<NoopAnalysis>(
42         Code, "target",
43         [](ASTContext &C, Environment &) { return NoopAnalysis(C); },
44         [&Match](llvm::ArrayRef<
45                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
46                      Results,
47                  ASTContext &ASTCtx) { Match(Results, ASTCtx); },
48         {"-fsyntax-only", "-std=c++17"});
49   }
50 };
51 
52 /// Returns the `ValueDecl` for the given identifier.
53 ///
54 /// Requirements:
55 ///
56 ///  `Name` must be unique in `ASTCtx`.
57 static const ValueDecl *findValueDecl(ASTContext &ASTCtx,
58                                       llvm::StringRef Name) {
59   auto TargetNodes = ast_matchers::match(
60       ast_matchers::valueDecl(ast_matchers::hasName(Name)).bind("v"), ASTCtx);
61   assert(TargetNodes.size() == 1 && "Name must be unique");
62   auto *const Result = ast_matchers::selectFirst<ValueDecl>("v", TargetNodes);
63   assert(Result != nullptr);
64   return Result;
65 }
66 
67 TEST_F(TransferTest, IntVarDecl) {
68   std::string Code = R"(
69     void target() {
70       int Foo;
71       // [[p]]
72     }
73   )";
74   runDataflow(
75       Code, [](llvm::ArrayRef<
76                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
77                    Results,
78                ASTContext &ASTCtx) {
79         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
80         const Environment &Env = Results[0].second.Env;
81 
82         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
83         ASSERT_THAT(FooDecl, NotNull());
84 
85         const StorageLocation *FooLoc =
86             Env.getStorageLocation(*FooDecl, SkipPast::None);
87         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
88 
89         const Value *FooVal = Env.getValue(*FooLoc);
90         EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
91       });
92 }
93 
94 TEST_F(TransferTest, StructVarDecl) {
95   std::string Code = R"(
96     struct A {
97       int Bar;
98     };
99 
100     void target() {
101       A Foo;
102       // [[p]]
103     }
104   )";
105   runDataflow(
106       Code, [](llvm::ArrayRef<
107                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
108                    Results,
109                ASTContext &ASTCtx) {
110         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
111         const Environment &Env = Results[0].second.Env;
112 
113         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
114         ASSERT_THAT(FooDecl, NotNull());
115 
116         ASSERT_TRUE(FooDecl->getType()->isStructureType());
117         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
118 
119         FieldDecl *BarDecl = nullptr;
120         for (FieldDecl *Field : FooFields) {
121           if (Field->getNameAsString() == "Bar") {
122             BarDecl = Field;
123           } else {
124             FAIL() << "Unexpected field: " << Field->getNameAsString();
125           }
126         }
127         ASSERT_THAT(BarDecl, NotNull());
128 
129         const auto *FooLoc = cast<AggregateStorageLocation>(
130             Env.getStorageLocation(*FooDecl, SkipPast::None));
131         const auto *BarLoc =
132             cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
133 
134         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
135         const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl));
136         EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
137       });
138 }
139 
140 TEST_F(TransferTest, ClassVarDecl) {
141   std::string Code = R"(
142     class A {
143       int Bar;
144     };
145 
146     void target() {
147       A Foo;
148       // [[p]]
149     }
150   )";
151   runDataflow(
152       Code, [](llvm::ArrayRef<
153                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
154                    Results,
155                ASTContext &ASTCtx) {
156         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
157         const Environment &Env = Results[0].second.Env;
158 
159         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
160         ASSERT_THAT(FooDecl, NotNull());
161 
162         ASSERT_TRUE(FooDecl->getType()->isClassType());
163         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
164 
165         FieldDecl *BarDecl = nullptr;
166         for (FieldDecl *Field : FooFields) {
167           if (Field->getNameAsString() == "Bar") {
168             BarDecl = Field;
169           } else {
170             FAIL() << "Unexpected field: " << Field->getNameAsString();
171           }
172         }
173         ASSERT_THAT(BarDecl, NotNull());
174 
175         const auto *FooLoc = cast<AggregateStorageLocation>(
176             Env.getStorageLocation(*FooDecl, SkipPast::None));
177         const auto *BarLoc =
178             cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
179 
180         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
181         const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl));
182         EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
183       });
184 }
185 
186 TEST_F(TransferTest, ReferenceVarDecl) {
187   std::string Code = R"(
188     struct A {};
189 
190     A &getA();
191 
192     void target() {
193       A &Foo = getA();
194       // [[p]]
195     }
196   )";
197   runDataflow(
198       Code, [](llvm::ArrayRef<
199                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
200                    Results,
201                ASTContext &ASTCtx) {
202         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
203         const Environment &Env = Results[0].second.Env;
204 
205         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
206         ASSERT_THAT(FooDecl, NotNull());
207 
208         const StorageLocation *FooLoc =
209             Env.getStorageLocation(*FooDecl, SkipPast::None);
210         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
211 
212         const ReferenceValue *FooVal =
213             cast<ReferenceValue>(Env.getValue(*FooLoc));
214         const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
215         EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc));
216 
217         const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
218         EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal));
219       });
220 }
221 
222 TEST_F(TransferTest, SelfReferentialReferenceVarDecl) {
223   std::string Code = R"(
224     struct A;
225 
226     struct B {};
227 
228     struct C {
229       A &FooRef;
230       A *FooPtr;
231       B &BazRef;
232       B *BazPtr;
233     };
234 
235     struct A {
236       C &Bar;
237     };
238 
239     A &getA();
240 
241     void target() {
242       A &Foo = getA();
243       // [[p]]
244     }
245   )";
246   runDataflow(Code, [](llvm::ArrayRef<std::pair<
247                            std::string, DataflowAnalysisState<NoopLattice>>>
248                            Results,
249                        ASTContext &ASTCtx) {
250     ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
251     const Environment &Env = Results[0].second.Env;
252 
253     const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
254     ASSERT_THAT(FooDecl, NotNull());
255 
256     ASSERT_TRUE(FooDecl->getType()->isReferenceType());
257     ASSERT_TRUE(FooDecl->getType().getNonReferenceType()->isStructureType());
258     const auto FooFields =
259         FooDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields();
260 
261     FieldDecl *BarDecl = nullptr;
262     for (FieldDecl *Field : FooFields) {
263       if (Field->getNameAsString() == "Bar") {
264         BarDecl = Field;
265       } else {
266         FAIL() << "Unexpected field: " << Field->getNameAsString();
267       }
268     }
269     ASSERT_THAT(BarDecl, NotNull());
270 
271     ASSERT_TRUE(BarDecl->getType()->isReferenceType());
272     ASSERT_TRUE(BarDecl->getType().getNonReferenceType()->isStructureType());
273     const auto BarFields =
274         BarDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields();
275 
276     FieldDecl *FooRefDecl = nullptr;
277     FieldDecl *FooPtrDecl = nullptr;
278     FieldDecl *BazRefDecl = nullptr;
279     FieldDecl *BazPtrDecl = nullptr;
280     for (FieldDecl *Field : BarFields) {
281       if (Field->getNameAsString() == "FooRef") {
282         FooRefDecl = Field;
283       } else if (Field->getNameAsString() == "FooPtr") {
284         FooPtrDecl = Field;
285       } else if (Field->getNameAsString() == "BazRef") {
286         BazRefDecl = Field;
287       } else if (Field->getNameAsString() == "BazPtr") {
288         BazPtrDecl = Field;
289       } else {
290         FAIL() << "Unexpected field: " << Field->getNameAsString();
291       }
292     }
293     ASSERT_THAT(FooRefDecl, NotNull());
294     ASSERT_THAT(FooPtrDecl, NotNull());
295     ASSERT_THAT(BazRefDecl, NotNull());
296     ASSERT_THAT(BazPtrDecl, NotNull());
297 
298     const auto *FooLoc = cast<ScalarStorageLocation>(
299         Env.getStorageLocation(*FooDecl, SkipPast::None));
300     const auto *FooVal = cast<ReferenceValue>(Env.getValue(*FooLoc));
301     const auto *FooPointeeVal =
302         cast<StructValue>(Env.getValue(FooVal->getPointeeLoc()));
303 
304     const auto *BarVal =
305         cast<ReferenceValue>(&FooPointeeVal->getChild(*BarDecl));
306     const auto *BarPointeeVal =
307         cast<StructValue>(Env.getValue(BarVal->getPointeeLoc()));
308 
309     const auto *FooRefVal =
310         cast<ReferenceValue>(&BarPointeeVal->getChild(*FooRefDecl));
311     const StorageLocation &FooRefPointeeLoc = FooRefVal->getPointeeLoc();
312     EXPECT_THAT(Env.getValue(FooRefPointeeLoc), IsNull());
313 
314     const auto *FooPtrVal =
315         cast<PointerValue>(&BarPointeeVal->getChild(*FooPtrDecl));
316     const StorageLocation &FooPtrPointeeLoc = FooPtrVal->getPointeeLoc();
317     EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull());
318 
319     const auto *BazRefVal =
320         cast<ReferenceValue>(&BarPointeeVal->getChild(*BazRefDecl));
321     const StorageLocation &BazRefPointeeLoc = BazRefVal->getPointeeLoc();
322     EXPECT_THAT(Env.getValue(BazRefPointeeLoc), NotNull());
323 
324     const auto *BazPtrVal =
325         cast<PointerValue>(&BarPointeeVal->getChild(*BazPtrDecl));
326     const StorageLocation &BazPtrPointeeLoc = BazPtrVal->getPointeeLoc();
327     EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull());
328   });
329 }
330 
331 TEST_F(TransferTest, PointerVarDecl) {
332   std::string Code = R"(
333     struct A {};
334 
335     A *getA();
336 
337     void target() {
338       A *Foo = getA();
339       // [[p]]
340     }
341   )";
342   runDataflow(
343       Code, [](llvm::ArrayRef<
344                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
345                    Results,
346                ASTContext &ASTCtx) {
347         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
348         const Environment &Env = Results[0].second.Env;
349 
350         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
351         ASSERT_THAT(FooDecl, NotNull());
352 
353         const StorageLocation *FooLoc =
354             Env.getStorageLocation(*FooDecl, SkipPast::None);
355         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
356 
357         const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));
358         const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
359         EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc));
360 
361         const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
362         EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal));
363       });
364 }
365 
366 TEST_F(TransferTest, SelfReferentialPointerVarDecl) {
367   std::string Code = R"(
368     struct A;
369 
370     struct B {};
371 
372     struct C {
373       A &FooRef;
374       A *FooPtr;
375       B &BazRef;
376       B *BazPtr;
377     };
378 
379     struct A {
380       C *Bar;
381     };
382 
383     A *getA();
384 
385     void target() {
386       A *Foo = getA();
387       // [[p]]
388     }
389   )";
390   runDataflow(
391       Code, [](llvm::ArrayRef<
392                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
393                    Results,
394                ASTContext &ASTCtx) {
395         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
396         const Environment &Env = Results[0].second.Env;
397 
398         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
399         ASSERT_THAT(FooDecl, NotNull());
400 
401         ASSERT_TRUE(FooDecl->getType()->isPointerType());
402         ASSERT_TRUE(FooDecl->getType()
403                         ->getAs<PointerType>()
404                         ->getPointeeType()
405                         ->isStructureType());
406         const auto FooFields = FooDecl->getType()
407                                    ->getAs<PointerType>()
408                                    ->getPointeeType()
409                                    ->getAsRecordDecl()
410                                    ->fields();
411 
412         FieldDecl *BarDecl = nullptr;
413         for (FieldDecl *Field : FooFields) {
414           if (Field->getNameAsString() == "Bar") {
415             BarDecl = Field;
416           } else {
417             FAIL() << "Unexpected field: " << Field->getNameAsString();
418           }
419         }
420         ASSERT_THAT(BarDecl, NotNull());
421 
422         ASSERT_TRUE(BarDecl->getType()->isPointerType());
423         ASSERT_TRUE(BarDecl->getType()
424                         ->getAs<PointerType>()
425                         ->getPointeeType()
426                         ->isStructureType());
427         const auto BarFields = BarDecl->getType()
428                                    ->getAs<PointerType>()
429                                    ->getPointeeType()
430                                    ->getAsRecordDecl()
431                                    ->fields();
432 
433         FieldDecl *FooRefDecl = nullptr;
434         FieldDecl *FooPtrDecl = nullptr;
435         FieldDecl *BazRefDecl = nullptr;
436         FieldDecl *BazPtrDecl = nullptr;
437         for (FieldDecl *Field : BarFields) {
438           if (Field->getNameAsString() == "FooRef") {
439             FooRefDecl = Field;
440           } else if (Field->getNameAsString() == "FooPtr") {
441             FooPtrDecl = Field;
442           } else if (Field->getNameAsString() == "BazRef") {
443             BazRefDecl = Field;
444           } else if (Field->getNameAsString() == "BazPtr") {
445             BazPtrDecl = Field;
446           } else {
447             FAIL() << "Unexpected field: " << Field->getNameAsString();
448           }
449         }
450         ASSERT_THAT(FooRefDecl, NotNull());
451         ASSERT_THAT(FooPtrDecl, NotNull());
452         ASSERT_THAT(BazRefDecl, NotNull());
453         ASSERT_THAT(BazPtrDecl, NotNull());
454 
455         const auto *FooLoc = cast<ScalarStorageLocation>(
456             Env.getStorageLocation(*FooDecl, SkipPast::None));
457         const auto *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));
458         const auto *FooPointeeVal =
459             cast<StructValue>(Env.getValue(FooVal->getPointeeLoc()));
460 
461         const auto *BarVal =
462             cast<PointerValue>(&FooPointeeVal->getChild(*BarDecl));
463         const auto *BarPointeeVal =
464             cast<StructValue>(Env.getValue(BarVal->getPointeeLoc()));
465 
466         const auto *FooRefVal =
467             cast<ReferenceValue>(&BarPointeeVal->getChild(*FooRefDecl));
468         const StorageLocation &FooRefPointeeLoc = FooRefVal->getPointeeLoc();
469         EXPECT_THAT(Env.getValue(FooRefPointeeLoc), IsNull());
470 
471         const auto *FooPtrVal =
472             cast<PointerValue>(&BarPointeeVal->getChild(*FooPtrDecl));
473         const StorageLocation &FooPtrPointeeLoc = FooPtrVal->getPointeeLoc();
474         EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull());
475 
476         const auto *BazRefVal =
477             cast<ReferenceValue>(&BarPointeeVal->getChild(*BazRefDecl));
478         const StorageLocation &BazRefPointeeLoc = BazRefVal->getPointeeLoc();
479         EXPECT_THAT(Env.getValue(BazRefPointeeLoc), NotNull());
480 
481         const auto *BazPtrVal =
482             cast<PointerValue>(&BarPointeeVal->getChild(*BazPtrDecl));
483         const StorageLocation &BazPtrPointeeLoc = BazPtrVal->getPointeeLoc();
484         EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull());
485       });
486 }
487 
488 TEST_F(TransferTest, JoinVarDecl) {
489   std::string Code = R"(
490     void target(bool B) {
491       int Foo;
492       // [[p1]]
493       if (B) {
494         int Bar;
495         // [[p2]]
496       } else {
497         int Baz;
498         // [[p3]]
499       }
500       (void)0;
501       // [[p4]]
502     }
503   )";
504   runDataflow(Code, [](llvm::ArrayRef<std::pair<
505                            std::string, DataflowAnalysisState<NoopLattice>>>
506                            Results,
507                        ASTContext &ASTCtx) {
508     ASSERT_THAT(Results, ElementsAre(Pair("p4", _), Pair("p3", _),
509                                      Pair("p2", _), Pair("p1", _)));
510     const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
511     ASSERT_THAT(FooDecl, NotNull());
512 
513     const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
514     ASSERT_THAT(BarDecl, NotNull());
515 
516     const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
517     ASSERT_THAT(BazDecl, NotNull());
518 
519     const Environment &Env1 = Results[3].second.Env;
520     const StorageLocation *FooLoc =
521         Env1.getStorageLocation(*FooDecl, SkipPast::None);
522     EXPECT_THAT(FooLoc, NotNull());
523     EXPECT_THAT(Env1.getStorageLocation(*BarDecl, SkipPast::None), IsNull());
524     EXPECT_THAT(Env1.getStorageLocation(*BazDecl, SkipPast::None), IsNull());
525 
526     const Environment &Env2 = Results[2].second.Env;
527     EXPECT_EQ(Env2.getStorageLocation(*FooDecl, SkipPast::None), FooLoc);
528     EXPECT_THAT(Env2.getStorageLocation(*BarDecl, SkipPast::None), NotNull());
529     EXPECT_THAT(Env2.getStorageLocation(*BazDecl, SkipPast::None), IsNull());
530 
531     const Environment &Env3 = Results[1].second.Env;
532     EXPECT_EQ(Env3.getStorageLocation(*FooDecl, SkipPast::None), FooLoc);
533     EXPECT_THAT(Env3.getStorageLocation(*BarDecl, SkipPast::None), IsNull());
534     EXPECT_THAT(Env3.getStorageLocation(*BazDecl, SkipPast::None), NotNull());
535 
536     const Environment &Env4 = Results[0].second.Env;
537     EXPECT_EQ(Env4.getStorageLocation(*FooDecl, SkipPast::None), FooLoc);
538     EXPECT_THAT(Env4.getStorageLocation(*BarDecl, SkipPast::None), IsNull());
539     EXPECT_THAT(Env4.getStorageLocation(*BazDecl, SkipPast::None), IsNull());
540   });
541 }
542 
543 TEST_F(TransferTest, BinaryOperatorAssign) {
544   std::string Code = R"(
545     void target() {
546       int Foo;
547       int Bar;
548       (Bar) = (Foo);
549       // [[p]]
550     }
551   )";
552   runDataflow(Code,
553               [](llvm::ArrayRef<
554                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
555                      Results,
556                  ASTContext &ASTCtx) {
557                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
558                 const Environment &Env = Results[0].second.Env;
559 
560                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
561                 ASSERT_THAT(FooDecl, NotNull());
562 
563                 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
564                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
565 
566                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
567                 ASSERT_THAT(BarDecl, NotNull());
568 
569                 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal);
570               });
571 }
572 
573 TEST_F(TransferTest, VarDeclInitAssign) {
574   std::string Code = R"(
575     void target() {
576       int Foo;
577       int Bar = Foo;
578       // [[p]]
579     }
580   )";
581   runDataflow(Code,
582               [](llvm::ArrayRef<
583                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
584                      Results,
585                  ASTContext &ASTCtx) {
586                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
587                 const Environment &Env = Results[0].second.Env;
588 
589                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
590                 ASSERT_THAT(FooDecl, NotNull());
591 
592                 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
593                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
594 
595                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
596                 ASSERT_THAT(BarDecl, NotNull());
597 
598                 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal);
599               });
600 }
601 
602 TEST_F(TransferTest, VarDeclInitAssignChained) {
603   std::string Code = R"(
604     void target() {
605       int Foo;
606       int Bar;
607       int Baz = (Bar = Foo);
608       // [[p]]
609     }
610   )";
611   runDataflow(Code,
612               [](llvm::ArrayRef<
613                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
614                      Results,
615                  ASTContext &ASTCtx) {
616                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
617                 const Environment &Env = Results[0].second.Env;
618 
619                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
620                 ASSERT_THAT(FooDecl, NotNull());
621 
622                 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
623                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
624 
625                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
626                 ASSERT_THAT(BarDecl, NotNull());
627 
628                 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
629                 ASSERT_THAT(BazDecl, NotNull());
630 
631                 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal);
632                 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), FooVal);
633               });
634 }
635 
636 TEST_F(TransferTest, VarDeclInitAssignPtrDeref) {
637   std::string Code = R"(
638     void target() {
639       int Foo;
640       int *Bar;
641       *(Bar) = Foo;
642       int Baz = *(Bar);
643       // [[p]]
644     }
645   )";
646   runDataflow(Code,
647               [](llvm::ArrayRef<
648                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
649                      Results,
650                  ASTContext &ASTCtx) {
651                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
652                 const Environment &Env = Results[0].second.Env;
653 
654                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
655                 ASSERT_THAT(FooDecl, NotNull());
656 
657                 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
658                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
659 
660                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
661                 ASSERT_THAT(BarDecl, NotNull());
662 
663                 const auto *BarVal =
664                     cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None));
665                 EXPECT_EQ(Env.getValue(BarVal->getPointeeLoc()), FooVal);
666 
667                 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
668                 ASSERT_THAT(BazDecl, NotNull());
669 
670                 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), FooVal);
671               });
672 }
673 
674 TEST_F(TransferTest, AssignToAndFromReference) {
675   std::string Code = R"(
676     void target() {
677       int Foo;
678       int Bar;
679       int &Baz = Foo;
680       // [[p1]]
681       Baz = Bar;
682       int Qux = Baz;
683       int &Quux = Baz;
684       // [[p2]]
685     }
686   )";
687   runDataflow(
688       Code, [](llvm::ArrayRef<
689                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
690                    Results,
691                ASTContext &ASTCtx) {
692         ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _)));
693         const Environment &Env1 = Results[0].second.Env;
694         const Environment &Env2 = Results[1].second.Env;
695 
696         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
697         ASSERT_THAT(FooDecl, NotNull());
698 
699         const Value *FooVal = Env1.getValue(*FooDecl, SkipPast::None);
700         ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
701 
702         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
703         ASSERT_THAT(BarDecl, NotNull());
704 
705         const Value *BarVal = Env1.getValue(*BarDecl, SkipPast::None);
706         ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
707 
708         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
709         ASSERT_THAT(BazDecl, NotNull());
710 
711         EXPECT_EQ(Env1.getValue(*BazDecl, SkipPast::Reference), FooVal);
712 
713         EXPECT_EQ(Env2.getValue(*BazDecl, SkipPast::Reference), BarVal);
714         EXPECT_EQ(Env2.getValue(*FooDecl, SkipPast::None), BarVal);
715 
716         const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
717         ASSERT_THAT(QuxDecl, NotNull());
718         EXPECT_EQ(Env2.getValue(*QuxDecl, SkipPast::None), BarVal);
719 
720         const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
721         ASSERT_THAT(QuuxDecl, NotNull());
722         EXPECT_EQ(Env2.getValue(*QuuxDecl, SkipPast::Reference), BarVal);
723       });
724 }
725 
726 TEST_F(TransferTest, MultipleParamDecls) {
727   std::string Code = R"(
728     void target(int Foo, int Bar) {
729       (void)0;
730       // [[p]]
731     }
732   )";
733   runDataflow(Code,
734               [](llvm::ArrayRef<
735                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
736                      Results,
737                  ASTContext &ASTCtx) {
738                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
739                 const Environment &Env = Results[0].second.Env;
740 
741                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
742                 ASSERT_THAT(FooDecl, NotNull());
743 
744                 const StorageLocation *FooLoc =
745                     Env.getStorageLocation(*FooDecl, SkipPast::None);
746                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
747 
748                 const Value *FooVal = Env.getValue(*FooLoc);
749                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
750 
751                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
752                 ASSERT_THAT(BarDecl, NotNull());
753 
754                 const StorageLocation *BarLoc =
755                     Env.getStorageLocation(*BarDecl, SkipPast::None);
756                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
757 
758                 const Value *BarVal = Env.getValue(*BarLoc);
759                 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
760               });
761 }
762 
763 TEST_F(TransferTest, StructParamDecl) {
764   std::string Code = R"(
765     struct A {
766       int Bar;
767     };
768 
769     void target(A Foo) {
770       (void)0;
771       // [[p]]
772     }
773   )";
774   runDataflow(
775       Code, [](llvm::ArrayRef<
776                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
777                    Results,
778                ASTContext &ASTCtx) {
779         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
780         const Environment &Env = Results[0].second.Env;
781 
782         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
783         ASSERT_THAT(FooDecl, NotNull());
784 
785         ASSERT_TRUE(FooDecl->getType()->isStructureType());
786         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
787 
788         FieldDecl *BarDecl = nullptr;
789         for (FieldDecl *Field : FooFields) {
790           if (Field->getNameAsString() == "Bar") {
791             BarDecl = Field;
792           } else {
793             FAIL() << "Unexpected field: " << Field->getNameAsString();
794           }
795         }
796         ASSERT_THAT(BarDecl, NotNull());
797 
798         const auto *FooLoc = cast<AggregateStorageLocation>(
799             Env.getStorageLocation(*FooDecl, SkipPast::None));
800         const auto *BarLoc =
801             cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
802 
803         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
804         const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl));
805         EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
806       });
807 }
808 
809 TEST_F(TransferTest, ReferenceParamDecl) {
810   std::string Code = R"(
811     struct A {};
812 
813     void target(A &Foo) {
814       (void)0;
815       // [[p]]
816     }
817   )";
818   runDataflow(Code,
819               [](llvm::ArrayRef<
820                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
821                      Results,
822                  ASTContext &ASTCtx) {
823                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
824                 const Environment &Env = Results[0].second.Env;
825 
826                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
827                 ASSERT_THAT(FooDecl, NotNull());
828 
829                 const StorageLocation *FooLoc =
830                     Env.getStorageLocation(*FooDecl, SkipPast::None);
831                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
832 
833                 const ReferenceValue *FooVal =
834                     dyn_cast<ReferenceValue>(Env.getValue(*FooLoc));
835                 ASSERT_THAT(FooVal, NotNull());
836 
837                 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
838                 EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc));
839 
840                 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
841                 EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal));
842               });
843 }
844 
845 TEST_F(TransferTest, PointerParamDecl) {
846   std::string Code = R"(
847     struct A {};
848 
849     void target(A *Foo) {
850       (void)0;
851       // [[p]]
852     }
853   )";
854   runDataflow(
855       Code, [](llvm::ArrayRef<
856                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
857                    Results,
858                ASTContext &ASTCtx) {
859         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
860         const Environment &Env = Results[0].second.Env;
861 
862         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
863         ASSERT_THAT(FooDecl, NotNull());
864 
865         const StorageLocation *FooLoc =
866             Env.getStorageLocation(*FooDecl, SkipPast::None);
867         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
868 
869         const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));
870         const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
871         EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc));
872 
873         const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
874         EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal));
875       });
876 }
877 
878 TEST_F(TransferTest, StructMember) {
879   std::string Code = R"(
880     struct A {
881       int Bar;
882     };
883 
884     void target(A Foo) {
885       int Baz = Foo.Bar;
886       // [[p]]
887     }
888   )";
889   runDataflow(
890       Code, [](llvm::ArrayRef<
891                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
892                    Results,
893                ASTContext &ASTCtx) {
894         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
895         const Environment &Env = Results[0].second.Env;
896 
897         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
898         ASSERT_THAT(FooDecl, NotNull());
899 
900         ASSERT_TRUE(FooDecl->getType()->isStructureType());
901         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
902 
903         FieldDecl *BarDecl = nullptr;
904         for (FieldDecl *Field : FooFields) {
905           if (Field->getNameAsString() == "Bar") {
906             BarDecl = Field;
907           } else {
908             FAIL() << "Unexpected field: " << Field->getNameAsString();
909           }
910         }
911         ASSERT_THAT(BarDecl, NotNull());
912 
913         const auto *FooLoc = cast<AggregateStorageLocation>(
914             Env.getStorageLocation(*FooDecl, SkipPast::None));
915         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
916         const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl));
917 
918         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
919         ASSERT_THAT(BazDecl, NotNull());
920 
921         EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarVal);
922       });
923 }
924 
925 TEST_F(TransferTest, ClassMember) {
926   std::string Code = R"(
927     class A {
928     public:
929       int Bar;
930     };
931 
932     void target(A Foo) {
933       int Baz = Foo.Bar;
934       // [[p]]
935     }
936   )";
937   runDataflow(
938       Code, [](llvm::ArrayRef<
939                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
940                    Results,
941                ASTContext &ASTCtx) {
942         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
943         const Environment &Env = Results[0].second.Env;
944 
945         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
946         ASSERT_THAT(FooDecl, NotNull());
947 
948         ASSERT_TRUE(FooDecl->getType()->isClassType());
949         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
950 
951         FieldDecl *BarDecl = nullptr;
952         for (FieldDecl *Field : FooFields) {
953           if (Field->getNameAsString() == "Bar") {
954             BarDecl = Field;
955           } else {
956             FAIL() << "Unexpected field: " << Field->getNameAsString();
957           }
958         }
959         ASSERT_THAT(BarDecl, NotNull());
960 
961         const auto *FooLoc = cast<AggregateStorageLocation>(
962             Env.getStorageLocation(*FooDecl, SkipPast::None));
963         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
964         const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl));
965 
966         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
967         ASSERT_THAT(BazDecl, NotNull());
968 
969         EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarVal);
970       });
971 }
972 
973 TEST_F(TransferTest, ReferenceMember) {
974   std::string Code = R"(
975     struct A {
976       int &Bar;
977     };
978 
979     void target(A Foo) {
980       int Baz = Foo.Bar;
981       // [[p]]
982     }
983   )";
984   runDataflow(
985       Code, [](llvm::ArrayRef<
986                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
987                    Results,
988                ASTContext &ASTCtx) {
989         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
990         const Environment &Env = Results[0].second.Env;
991 
992         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
993         ASSERT_THAT(FooDecl, NotNull());
994 
995         ASSERT_TRUE(FooDecl->getType()->isStructureType());
996         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
997 
998         FieldDecl *BarDecl = nullptr;
999         for (FieldDecl *Field : FooFields) {
1000           if (Field->getNameAsString() == "Bar") {
1001             BarDecl = Field;
1002           } else {
1003             FAIL() << "Unexpected field: " << Field->getNameAsString();
1004           }
1005         }
1006         ASSERT_THAT(BarDecl, NotNull());
1007 
1008         const auto *FooLoc = cast<AggregateStorageLocation>(
1009             Env.getStorageLocation(*FooDecl, SkipPast::None));
1010         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1011         const auto *BarVal = cast<ReferenceValue>(&FooVal->getChild(*BarDecl));
1012         const auto *BarPointeeVal =
1013             cast<IntegerValue>(Env.getValue(BarVal->getPointeeLoc()));
1014 
1015         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1016         ASSERT_THAT(BazDecl, NotNull());
1017 
1018         EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarPointeeVal);
1019       });
1020 }
1021 
1022 TEST_F(TransferTest, StructThisMember) {
1023   std::string Code = R"(
1024     struct A {
1025       int Bar;
1026 
1027       struct B {
1028         int Baz;
1029       };
1030 
1031       B Qux;
1032 
1033       void target() {
1034         int Foo = Bar;
1035         int Quux = Qux.Baz;
1036         // [[p]]
1037       }
1038     };
1039   )";
1040   runDataflow(
1041       Code, [](llvm::ArrayRef<
1042                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1043                    Results,
1044                ASTContext &ASTCtx) {
1045         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1046         const Environment &Env = Results[0].second.Env;
1047 
1048         const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1049             Env.getThisPointeeStorageLocation());
1050         ASSERT_THAT(ThisLoc, NotNull());
1051 
1052         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1053         ASSERT_THAT(BarDecl, NotNull());
1054 
1055         const auto *BarLoc =
1056             cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl));
1057         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1058 
1059         const Value *BarVal = Env.getValue(*BarLoc);
1060         ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1061 
1062         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1063         ASSERT_THAT(FooDecl, NotNull());
1064         EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal);
1065 
1066         const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1067         ASSERT_THAT(QuxDecl, NotNull());
1068 
1069         ASSERT_TRUE(QuxDecl->getType()->isStructureType());
1070         auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields();
1071 
1072         FieldDecl *BazDecl = nullptr;
1073         for (FieldDecl *Field : QuxFields) {
1074           if (Field->getNameAsString() == "Baz") {
1075             BazDecl = Field;
1076           } else {
1077             FAIL() << "Unexpected field: " << Field->getNameAsString();
1078           }
1079         }
1080         ASSERT_THAT(BazDecl, NotNull());
1081 
1082         const auto *QuxLoc =
1083             cast<AggregateStorageLocation>(&ThisLoc->getChild(*QuxDecl));
1084         const auto *QuxVal = dyn_cast<StructValue>(Env.getValue(*QuxLoc));
1085         ASSERT_THAT(QuxVal, NotNull());
1086 
1087         const auto *BazLoc =
1088             cast<ScalarStorageLocation>(&QuxLoc->getChild(*BazDecl));
1089         const auto *BazVal = cast<IntegerValue>(&QuxVal->getChild(*BazDecl));
1090         EXPECT_EQ(Env.getValue(*BazLoc), BazVal);
1091 
1092         const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
1093         ASSERT_THAT(QuuxDecl, NotNull());
1094         EXPECT_EQ(Env.getValue(*QuuxDecl, SkipPast::None), BazVal);
1095       });
1096 }
1097 
1098 TEST_F(TransferTest, ClassThisMember) {
1099   std::string Code = R"(
1100     class A {
1101       int Bar;
1102 
1103       class B {
1104       public:
1105         int Baz;
1106       };
1107 
1108       B Qux;
1109 
1110       void target() {
1111         int Foo = Bar;
1112         int Quux = Qux.Baz;
1113         // [[p]]
1114       }
1115     };
1116   )";
1117   runDataflow(
1118       Code, [](llvm::ArrayRef<
1119                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1120                    Results,
1121                ASTContext &ASTCtx) {
1122         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1123         const Environment &Env = Results[0].second.Env;
1124 
1125         const auto *ThisLoc =
1126             cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation());
1127 
1128         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1129         ASSERT_THAT(BarDecl, NotNull());
1130 
1131         const auto *BarLoc =
1132             cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl));
1133         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1134 
1135         const Value *BarVal = Env.getValue(*BarLoc);
1136         ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1137 
1138         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1139         ASSERT_THAT(FooDecl, NotNull());
1140         EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal);
1141 
1142         const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1143         ASSERT_THAT(QuxDecl, NotNull());
1144 
1145         ASSERT_TRUE(QuxDecl->getType()->isClassType());
1146         auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields();
1147 
1148         FieldDecl *BazDecl = nullptr;
1149         for (FieldDecl *Field : QuxFields) {
1150           if (Field->getNameAsString() == "Baz") {
1151             BazDecl = Field;
1152           } else {
1153             FAIL() << "Unexpected field: " << Field->getNameAsString();
1154           }
1155         }
1156         ASSERT_THAT(BazDecl, NotNull());
1157 
1158         const auto *QuxLoc =
1159             cast<AggregateStorageLocation>(&ThisLoc->getChild(*QuxDecl));
1160         const auto *QuxVal = dyn_cast<StructValue>(Env.getValue(*QuxLoc));
1161         ASSERT_THAT(QuxVal, NotNull());
1162 
1163         const auto *BazLoc =
1164             cast<ScalarStorageLocation>(&QuxLoc->getChild(*BazDecl));
1165         const auto *BazVal = cast<IntegerValue>(&QuxVal->getChild(*BazDecl));
1166         EXPECT_EQ(Env.getValue(*BazLoc), BazVal);
1167 
1168         const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
1169         ASSERT_THAT(QuuxDecl, NotNull());
1170         EXPECT_EQ(Env.getValue(*QuuxDecl, SkipPast::None), BazVal);
1171       });
1172 }
1173 
1174 TEST_F(TransferTest, ConstructorInitializer) {
1175   std::string Code = R"(
1176     struct target {
1177       int Bar;
1178 
1179       target(int Foo) : Bar(Foo) {
1180         int Qux = Bar;
1181         // [[p]]
1182       }
1183     };
1184   )";
1185   runDataflow(Code,
1186               [](llvm::ArrayRef<
1187                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1188                      Results,
1189                  ASTContext &ASTCtx) {
1190                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1191                 const Environment &Env = Results[0].second.Env;
1192 
1193                 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1194                     Env.getThisPointeeStorageLocation());
1195                 ASSERT_THAT(ThisLoc, NotNull());
1196 
1197                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1198                 ASSERT_THAT(FooDecl, NotNull());
1199 
1200                 const auto *FooVal =
1201                     cast<IntegerValue>(Env.getValue(*FooDecl, SkipPast::None));
1202 
1203                 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1204                 ASSERT_THAT(QuxDecl, NotNull());
1205                 EXPECT_EQ(Env.getValue(*QuxDecl, SkipPast::None), FooVal);
1206               });
1207 }
1208 
1209 TEST_F(TransferTest, DefaultInitializer) {
1210   std::string Code = R"(
1211     struct target {
1212       int Bar;
1213       int Baz = Bar;
1214 
1215       target(int Foo) : Bar(Foo) {
1216         int Qux = Baz;
1217         // [[p]]
1218       }
1219     };
1220   )";
1221   runDataflow(Code,
1222               [](llvm::ArrayRef<
1223                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1224                      Results,
1225                  ASTContext &ASTCtx) {
1226                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1227                 const Environment &Env = Results[0].second.Env;
1228 
1229                 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1230                     Env.getThisPointeeStorageLocation());
1231                 ASSERT_THAT(ThisLoc, NotNull());
1232 
1233                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1234                 ASSERT_THAT(FooDecl, NotNull());
1235 
1236                 const auto *FooVal =
1237                     cast<IntegerValue>(Env.getValue(*FooDecl, SkipPast::None));
1238 
1239                 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1240                 ASSERT_THAT(QuxDecl, NotNull());
1241                 EXPECT_EQ(Env.getValue(*QuxDecl, SkipPast::None), FooVal);
1242               });
1243 }
1244 
1245 TEST_F(TransferTest, DefaultInitializerReference) {
1246   std::string Code = R"(
1247     struct target {
1248       int &Bar;
1249       int &Baz = Bar;
1250 
1251       target(int &Foo) : Bar(Foo) {
1252         int &Qux = Baz;
1253         // [[p]]
1254       }
1255     };
1256   )";
1257   runDataflow(
1258       Code, [](llvm::ArrayRef<
1259                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1260                    Results,
1261                ASTContext &ASTCtx) {
1262         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1263         const Environment &Env = Results[0].second.Env;
1264 
1265         const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1266             Env.getThisPointeeStorageLocation());
1267         ASSERT_THAT(ThisLoc, NotNull());
1268 
1269         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1270         ASSERT_THAT(FooDecl, NotNull());
1271 
1272         const auto *FooVal =
1273             cast<ReferenceValue>(Env.getValue(*FooDecl, SkipPast::None));
1274 
1275         const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1276         ASSERT_THAT(QuxDecl, NotNull());
1277 
1278         const auto *QuxVal =
1279             cast<ReferenceValue>(Env.getValue(*QuxDecl, SkipPast::None));
1280         EXPECT_EQ(&QuxVal->getPointeeLoc(), &FooVal->getPointeeLoc());
1281       });
1282 }
1283 
1284 } // namespace
1285