xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp (revision a0262043bb87fdef68c817722de320a5dd9eb9c9)
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 "clang/Basic/LangStandard.h"
19 #include "llvm/ADT/ArrayRef.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/Support/Casting.h"
22 #include "llvm/Testing/Support/Error.h"
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include <cassert>
26 #include <string>
27 #include <utility>
28 
29 namespace {
30 
31 using namespace clang;
32 using namespace dataflow;
33 using ::testing::_;
34 using ::testing::ElementsAre;
35 using ::testing::IsNull;
36 using ::testing::NotNull;
37 using ::testing::Pair;
38 
39 class TransferTest : public ::testing::Test {
40 protected:
41   template <typename Matcher>
42   void runDataflow(llvm::StringRef Code, Matcher Match,
43                    LangStandard::Kind Std = LangStandard::lang_cxx17) {
44     ASSERT_THAT_ERROR(
45         test::checkDataflow<NoopAnalysis>(
46             Code, "target",
47             [](ASTContext &C, Environment &) { return NoopAnalysis(C); },
48             [&Match](
49                 llvm::ArrayRef<
50                     std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
51                     Results,
52                 ASTContext &ASTCtx) { Match(Results, ASTCtx); },
53             {"-fsyntax-only",
54              "-std=" +
55                  std::string(
56                      LangStandard::getLangStandardForKind(Std).getName())}),
57         llvm::Succeeded());
58   }
59 };
60 
61 /// Returns the `ValueDecl` for the given identifier.
62 ///
63 /// Requirements:
64 ///
65 ///  `Name` must be unique in `ASTCtx`.
66 static const ValueDecl *findValueDecl(ASTContext &ASTCtx,
67                                       llvm::StringRef Name) {
68   auto TargetNodes = ast_matchers::match(
69       ast_matchers::valueDecl(ast_matchers::hasName(Name)).bind("v"), ASTCtx);
70   assert(TargetNodes.size() == 1 && "Name must be unique");
71   auto *const Result = ast_matchers::selectFirst<ValueDecl>("v", TargetNodes);
72   assert(Result != nullptr);
73   return Result;
74 }
75 
76 TEST_F(TransferTest, IntVarDecl) {
77   std::string Code = R"(
78     void target() {
79       int Foo;
80       // [[p]]
81     }
82   )";
83   runDataflow(
84       Code, [](llvm::ArrayRef<
85                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
86                    Results,
87                ASTContext &ASTCtx) {
88         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
89         const Environment &Env = Results[0].second.Env;
90 
91         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
92         ASSERT_THAT(FooDecl, NotNull());
93 
94         const StorageLocation *FooLoc =
95             Env.getStorageLocation(*FooDecl, SkipPast::None);
96         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
97 
98         const Value *FooVal = Env.getValue(*FooLoc);
99         EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
100       });
101 }
102 
103 TEST_F(TransferTest, StructVarDecl) {
104   std::string Code = R"(
105     struct A {
106       int Bar;
107     };
108 
109     void target() {
110       A Foo;
111       // [[p]]
112     }
113   )";
114   runDataflow(
115       Code, [](llvm::ArrayRef<
116                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
117                    Results,
118                ASTContext &ASTCtx) {
119         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
120         const Environment &Env = Results[0].second.Env;
121 
122         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
123         ASSERT_THAT(FooDecl, NotNull());
124 
125         ASSERT_TRUE(FooDecl->getType()->isStructureType());
126         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
127 
128         FieldDecl *BarDecl = nullptr;
129         for (FieldDecl *Field : FooFields) {
130           if (Field->getNameAsString() == "Bar") {
131             BarDecl = Field;
132           } else {
133             FAIL() << "Unexpected field: " << Field->getNameAsString();
134           }
135         }
136         ASSERT_THAT(BarDecl, NotNull());
137 
138         const auto *FooLoc = cast<AggregateStorageLocation>(
139             Env.getStorageLocation(*FooDecl, SkipPast::None));
140         const auto *BarLoc =
141             cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
142 
143         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
144         const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl));
145         EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
146       });
147 }
148 
149 TEST_F(TransferTest, ClassVarDecl) {
150   std::string Code = R"(
151     class A {
152       int Bar;
153     };
154 
155     void target() {
156       A Foo;
157       // [[p]]
158     }
159   )";
160   runDataflow(
161       Code, [](llvm::ArrayRef<
162                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
163                    Results,
164                ASTContext &ASTCtx) {
165         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
166         const Environment &Env = Results[0].second.Env;
167 
168         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
169         ASSERT_THAT(FooDecl, NotNull());
170 
171         ASSERT_TRUE(FooDecl->getType()->isClassType());
172         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
173 
174         FieldDecl *BarDecl = nullptr;
175         for (FieldDecl *Field : FooFields) {
176           if (Field->getNameAsString() == "Bar") {
177             BarDecl = Field;
178           } else {
179             FAIL() << "Unexpected field: " << Field->getNameAsString();
180           }
181         }
182         ASSERT_THAT(BarDecl, NotNull());
183 
184         const auto *FooLoc = cast<AggregateStorageLocation>(
185             Env.getStorageLocation(*FooDecl, SkipPast::None));
186         const auto *BarLoc =
187             cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
188 
189         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
190         const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl));
191         EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
192       });
193 }
194 
195 TEST_F(TransferTest, ReferenceVarDecl) {
196   std::string Code = R"(
197     struct A {};
198 
199     A &getA();
200 
201     void target() {
202       A &Foo = getA();
203       // [[p]]
204     }
205   )";
206   runDataflow(
207       Code, [](llvm::ArrayRef<
208                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
209                    Results,
210                ASTContext &ASTCtx) {
211         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
212         const Environment &Env = Results[0].second.Env;
213 
214         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
215         ASSERT_THAT(FooDecl, NotNull());
216 
217         const StorageLocation *FooLoc =
218             Env.getStorageLocation(*FooDecl, SkipPast::None);
219         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
220 
221         const ReferenceValue *FooVal =
222             cast<ReferenceValue>(Env.getValue(*FooLoc));
223         const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
224         EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc));
225 
226         const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
227         EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal));
228       });
229 }
230 
231 TEST_F(TransferTest, SelfReferentialReferenceVarDecl) {
232   std::string Code = R"(
233     struct A;
234 
235     struct B {};
236 
237     struct C {
238       A &FooRef;
239       A *FooPtr;
240       B &BazRef;
241       B *BazPtr;
242     };
243 
244     struct A {
245       C &Bar;
246     };
247 
248     A &getA();
249 
250     void target() {
251       A &Foo = getA();
252       // [[p]]
253     }
254   )";
255   runDataflow(Code, [](llvm::ArrayRef<std::pair<
256                            std::string, DataflowAnalysisState<NoopLattice>>>
257                            Results,
258                        ASTContext &ASTCtx) {
259     ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
260     const Environment &Env = Results[0].second.Env;
261 
262     const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
263     ASSERT_THAT(FooDecl, NotNull());
264 
265     ASSERT_TRUE(FooDecl->getType()->isReferenceType());
266     ASSERT_TRUE(FooDecl->getType().getNonReferenceType()->isStructureType());
267     const auto FooFields =
268         FooDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields();
269 
270     FieldDecl *BarDecl = nullptr;
271     for (FieldDecl *Field : FooFields) {
272       if (Field->getNameAsString() == "Bar") {
273         BarDecl = Field;
274       } else {
275         FAIL() << "Unexpected field: " << Field->getNameAsString();
276       }
277     }
278     ASSERT_THAT(BarDecl, NotNull());
279 
280     ASSERT_TRUE(BarDecl->getType()->isReferenceType());
281     ASSERT_TRUE(BarDecl->getType().getNonReferenceType()->isStructureType());
282     const auto BarFields =
283         BarDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields();
284 
285     FieldDecl *FooRefDecl = nullptr;
286     FieldDecl *FooPtrDecl = nullptr;
287     FieldDecl *BazRefDecl = nullptr;
288     FieldDecl *BazPtrDecl = nullptr;
289     for (FieldDecl *Field : BarFields) {
290       if (Field->getNameAsString() == "FooRef") {
291         FooRefDecl = Field;
292       } else if (Field->getNameAsString() == "FooPtr") {
293         FooPtrDecl = Field;
294       } else if (Field->getNameAsString() == "BazRef") {
295         BazRefDecl = Field;
296       } else if (Field->getNameAsString() == "BazPtr") {
297         BazPtrDecl = Field;
298       } else {
299         FAIL() << "Unexpected field: " << Field->getNameAsString();
300       }
301     }
302     ASSERT_THAT(FooRefDecl, NotNull());
303     ASSERT_THAT(FooPtrDecl, NotNull());
304     ASSERT_THAT(BazRefDecl, NotNull());
305     ASSERT_THAT(BazPtrDecl, NotNull());
306 
307     const auto *FooLoc = cast<ScalarStorageLocation>(
308         Env.getStorageLocation(*FooDecl, SkipPast::None));
309     const auto *FooVal = cast<ReferenceValue>(Env.getValue(*FooLoc));
310     const auto *FooPointeeVal =
311         cast<StructValue>(Env.getValue(FooVal->getPointeeLoc()));
312 
313     const auto *BarVal =
314         cast<ReferenceValue>(&FooPointeeVal->getChild(*BarDecl));
315     const auto *BarPointeeVal =
316         cast<StructValue>(Env.getValue(BarVal->getPointeeLoc()));
317 
318     const auto *FooRefVal =
319         cast<ReferenceValue>(&BarPointeeVal->getChild(*FooRefDecl));
320     const StorageLocation &FooRefPointeeLoc = FooRefVal->getPointeeLoc();
321     EXPECT_THAT(Env.getValue(FooRefPointeeLoc), IsNull());
322 
323     const auto *FooPtrVal =
324         cast<PointerValue>(&BarPointeeVal->getChild(*FooPtrDecl));
325     const StorageLocation &FooPtrPointeeLoc = FooPtrVal->getPointeeLoc();
326     EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull());
327 
328     const auto *BazRefVal =
329         cast<ReferenceValue>(&BarPointeeVal->getChild(*BazRefDecl));
330     const StorageLocation &BazRefPointeeLoc = BazRefVal->getPointeeLoc();
331     EXPECT_THAT(Env.getValue(BazRefPointeeLoc), NotNull());
332 
333     const auto *BazPtrVal =
334         cast<PointerValue>(&BarPointeeVal->getChild(*BazPtrDecl));
335     const StorageLocation &BazPtrPointeeLoc = BazPtrVal->getPointeeLoc();
336     EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull());
337   });
338 }
339 
340 TEST_F(TransferTest, PointerVarDecl) {
341   std::string Code = R"(
342     struct A {};
343 
344     A *getA();
345 
346     void target() {
347       A *Foo = getA();
348       // [[p]]
349     }
350   )";
351   runDataflow(
352       Code, [](llvm::ArrayRef<
353                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
354                    Results,
355                ASTContext &ASTCtx) {
356         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
357         const Environment &Env = Results[0].second.Env;
358 
359         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
360         ASSERT_THAT(FooDecl, NotNull());
361 
362         const StorageLocation *FooLoc =
363             Env.getStorageLocation(*FooDecl, SkipPast::None);
364         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
365 
366         const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));
367         const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
368         EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc));
369 
370         const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
371         EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal));
372       });
373 }
374 
375 TEST_F(TransferTest, SelfReferentialPointerVarDecl) {
376   std::string Code = R"(
377     struct A;
378 
379     struct B {};
380 
381     struct C {
382       A &FooRef;
383       A *FooPtr;
384       B &BazRef;
385       B *BazPtr;
386     };
387 
388     struct A {
389       C *Bar;
390     };
391 
392     A *getA();
393 
394     void target() {
395       A *Foo = getA();
396       // [[p]]
397     }
398   )";
399   runDataflow(
400       Code, [](llvm::ArrayRef<
401                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
402                    Results,
403                ASTContext &ASTCtx) {
404         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
405         const Environment &Env = Results[0].second.Env;
406 
407         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
408         ASSERT_THAT(FooDecl, NotNull());
409 
410         ASSERT_TRUE(FooDecl->getType()->isPointerType());
411         ASSERT_TRUE(FooDecl->getType()
412                         ->getAs<PointerType>()
413                         ->getPointeeType()
414                         ->isStructureType());
415         const auto FooFields = FooDecl->getType()
416                                    ->getAs<PointerType>()
417                                    ->getPointeeType()
418                                    ->getAsRecordDecl()
419                                    ->fields();
420 
421         FieldDecl *BarDecl = nullptr;
422         for (FieldDecl *Field : FooFields) {
423           if (Field->getNameAsString() == "Bar") {
424             BarDecl = Field;
425           } else {
426             FAIL() << "Unexpected field: " << Field->getNameAsString();
427           }
428         }
429         ASSERT_THAT(BarDecl, NotNull());
430 
431         ASSERT_TRUE(BarDecl->getType()->isPointerType());
432         ASSERT_TRUE(BarDecl->getType()
433                         ->getAs<PointerType>()
434                         ->getPointeeType()
435                         ->isStructureType());
436         const auto BarFields = BarDecl->getType()
437                                    ->getAs<PointerType>()
438                                    ->getPointeeType()
439                                    ->getAsRecordDecl()
440                                    ->fields();
441 
442         FieldDecl *FooRefDecl = nullptr;
443         FieldDecl *FooPtrDecl = nullptr;
444         FieldDecl *BazRefDecl = nullptr;
445         FieldDecl *BazPtrDecl = nullptr;
446         for (FieldDecl *Field : BarFields) {
447           if (Field->getNameAsString() == "FooRef") {
448             FooRefDecl = Field;
449           } else if (Field->getNameAsString() == "FooPtr") {
450             FooPtrDecl = Field;
451           } else if (Field->getNameAsString() == "BazRef") {
452             BazRefDecl = Field;
453           } else if (Field->getNameAsString() == "BazPtr") {
454             BazPtrDecl = Field;
455           } else {
456             FAIL() << "Unexpected field: " << Field->getNameAsString();
457           }
458         }
459         ASSERT_THAT(FooRefDecl, NotNull());
460         ASSERT_THAT(FooPtrDecl, NotNull());
461         ASSERT_THAT(BazRefDecl, NotNull());
462         ASSERT_THAT(BazPtrDecl, NotNull());
463 
464         const auto *FooLoc = cast<ScalarStorageLocation>(
465             Env.getStorageLocation(*FooDecl, SkipPast::None));
466         const auto *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));
467         const auto *FooPointeeVal =
468             cast<StructValue>(Env.getValue(FooVal->getPointeeLoc()));
469 
470         const auto *BarVal =
471             cast<PointerValue>(&FooPointeeVal->getChild(*BarDecl));
472         const auto *BarPointeeVal =
473             cast<StructValue>(Env.getValue(BarVal->getPointeeLoc()));
474 
475         const auto *FooRefVal =
476             cast<ReferenceValue>(&BarPointeeVal->getChild(*FooRefDecl));
477         const StorageLocation &FooRefPointeeLoc = FooRefVal->getPointeeLoc();
478         EXPECT_THAT(Env.getValue(FooRefPointeeLoc), IsNull());
479 
480         const auto *FooPtrVal =
481             cast<PointerValue>(&BarPointeeVal->getChild(*FooPtrDecl));
482         const StorageLocation &FooPtrPointeeLoc = FooPtrVal->getPointeeLoc();
483         EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull());
484 
485         const auto *BazRefVal =
486             cast<ReferenceValue>(&BarPointeeVal->getChild(*BazRefDecl));
487         const StorageLocation &BazRefPointeeLoc = BazRefVal->getPointeeLoc();
488         EXPECT_THAT(Env.getValue(BazRefPointeeLoc), NotNull());
489 
490         const auto *BazPtrVal =
491             cast<PointerValue>(&BarPointeeVal->getChild(*BazPtrDecl));
492         const StorageLocation &BazPtrPointeeLoc = BazPtrVal->getPointeeLoc();
493         EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull());
494       });
495 }
496 
497 TEST_F(TransferTest, MultipleVarsDecl) {
498   std::string Code = R"(
499     void target() {
500       int Foo, Bar;
501       (void)0;
502       // [[p]]
503     }
504   )";
505   runDataflow(Code,
506               [](llvm::ArrayRef<
507                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
508                      Results,
509                  ASTContext &ASTCtx) {
510                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
511                 const Environment &Env = Results[0].second.Env;
512 
513                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
514                 ASSERT_THAT(FooDecl, NotNull());
515 
516                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
517                 ASSERT_THAT(BarDecl, NotNull());
518 
519                 const StorageLocation *FooLoc =
520                     Env.getStorageLocation(*FooDecl, SkipPast::None);
521                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
522 
523                 const StorageLocation *BarLoc =
524                     Env.getStorageLocation(*BarDecl, SkipPast::None);
525                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
526 
527                 const Value *FooVal = Env.getValue(*FooLoc);
528                 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
529 
530                 const Value *BarVal = Env.getValue(*BarLoc);
531                 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
532               });
533 }
534 
535 TEST_F(TransferTest, JoinVarDecl) {
536   std::string Code = R"(
537     void target(bool B) {
538       int Foo;
539       // [[p1]]
540       if (B) {
541         int Bar;
542         // [[p2]]
543       } else {
544         int Baz;
545         // [[p3]]
546       }
547       (void)0;
548       // [[p4]]
549     }
550   )";
551   runDataflow(Code, [](llvm::ArrayRef<std::pair<
552                            std::string, DataflowAnalysisState<NoopLattice>>>
553                            Results,
554                        ASTContext &ASTCtx) {
555     ASSERT_THAT(Results, ElementsAre(Pair("p4", _), Pair("p3", _),
556                                      Pair("p2", _), Pair("p1", _)));
557     const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
558     ASSERT_THAT(FooDecl, NotNull());
559 
560     const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
561     ASSERT_THAT(BarDecl, NotNull());
562 
563     const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
564     ASSERT_THAT(BazDecl, NotNull());
565 
566     const Environment &Env1 = Results[3].second.Env;
567     const StorageLocation *FooLoc =
568         Env1.getStorageLocation(*FooDecl, SkipPast::None);
569     EXPECT_THAT(FooLoc, NotNull());
570     EXPECT_THAT(Env1.getStorageLocation(*BarDecl, SkipPast::None), IsNull());
571     EXPECT_THAT(Env1.getStorageLocation(*BazDecl, SkipPast::None), IsNull());
572 
573     const Environment &Env2 = Results[2].second.Env;
574     EXPECT_EQ(Env2.getStorageLocation(*FooDecl, SkipPast::None), FooLoc);
575     EXPECT_THAT(Env2.getStorageLocation(*BarDecl, SkipPast::None), NotNull());
576     EXPECT_THAT(Env2.getStorageLocation(*BazDecl, SkipPast::None), IsNull());
577 
578     const Environment &Env3 = Results[1].second.Env;
579     EXPECT_EQ(Env3.getStorageLocation(*FooDecl, SkipPast::None), FooLoc);
580     EXPECT_THAT(Env3.getStorageLocation(*BarDecl, SkipPast::None), IsNull());
581     EXPECT_THAT(Env3.getStorageLocation(*BazDecl, SkipPast::None), NotNull());
582 
583     const Environment &Env4 = Results[0].second.Env;
584     EXPECT_EQ(Env4.getStorageLocation(*FooDecl, SkipPast::None), FooLoc);
585     EXPECT_THAT(Env4.getStorageLocation(*BarDecl, SkipPast::None), IsNull());
586     EXPECT_THAT(Env4.getStorageLocation(*BazDecl, SkipPast::None), IsNull());
587   });
588 }
589 
590 TEST_F(TransferTest, BinaryOperatorAssign) {
591   std::string Code = R"(
592     void target() {
593       int Foo;
594       int Bar;
595       (Bar) = (Foo);
596       // [[p]]
597     }
598   )";
599   runDataflow(Code,
600               [](llvm::ArrayRef<
601                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
602                      Results,
603                  ASTContext &ASTCtx) {
604                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
605                 const Environment &Env = Results[0].second.Env;
606 
607                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
608                 ASSERT_THAT(FooDecl, NotNull());
609 
610                 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
611                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
612 
613                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
614                 ASSERT_THAT(BarDecl, NotNull());
615 
616                 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal);
617               });
618 }
619 
620 TEST_F(TransferTest, VarDeclInitAssign) {
621   std::string Code = R"(
622     void target() {
623       int Foo;
624       int Bar = Foo;
625       // [[p]]
626     }
627   )";
628   runDataflow(Code,
629               [](llvm::ArrayRef<
630                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
631                      Results,
632                  ASTContext &ASTCtx) {
633                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
634                 const Environment &Env = Results[0].second.Env;
635 
636                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
637                 ASSERT_THAT(FooDecl, NotNull());
638 
639                 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
640                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
641 
642                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
643                 ASSERT_THAT(BarDecl, NotNull());
644 
645                 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal);
646               });
647 }
648 
649 TEST_F(TransferTest, VarDeclInitAssignChained) {
650   std::string Code = R"(
651     void target() {
652       int Foo;
653       int Bar;
654       int Baz = (Bar = Foo);
655       // [[p]]
656     }
657   )";
658   runDataflow(Code,
659               [](llvm::ArrayRef<
660                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
661                      Results,
662                  ASTContext &ASTCtx) {
663                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
664                 const Environment &Env = Results[0].second.Env;
665 
666                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
667                 ASSERT_THAT(FooDecl, NotNull());
668 
669                 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
670                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
671 
672                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
673                 ASSERT_THAT(BarDecl, NotNull());
674 
675                 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
676                 ASSERT_THAT(BazDecl, NotNull());
677 
678                 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal);
679                 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), FooVal);
680               });
681 }
682 
683 TEST_F(TransferTest, VarDeclInitAssignPtrDeref) {
684   std::string Code = R"(
685     void target() {
686       int Foo;
687       int *Bar;
688       *(Bar) = Foo;
689       int Baz = *(Bar);
690       // [[p]]
691     }
692   )";
693   runDataflow(Code,
694               [](llvm::ArrayRef<
695                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
696                      Results,
697                  ASTContext &ASTCtx) {
698                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
699                 const Environment &Env = Results[0].second.Env;
700 
701                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
702                 ASSERT_THAT(FooDecl, NotNull());
703 
704                 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
705                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
706 
707                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
708                 ASSERT_THAT(BarDecl, NotNull());
709 
710                 const auto *BarVal =
711                     cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None));
712                 EXPECT_EQ(Env.getValue(BarVal->getPointeeLoc()), FooVal);
713 
714                 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
715                 ASSERT_THAT(BazDecl, NotNull());
716 
717                 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), FooVal);
718               });
719 }
720 
721 TEST_F(TransferTest, AssignToAndFromReference) {
722   std::string Code = R"(
723     void target() {
724       int Foo;
725       int Bar;
726       int &Baz = Foo;
727       // [[p1]]
728       Baz = Bar;
729       int Qux = Baz;
730       int &Quux = Baz;
731       // [[p2]]
732     }
733   )";
734   runDataflow(
735       Code, [](llvm::ArrayRef<
736                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
737                    Results,
738                ASTContext &ASTCtx) {
739         ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _)));
740         const Environment &Env1 = Results[0].second.Env;
741         const Environment &Env2 = Results[1].second.Env;
742 
743         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
744         ASSERT_THAT(FooDecl, NotNull());
745 
746         const Value *FooVal = Env1.getValue(*FooDecl, SkipPast::None);
747         ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
748 
749         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
750         ASSERT_THAT(BarDecl, NotNull());
751 
752         const Value *BarVal = Env1.getValue(*BarDecl, SkipPast::None);
753         ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
754 
755         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
756         ASSERT_THAT(BazDecl, NotNull());
757 
758         EXPECT_EQ(Env1.getValue(*BazDecl, SkipPast::Reference), FooVal);
759 
760         EXPECT_EQ(Env2.getValue(*BazDecl, SkipPast::Reference), BarVal);
761         EXPECT_EQ(Env2.getValue(*FooDecl, SkipPast::None), BarVal);
762 
763         const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
764         ASSERT_THAT(QuxDecl, NotNull());
765         EXPECT_EQ(Env2.getValue(*QuxDecl, SkipPast::None), BarVal);
766 
767         const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
768         ASSERT_THAT(QuuxDecl, NotNull());
769         EXPECT_EQ(Env2.getValue(*QuuxDecl, SkipPast::Reference), BarVal);
770       });
771 }
772 
773 TEST_F(TransferTest, MultipleParamDecls) {
774   std::string Code = R"(
775     void target(int Foo, int Bar) {
776       (void)0;
777       // [[p]]
778     }
779   )";
780   runDataflow(Code,
781               [](llvm::ArrayRef<
782                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
783                      Results,
784                  ASTContext &ASTCtx) {
785                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
786                 const Environment &Env = Results[0].second.Env;
787 
788                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
789                 ASSERT_THAT(FooDecl, NotNull());
790 
791                 const StorageLocation *FooLoc =
792                     Env.getStorageLocation(*FooDecl, SkipPast::None);
793                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
794 
795                 const Value *FooVal = Env.getValue(*FooLoc);
796                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
797 
798                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
799                 ASSERT_THAT(BarDecl, NotNull());
800 
801                 const StorageLocation *BarLoc =
802                     Env.getStorageLocation(*BarDecl, SkipPast::None);
803                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
804 
805                 const Value *BarVal = Env.getValue(*BarLoc);
806                 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
807               });
808 }
809 
810 TEST_F(TransferTest, StructParamDecl) {
811   std::string Code = R"(
812     struct A {
813       int Bar;
814     };
815 
816     void target(A Foo) {
817       (void)0;
818       // [[p]]
819     }
820   )";
821   runDataflow(
822       Code, [](llvm::ArrayRef<
823                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
824                    Results,
825                ASTContext &ASTCtx) {
826         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
827         const Environment &Env = Results[0].second.Env;
828 
829         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
830         ASSERT_THAT(FooDecl, NotNull());
831 
832         ASSERT_TRUE(FooDecl->getType()->isStructureType());
833         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
834 
835         FieldDecl *BarDecl = nullptr;
836         for (FieldDecl *Field : FooFields) {
837           if (Field->getNameAsString() == "Bar") {
838             BarDecl = Field;
839           } else {
840             FAIL() << "Unexpected field: " << Field->getNameAsString();
841           }
842         }
843         ASSERT_THAT(BarDecl, NotNull());
844 
845         const auto *FooLoc = cast<AggregateStorageLocation>(
846             Env.getStorageLocation(*FooDecl, SkipPast::None));
847         const auto *BarLoc =
848             cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
849 
850         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
851         const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl));
852         EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
853       });
854 }
855 
856 TEST_F(TransferTest, ReferenceParamDecl) {
857   std::string Code = R"(
858     struct A {};
859 
860     void target(A &Foo) {
861       (void)0;
862       // [[p]]
863     }
864   )";
865   runDataflow(Code,
866               [](llvm::ArrayRef<
867                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
868                      Results,
869                  ASTContext &ASTCtx) {
870                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
871                 const Environment &Env = Results[0].second.Env;
872 
873                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
874                 ASSERT_THAT(FooDecl, NotNull());
875 
876                 const StorageLocation *FooLoc =
877                     Env.getStorageLocation(*FooDecl, SkipPast::None);
878                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
879 
880                 const ReferenceValue *FooVal =
881                     dyn_cast<ReferenceValue>(Env.getValue(*FooLoc));
882                 ASSERT_THAT(FooVal, NotNull());
883 
884                 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
885                 EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc));
886 
887                 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
888                 EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal));
889               });
890 }
891 
892 TEST_F(TransferTest, PointerParamDecl) {
893   std::string Code = R"(
894     struct A {};
895 
896     void target(A *Foo) {
897       (void)0;
898       // [[p]]
899     }
900   )";
901   runDataflow(
902       Code, [](llvm::ArrayRef<
903                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
904                    Results,
905                ASTContext &ASTCtx) {
906         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
907         const Environment &Env = Results[0].second.Env;
908 
909         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
910         ASSERT_THAT(FooDecl, NotNull());
911 
912         const StorageLocation *FooLoc =
913             Env.getStorageLocation(*FooDecl, SkipPast::None);
914         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
915 
916         const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));
917         const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
918         EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc));
919 
920         const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
921         EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal));
922       });
923 }
924 
925 TEST_F(TransferTest, StructMember) {
926   std::string Code = R"(
927     struct A {
928       int Bar;
929     };
930 
931     void target(A Foo) {
932       int Baz = Foo.Bar;
933       // [[p]]
934     }
935   )";
936   runDataflow(
937       Code, [](llvm::ArrayRef<
938                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
939                    Results,
940                ASTContext &ASTCtx) {
941         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
942         const Environment &Env = Results[0].second.Env;
943 
944         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
945         ASSERT_THAT(FooDecl, NotNull());
946 
947         ASSERT_TRUE(FooDecl->getType()->isStructureType());
948         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
949 
950         FieldDecl *BarDecl = nullptr;
951         for (FieldDecl *Field : FooFields) {
952           if (Field->getNameAsString() == "Bar") {
953             BarDecl = Field;
954           } else {
955             FAIL() << "Unexpected field: " << Field->getNameAsString();
956           }
957         }
958         ASSERT_THAT(BarDecl, NotNull());
959 
960         const auto *FooLoc = cast<AggregateStorageLocation>(
961             Env.getStorageLocation(*FooDecl, SkipPast::None));
962         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
963         const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl));
964 
965         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
966         ASSERT_THAT(BazDecl, NotNull());
967 
968         EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarVal);
969       });
970 }
971 
972 TEST_F(TransferTest, ClassMember) {
973   std::string Code = R"(
974     class A {
975     public:
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()->isClassType());
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<IntegerValue>(&FooVal->getChild(*BarDecl));
1012 
1013         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1014         ASSERT_THAT(BazDecl, NotNull());
1015 
1016         EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarVal);
1017       });
1018 }
1019 
1020 TEST_F(TransferTest, ReferenceMember) {
1021   std::string Code = R"(
1022     struct A {
1023       int &Bar;
1024     };
1025 
1026     void target(A Foo) {
1027       int Baz = Foo.Bar;
1028       // [[p]]
1029     }
1030   )";
1031   runDataflow(
1032       Code, [](llvm::ArrayRef<
1033                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1034                    Results,
1035                ASTContext &ASTCtx) {
1036         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1037         const Environment &Env = Results[0].second.Env;
1038 
1039         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1040         ASSERT_THAT(FooDecl, NotNull());
1041 
1042         ASSERT_TRUE(FooDecl->getType()->isStructureType());
1043         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1044 
1045         FieldDecl *BarDecl = nullptr;
1046         for (FieldDecl *Field : FooFields) {
1047           if (Field->getNameAsString() == "Bar") {
1048             BarDecl = Field;
1049           } else {
1050             FAIL() << "Unexpected field: " << Field->getNameAsString();
1051           }
1052         }
1053         ASSERT_THAT(BarDecl, NotNull());
1054 
1055         const auto *FooLoc = cast<AggregateStorageLocation>(
1056             Env.getStorageLocation(*FooDecl, SkipPast::None));
1057         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1058         const auto *BarVal = cast<ReferenceValue>(&FooVal->getChild(*BarDecl));
1059         const auto *BarPointeeVal =
1060             cast<IntegerValue>(Env.getValue(BarVal->getPointeeLoc()));
1061 
1062         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1063         ASSERT_THAT(BazDecl, NotNull());
1064 
1065         EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarPointeeVal);
1066       });
1067 }
1068 
1069 TEST_F(TransferTest, StructThisMember) {
1070   std::string Code = R"(
1071     struct A {
1072       int Bar;
1073 
1074       struct B {
1075         int Baz;
1076       };
1077 
1078       B Qux;
1079 
1080       void target() {
1081         int Foo = Bar;
1082         int Quux = Qux.Baz;
1083         // [[p]]
1084       }
1085     };
1086   )";
1087   runDataflow(
1088       Code, [](llvm::ArrayRef<
1089                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1090                    Results,
1091                ASTContext &ASTCtx) {
1092         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1093         const Environment &Env = Results[0].second.Env;
1094 
1095         const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1096             Env.getThisPointeeStorageLocation());
1097         ASSERT_THAT(ThisLoc, NotNull());
1098 
1099         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1100         ASSERT_THAT(BarDecl, NotNull());
1101 
1102         const auto *BarLoc =
1103             cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl));
1104         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1105 
1106         const Value *BarVal = Env.getValue(*BarLoc);
1107         ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1108 
1109         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1110         ASSERT_THAT(FooDecl, NotNull());
1111         EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal);
1112 
1113         const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1114         ASSERT_THAT(QuxDecl, NotNull());
1115 
1116         ASSERT_TRUE(QuxDecl->getType()->isStructureType());
1117         auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields();
1118 
1119         FieldDecl *BazDecl = nullptr;
1120         for (FieldDecl *Field : QuxFields) {
1121           if (Field->getNameAsString() == "Baz") {
1122             BazDecl = Field;
1123           } else {
1124             FAIL() << "Unexpected field: " << Field->getNameAsString();
1125           }
1126         }
1127         ASSERT_THAT(BazDecl, NotNull());
1128 
1129         const auto *QuxLoc =
1130             cast<AggregateStorageLocation>(&ThisLoc->getChild(*QuxDecl));
1131         const auto *QuxVal = dyn_cast<StructValue>(Env.getValue(*QuxLoc));
1132         ASSERT_THAT(QuxVal, NotNull());
1133 
1134         const auto *BazLoc =
1135             cast<ScalarStorageLocation>(&QuxLoc->getChild(*BazDecl));
1136         const auto *BazVal = cast<IntegerValue>(&QuxVal->getChild(*BazDecl));
1137         EXPECT_EQ(Env.getValue(*BazLoc), BazVal);
1138 
1139         const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
1140         ASSERT_THAT(QuuxDecl, NotNull());
1141         EXPECT_EQ(Env.getValue(*QuuxDecl, SkipPast::None), BazVal);
1142       });
1143 }
1144 
1145 TEST_F(TransferTest, ClassThisMember) {
1146   std::string Code = R"(
1147     class A {
1148       int Bar;
1149 
1150       class B {
1151       public:
1152         int Baz;
1153       };
1154 
1155       B Qux;
1156 
1157       void target() {
1158         int Foo = Bar;
1159         int Quux = Qux.Baz;
1160         // [[p]]
1161       }
1162     };
1163   )";
1164   runDataflow(
1165       Code, [](llvm::ArrayRef<
1166                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1167                    Results,
1168                ASTContext &ASTCtx) {
1169         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1170         const Environment &Env = Results[0].second.Env;
1171 
1172         const auto *ThisLoc =
1173             cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation());
1174 
1175         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1176         ASSERT_THAT(BarDecl, NotNull());
1177 
1178         const auto *BarLoc =
1179             cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl));
1180         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1181 
1182         const Value *BarVal = Env.getValue(*BarLoc);
1183         ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1184 
1185         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1186         ASSERT_THAT(FooDecl, NotNull());
1187         EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal);
1188 
1189         const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1190         ASSERT_THAT(QuxDecl, NotNull());
1191 
1192         ASSERT_TRUE(QuxDecl->getType()->isClassType());
1193         auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields();
1194 
1195         FieldDecl *BazDecl = nullptr;
1196         for (FieldDecl *Field : QuxFields) {
1197           if (Field->getNameAsString() == "Baz") {
1198             BazDecl = Field;
1199           } else {
1200             FAIL() << "Unexpected field: " << Field->getNameAsString();
1201           }
1202         }
1203         ASSERT_THAT(BazDecl, NotNull());
1204 
1205         const auto *QuxLoc =
1206             cast<AggregateStorageLocation>(&ThisLoc->getChild(*QuxDecl));
1207         const auto *QuxVal = dyn_cast<StructValue>(Env.getValue(*QuxLoc));
1208         ASSERT_THAT(QuxVal, NotNull());
1209 
1210         const auto *BazLoc =
1211             cast<ScalarStorageLocation>(&QuxLoc->getChild(*BazDecl));
1212         const auto *BazVal = cast<IntegerValue>(&QuxVal->getChild(*BazDecl));
1213         EXPECT_EQ(Env.getValue(*BazLoc), BazVal);
1214 
1215         const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
1216         ASSERT_THAT(QuuxDecl, NotNull());
1217         EXPECT_EQ(Env.getValue(*QuuxDecl, SkipPast::None), BazVal);
1218       });
1219 }
1220 
1221 TEST_F(TransferTest, ConstructorInitializer) {
1222   std::string Code = R"(
1223     struct target {
1224       int Bar;
1225 
1226       target(int Foo) : Bar(Foo) {
1227         int Qux = Bar;
1228         // [[p]]
1229       }
1230     };
1231   )";
1232   runDataflow(Code,
1233               [](llvm::ArrayRef<
1234                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1235                      Results,
1236                  ASTContext &ASTCtx) {
1237                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1238                 const Environment &Env = Results[0].second.Env;
1239 
1240                 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1241                     Env.getThisPointeeStorageLocation());
1242                 ASSERT_THAT(ThisLoc, NotNull());
1243 
1244                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1245                 ASSERT_THAT(FooDecl, NotNull());
1246 
1247                 const auto *FooVal =
1248                     cast<IntegerValue>(Env.getValue(*FooDecl, SkipPast::None));
1249 
1250                 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1251                 ASSERT_THAT(QuxDecl, NotNull());
1252                 EXPECT_EQ(Env.getValue(*QuxDecl, SkipPast::None), FooVal);
1253               });
1254 }
1255 
1256 TEST_F(TransferTest, DefaultInitializer) {
1257   std::string Code = R"(
1258     struct target {
1259       int Bar;
1260       int Baz = Bar;
1261 
1262       target(int Foo) : Bar(Foo) {
1263         int Qux = Baz;
1264         // [[p]]
1265       }
1266     };
1267   )";
1268   runDataflow(Code,
1269               [](llvm::ArrayRef<
1270                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1271                      Results,
1272                  ASTContext &ASTCtx) {
1273                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1274                 const Environment &Env = Results[0].second.Env;
1275 
1276                 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1277                     Env.getThisPointeeStorageLocation());
1278                 ASSERT_THAT(ThisLoc, NotNull());
1279 
1280                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1281                 ASSERT_THAT(FooDecl, NotNull());
1282 
1283                 const auto *FooVal =
1284                     cast<IntegerValue>(Env.getValue(*FooDecl, SkipPast::None));
1285 
1286                 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1287                 ASSERT_THAT(QuxDecl, NotNull());
1288                 EXPECT_EQ(Env.getValue(*QuxDecl, SkipPast::None), FooVal);
1289               });
1290 }
1291 
1292 TEST_F(TransferTest, DefaultInitializerReference) {
1293   std::string Code = R"(
1294     struct target {
1295       int &Bar;
1296       int &Baz = Bar;
1297 
1298       target(int &Foo) : Bar(Foo) {
1299         int &Qux = Baz;
1300         // [[p]]
1301       }
1302     };
1303   )";
1304   runDataflow(
1305       Code, [](llvm::ArrayRef<
1306                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1307                    Results,
1308                ASTContext &ASTCtx) {
1309         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1310         const Environment &Env = Results[0].second.Env;
1311 
1312         const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1313             Env.getThisPointeeStorageLocation());
1314         ASSERT_THAT(ThisLoc, NotNull());
1315 
1316         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1317         ASSERT_THAT(FooDecl, NotNull());
1318 
1319         const auto *FooVal =
1320             cast<ReferenceValue>(Env.getValue(*FooDecl, SkipPast::None));
1321 
1322         const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1323         ASSERT_THAT(QuxDecl, NotNull());
1324 
1325         const auto *QuxVal =
1326             cast<ReferenceValue>(Env.getValue(*QuxDecl, SkipPast::None));
1327         EXPECT_EQ(&QuxVal->getPointeeLoc(), &FooVal->getPointeeLoc());
1328       });
1329 }
1330 
1331 TEST_F(TransferTest, TemporaryObject) {
1332   std::string Code = R"(
1333     struct A {
1334       int Bar;
1335     };
1336 
1337     void target() {
1338       A Foo = A();
1339       // [[p]]
1340     }
1341   )";
1342   runDataflow(
1343       Code, [](llvm::ArrayRef<
1344                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1345                    Results,
1346                ASTContext &ASTCtx) {
1347         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1348         const Environment &Env = Results[0].second.Env;
1349 
1350         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1351         ASSERT_THAT(FooDecl, NotNull());
1352 
1353         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1354         ASSERT_THAT(BarDecl, NotNull());
1355 
1356         const auto *FooLoc = cast<AggregateStorageLocation>(
1357             Env.getStorageLocation(*FooDecl, SkipPast::None));
1358         const auto *BarLoc =
1359             cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
1360 
1361         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1362         const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl));
1363         EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
1364       });
1365 }
1366 
1367 TEST_F(TransferTest, ElidableConstructor) {
1368   // This test is effectively the same as TransferTest.TemporaryObject, but
1369   // the code is compiled as C++ 14.
1370   std::string Code = R"(
1371     struct A {
1372       int Bar;
1373     };
1374 
1375     void target() {
1376       A Foo = A();
1377       // [[p]]
1378     }
1379   )";
1380   runDataflow(
1381       Code,
1382       [](llvm::ArrayRef<
1383              std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1384              Results,
1385          ASTContext &ASTCtx) {
1386         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1387         const Environment &Env = Results[0].second.Env;
1388 
1389         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1390         ASSERT_THAT(FooDecl, NotNull());
1391 
1392         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1393         ASSERT_THAT(BarDecl, NotNull());
1394 
1395         const auto *FooLoc = cast<AggregateStorageLocation>(
1396             Env.getStorageLocation(*FooDecl, SkipPast::None));
1397         const auto *BarLoc =
1398             cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
1399 
1400         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1401         const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl));
1402         EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
1403       },
1404       LangStandard::lang_cxx14);
1405 }
1406 
1407 TEST_F(TransferTest, AssignmentOperator) {
1408   std::string Code = R"(
1409     struct A {
1410       int Baz;
1411     };
1412 
1413     void target() {
1414       A Foo;
1415       A Bar;
1416       // [[p1]]
1417       Foo = Bar;
1418       // [[p2]]
1419     }
1420   )";
1421   runDataflow(
1422       Code, [](llvm::ArrayRef<
1423                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1424                    Results,
1425                ASTContext &ASTCtx) {
1426         ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _)));
1427         const Environment &Env1 = Results[0].second.Env;
1428         const Environment &Env2 = Results[1].second.Env;
1429 
1430         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1431         ASSERT_THAT(FooDecl, NotNull());
1432 
1433         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1434         ASSERT_THAT(BarDecl, NotNull());
1435 
1436         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1437         ASSERT_THAT(BazDecl, NotNull());
1438 
1439         const auto *FooLoc1 = cast<AggregateStorageLocation>(
1440             Env1.getStorageLocation(*FooDecl, SkipPast::None));
1441         const auto *BarLoc1 = cast<AggregateStorageLocation>(
1442             Env1.getStorageLocation(*BarDecl, SkipPast::None));
1443 
1444         const auto *FooVal1 = cast<StructValue>(Env1.getValue(*FooLoc1));
1445         const auto *BarVal1 = cast<StructValue>(Env1.getValue(*BarLoc1));
1446         EXPECT_NE(FooVal1, BarVal1);
1447 
1448         const auto *FooBazVal1 =
1449             cast<IntegerValue>(Env1.getValue(FooLoc1->getChild(*BazDecl)));
1450         const auto *BarBazVal1 =
1451             cast<IntegerValue>(Env1.getValue(BarLoc1->getChild(*BazDecl)));
1452         EXPECT_NE(FooBazVal1, BarBazVal1);
1453 
1454         const auto *FooLoc2 = cast<AggregateStorageLocation>(
1455             Env2.getStorageLocation(*FooDecl, SkipPast::None));
1456         const auto *BarLoc2 = cast<AggregateStorageLocation>(
1457             Env2.getStorageLocation(*BarDecl, SkipPast::None));
1458 
1459         const auto *FooVal2 = cast<StructValue>(Env2.getValue(*FooLoc2));
1460         const auto *BarVal2 = cast<StructValue>(Env2.getValue(*BarLoc2));
1461         EXPECT_EQ(FooVal2, BarVal2);
1462 
1463         const auto *FooBazVal2 =
1464             cast<IntegerValue>(Env2.getValue(FooLoc1->getChild(*BazDecl)));
1465         const auto *BarBazVal2 =
1466             cast<IntegerValue>(Env2.getValue(BarLoc1->getChild(*BazDecl)));
1467         EXPECT_EQ(FooBazVal2, BarBazVal2);
1468       });
1469 }
1470 
1471 TEST_F(TransferTest, CopyConstructor) {
1472   std::string Code = R"(
1473     struct A {
1474       int Baz;
1475     };
1476 
1477     void target() {
1478       A Foo;
1479       A Bar = Foo;
1480       // [[p]]
1481     }
1482   )";
1483   runDataflow(
1484       Code, [](llvm::ArrayRef<
1485                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1486                    Results,
1487                ASTContext &ASTCtx) {
1488         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1489         const Environment &Env = Results[0].second.Env;
1490 
1491         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1492         ASSERT_THAT(FooDecl, NotNull());
1493 
1494         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1495         ASSERT_THAT(BarDecl, NotNull());
1496 
1497         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1498         ASSERT_THAT(BazDecl, NotNull());
1499 
1500         const auto *FooLoc = cast<AggregateStorageLocation>(
1501             Env.getStorageLocation(*FooDecl, SkipPast::None));
1502         const auto *BarLoc = cast<AggregateStorageLocation>(
1503             Env.getStorageLocation(*BarDecl, SkipPast::None));
1504 
1505         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1506         const auto *BarVal = cast<StructValue>(Env.getValue(*BarLoc));
1507         EXPECT_EQ(FooVal, BarVal);
1508 
1509         const auto *FooBazVal =
1510             cast<IntegerValue>(Env.getValue(FooLoc->getChild(*BazDecl)));
1511         const auto *BarBazVal =
1512             cast<IntegerValue>(Env.getValue(BarLoc->getChild(*BazDecl)));
1513         EXPECT_EQ(FooBazVal, BarBazVal);
1514       });
1515 }
1516 
1517 TEST_F(TransferTest, CopyConstructorWithParens) {
1518   std::string Code = R"(
1519     struct A {
1520       int Baz;
1521     };
1522 
1523     void target() {
1524       A Foo;
1525       A Bar((A(Foo)));
1526       // [[p]]
1527     }
1528   )";
1529   runDataflow(
1530       Code, [](llvm::ArrayRef<
1531                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1532                    Results,
1533                ASTContext &ASTCtx) {
1534         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1535         const Environment &Env = Results[0].second.Env;
1536 
1537         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1538         ASSERT_THAT(FooDecl, NotNull());
1539 
1540         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1541         ASSERT_THAT(BarDecl, NotNull());
1542 
1543         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1544         ASSERT_THAT(BazDecl, NotNull());
1545 
1546         const auto *FooLoc = cast<AggregateStorageLocation>(
1547             Env.getStorageLocation(*FooDecl, SkipPast::None));
1548         const auto *BarLoc = cast<AggregateStorageLocation>(
1549             Env.getStorageLocation(*BarDecl, SkipPast::None));
1550 
1551         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1552         const auto *BarVal = cast<StructValue>(Env.getValue(*BarLoc));
1553         EXPECT_EQ(FooVal, BarVal);
1554 
1555         const auto *FooBazVal =
1556             cast<IntegerValue>(Env.getValue(FooLoc->getChild(*BazDecl)));
1557         const auto *BarBazVal =
1558             cast<IntegerValue>(Env.getValue(BarLoc->getChild(*BazDecl)));
1559         EXPECT_EQ(FooBazVal, BarBazVal);
1560       });
1561 }
1562 
1563 TEST_F(TransferTest, MoveConstructor) {
1564   std::string Code = R"(
1565     namespace std {
1566 
1567     template <typename T> struct remove_reference      { using type = T; };
1568     template <typename T> struct remove_reference<T&>  { using type = T; };
1569     template <typename T> struct remove_reference<T&&> { using type = T; };
1570 
1571     template <typename T>
1572     using remove_reference_t = typename remove_reference<T>::type;
1573 
1574     template <typename T>
1575     std::remove_reference_t<T>&& move(T&& x);
1576 
1577     } // namespace std
1578 
1579     struct A {
1580       int Baz;
1581     };
1582 
1583     void target() {
1584       A Foo;
1585       A Bar;
1586       // [[p1]]
1587       Foo = std::move(Bar);
1588       // [[p2]]
1589     }
1590   )";
1591   runDataflow(
1592       Code, [](llvm::ArrayRef<
1593                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1594                    Results,
1595                ASTContext &ASTCtx) {
1596         ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _)));
1597         const Environment &Env1 = Results[0].second.Env;
1598         const Environment &Env2 = Results[1].second.Env;
1599 
1600         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1601         ASSERT_THAT(FooDecl, NotNull());
1602 
1603         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1604         ASSERT_THAT(BarDecl, NotNull());
1605 
1606         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1607         ASSERT_THAT(BazDecl, NotNull());
1608 
1609         const auto *FooLoc1 = cast<AggregateStorageLocation>(
1610             Env1.getStorageLocation(*FooDecl, SkipPast::None));
1611         const auto *BarLoc1 = cast<AggregateStorageLocation>(
1612             Env1.getStorageLocation(*BarDecl, SkipPast::None));
1613 
1614         const auto *FooVal1 = cast<StructValue>(Env1.getValue(*FooLoc1));
1615         const auto *BarVal1 = cast<StructValue>(Env1.getValue(*BarLoc1));
1616         EXPECT_NE(FooVal1, BarVal1);
1617 
1618         const auto *FooBazVal1 =
1619             cast<IntegerValue>(Env1.getValue(FooLoc1->getChild(*BazDecl)));
1620         const auto *BarBazVal1 =
1621             cast<IntegerValue>(Env1.getValue(BarLoc1->getChild(*BazDecl)));
1622         EXPECT_NE(FooBazVal1, BarBazVal1);
1623 
1624         const auto *FooLoc2 = cast<AggregateStorageLocation>(
1625             Env2.getStorageLocation(*FooDecl, SkipPast::None));
1626         const auto *FooVal2 = cast<StructValue>(Env2.getValue(*FooLoc2));
1627         EXPECT_EQ(FooVal2, BarVal1);
1628 
1629         const auto *FooBazVal2 =
1630             cast<IntegerValue>(Env2.getValue(FooLoc1->getChild(*BazDecl)));
1631         EXPECT_EQ(FooBazVal2, BarBazVal1);
1632       });
1633 }
1634 
1635 TEST_F(TransferTest, BindTemporary) {
1636   std::string Code = R"(
1637     struct A {
1638       virtual ~A() = default;
1639 
1640       int Baz;
1641     };
1642 
1643     void target(A Foo) {
1644       int Bar = A(Foo).Baz;
1645       // [[p]]
1646     }
1647   )";
1648   runDataflow(Code,
1649               [](llvm::ArrayRef<
1650                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1651                      Results,
1652                  ASTContext &ASTCtx) {
1653                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1654                 const Environment &Env = Results[0].second.Env;
1655 
1656                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1657                 ASSERT_THAT(FooDecl, NotNull());
1658 
1659                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1660                 ASSERT_THAT(BarDecl, NotNull());
1661 
1662                 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1663                 ASSERT_THAT(BazDecl, NotNull());
1664 
1665                 const auto &FooVal =
1666                     *cast<StructValue>(Env.getValue(*FooDecl, SkipPast::None));
1667                 const auto *BarVal =
1668                     cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None));
1669                 EXPECT_EQ(BarVal, &FooVal.getChild(*BazDecl));
1670               });
1671 }
1672 
1673 TEST_F(TransferTest, StaticCast) {
1674   std::string Code = R"(
1675     void target(int Foo) {
1676       int Bar = static_cast<int>(Foo);
1677       // [[p]]
1678     }
1679   )";
1680   runDataflow(Code,
1681               [](llvm::ArrayRef<
1682                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1683                      Results,
1684                  ASTContext &ASTCtx) {
1685                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1686                 const Environment &Env = Results[0].second.Env;
1687 
1688                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1689                 ASSERT_THAT(FooDecl, NotNull());
1690 
1691                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1692                 ASSERT_THAT(BarDecl, NotNull());
1693 
1694                 const auto *FooVal =
1695                     cast<IntegerValue>(Env.getValue(*FooDecl, SkipPast::None));
1696                 const auto *BarVal =
1697                     cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None));
1698                 EXPECT_EQ(FooVal, BarVal);
1699               });
1700 }
1701 
1702 TEST_F(TransferTest, AddrOfValue) {
1703   std::string Code = R"(
1704     void target() {
1705       int Foo;
1706       int *Bar = &Foo;
1707       // [[p]]
1708     }
1709   )";
1710   runDataflow(Code,
1711               [](llvm::ArrayRef<
1712                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1713                      Results,
1714                  ASTContext &ASTCtx) {
1715                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1716                 const Environment &Env = Results[0].second.Env;
1717 
1718                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1719                 ASSERT_THAT(FooDecl, NotNull());
1720 
1721                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1722                 ASSERT_THAT(BarDecl, NotNull());
1723 
1724                 const auto *FooLoc = cast<ScalarStorageLocation>(
1725                     Env.getStorageLocation(*FooDecl, SkipPast::None));
1726                 const auto *BarVal =
1727                     cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None));
1728                 EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc);
1729               });
1730 }
1731 
1732 TEST_F(TransferTest, AddrOfReference) {
1733   std::string Code = R"(
1734     void target(int *Foo) {
1735       int *Bar = &(*Foo);
1736       // [[p]]
1737     }
1738   )";
1739   runDataflow(Code,
1740               [](llvm::ArrayRef<
1741                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1742                      Results,
1743                  ASTContext &ASTCtx) {
1744                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1745                 const Environment &Env = Results[0].second.Env;
1746 
1747                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1748                 ASSERT_THAT(FooDecl, NotNull());
1749 
1750                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1751                 ASSERT_THAT(BarDecl, NotNull());
1752 
1753                 const auto *FooVal =
1754                     cast<PointerValue>(Env.getValue(*FooDecl, SkipPast::None));
1755                 const auto *BarVal =
1756                     cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None));
1757                 EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc());
1758               });
1759 }
1760 
1761 } // namespace
1762