xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp (revision ce205cffdfa0f16ce9441ba46fa43e23cecf8be7)
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 "clang/AST/ASTContext.h"
11 #include "clang/AST/Decl.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/ASTMatchers/ASTMatchers.h"
14 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
15 #include "clang/Analysis/FlowSensitive/StorageLocation.h"
16 #include "clang/Analysis/FlowSensitive/TestingSupport.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 <string>
26 #include <utility>
27 
28 namespace {
29 
30 using namespace clang;
31 using namespace dataflow;
32 using namespace test;
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                    bool ApplyBuiltinTransfer = true) {
45     ASSERT_THAT_ERROR(
46         test::checkDataflow<NoopAnalysis>(
47             Code, "target",
48             [ApplyBuiltinTransfer](ASTContext &C, Environment &) {
49               return NoopAnalysis(C, ApplyBuiltinTransfer);
50             },
51             [&Match](
52                 llvm::ArrayRef<
53                     std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
54                     Results,
55                 ASTContext &ASTCtx) { Match(Results, ASTCtx); },
56             {"-fsyntax-only", "-fno-delayed-template-parsing",
57              "-std=" +
58                  std::string(
59                      LangStandard::getLangStandardForKind(Std).getName())}),
60         llvm::Succeeded());
61   }
62 };
63 
64 TEST_F(TransferTest, IntVarDeclNotTrackedWhenTransferDisabled) {
65   std::string Code = R"(
66     void target() {
67       int Foo;
68       // [[p]]
69     }
70   )";
71   runDataflow(
72       Code,
73       [](llvm::ArrayRef<
74              std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
75              Results,
76          ASTContext &ASTCtx) {
77         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
78         const Environment &Env = Results[0].second.Env;
79 
80         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
81         ASSERT_THAT(FooDecl, NotNull());
82 
83         EXPECT_EQ(Env.getStorageLocation(*FooDecl, SkipPast::None), nullptr);
84       },
85       LangStandard::lang_cxx17,
86       /*ApplyBuiltinTransfer=*/false);
87 }
88 
89 TEST_F(TransferTest, BoolVarDecl) {
90   std::string Code = R"(
91     void target() {
92       bool Foo;
93       // [[p]]
94     }
95   )";
96   runDataflow(Code,
97               [](llvm::ArrayRef<
98                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
99                      Results,
100                  ASTContext &ASTCtx) {
101                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
102                 const Environment &Env = Results[0].second.Env;
103 
104                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
105                 ASSERT_THAT(FooDecl, NotNull());
106 
107                 const StorageLocation *FooLoc =
108                     Env.getStorageLocation(*FooDecl, SkipPast::None);
109                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
110 
111                 const Value *FooVal = Env.getValue(*FooLoc);
112                 EXPECT_TRUE(isa_and_nonnull<BoolValue>(FooVal));
113               });
114 }
115 
116 TEST_F(TransferTest, IntVarDecl) {
117   std::string Code = R"(
118     void target() {
119       int Foo;
120       // [[p]]
121     }
122   )";
123   runDataflow(
124       Code, [](llvm::ArrayRef<
125                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
126                    Results,
127                ASTContext &ASTCtx) {
128         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
129         const Environment &Env = Results[0].second.Env;
130 
131         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
132         ASSERT_THAT(FooDecl, NotNull());
133 
134         const StorageLocation *FooLoc =
135             Env.getStorageLocation(*FooDecl, SkipPast::None);
136         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
137 
138         const Value *FooVal = Env.getValue(*FooLoc);
139         EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
140       });
141 }
142 
143 TEST_F(TransferTest, StructVarDecl) {
144   std::string Code = R"(
145     struct A {
146       int Bar;
147     };
148 
149     void target() {
150       A Foo;
151       // [[p]]
152     }
153   )";
154   runDataflow(
155       Code, [](llvm::ArrayRef<
156                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
157                    Results,
158                ASTContext &ASTCtx) {
159         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
160         const Environment &Env = Results[0].second.Env;
161 
162         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
163         ASSERT_THAT(FooDecl, NotNull());
164 
165         ASSERT_TRUE(FooDecl->getType()->isStructureType());
166         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
167 
168         FieldDecl *BarDecl = nullptr;
169         for (FieldDecl *Field : FooFields) {
170           if (Field->getNameAsString() == "Bar") {
171             BarDecl = Field;
172           } else {
173             FAIL() << "Unexpected field: " << Field->getNameAsString();
174           }
175         }
176         ASSERT_THAT(BarDecl, NotNull());
177 
178         const auto *FooLoc = cast<AggregateStorageLocation>(
179             Env.getStorageLocation(*FooDecl, SkipPast::None));
180         const auto *BarLoc =
181             cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
182 
183         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
184         const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl));
185         EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
186       });
187 }
188 
189 TEST_F(TransferTest, ClassVarDecl) {
190   std::string Code = R"(
191     class A {
192       int Bar;
193     };
194 
195     void target() {
196       A Foo;
197       // [[p]]
198     }
199   )";
200   runDataflow(
201       Code, [](llvm::ArrayRef<
202                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
203                    Results,
204                ASTContext &ASTCtx) {
205         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
206         const Environment &Env = Results[0].second.Env;
207 
208         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
209         ASSERT_THAT(FooDecl, NotNull());
210 
211         ASSERT_TRUE(FooDecl->getType()->isClassType());
212         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
213 
214         FieldDecl *BarDecl = nullptr;
215         for (FieldDecl *Field : FooFields) {
216           if (Field->getNameAsString() == "Bar") {
217             BarDecl = Field;
218           } else {
219             FAIL() << "Unexpected field: " << Field->getNameAsString();
220           }
221         }
222         ASSERT_THAT(BarDecl, NotNull());
223 
224         const auto *FooLoc = cast<AggregateStorageLocation>(
225             Env.getStorageLocation(*FooDecl, SkipPast::None));
226         const auto *BarLoc =
227             cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
228 
229         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
230         const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl));
231         EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
232       });
233 }
234 
235 TEST_F(TransferTest, ReferenceVarDecl) {
236   std::string Code = R"(
237     struct A {};
238 
239     A &getA();
240 
241     void target() {
242       A &Foo = getA();
243       // [[p]]
244     }
245   )";
246   runDataflow(
247       Code, [](llvm::ArrayRef<
248                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
249                    Results,
250                ASTContext &ASTCtx) {
251         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
252         const Environment &Env = Results[0].second.Env;
253 
254         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
255         ASSERT_THAT(FooDecl, NotNull());
256 
257         const StorageLocation *FooLoc =
258             Env.getStorageLocation(*FooDecl, SkipPast::None);
259         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
260 
261         const ReferenceValue *FooVal =
262             cast<ReferenceValue>(Env.getValue(*FooLoc));
263         const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
264         EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc));
265 
266         const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
267         EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal));
268       });
269 }
270 
271 TEST_F(TransferTest, SelfReferentialReferenceVarDecl) {
272   std::string Code = R"(
273     struct A;
274 
275     struct B {};
276 
277     struct C {
278       A &FooRef;
279       A *FooPtr;
280       B &BazRef;
281       B *BazPtr;
282     };
283 
284     struct A {
285       C &Bar;
286     };
287 
288     A &getA();
289 
290     void target() {
291       A &Foo = getA();
292       // [[p]]
293     }
294   )";
295   runDataflow(Code, [](llvm::ArrayRef<std::pair<
296                            std::string, DataflowAnalysisState<NoopLattice>>>
297                            Results,
298                        ASTContext &ASTCtx) {
299     ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
300     const Environment &Env = Results[0].second.Env;
301 
302     const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
303     ASSERT_THAT(FooDecl, NotNull());
304 
305     ASSERT_TRUE(FooDecl->getType()->isReferenceType());
306     ASSERT_TRUE(FooDecl->getType().getNonReferenceType()->isStructureType());
307     const auto FooFields =
308         FooDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields();
309 
310     FieldDecl *BarDecl = nullptr;
311     for (FieldDecl *Field : FooFields) {
312       if (Field->getNameAsString() == "Bar") {
313         BarDecl = Field;
314       } else {
315         FAIL() << "Unexpected field: " << Field->getNameAsString();
316       }
317     }
318     ASSERT_THAT(BarDecl, NotNull());
319 
320     ASSERT_TRUE(BarDecl->getType()->isReferenceType());
321     ASSERT_TRUE(BarDecl->getType().getNonReferenceType()->isStructureType());
322     const auto BarFields =
323         BarDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields();
324 
325     FieldDecl *FooRefDecl = nullptr;
326     FieldDecl *FooPtrDecl = nullptr;
327     FieldDecl *BazRefDecl = nullptr;
328     FieldDecl *BazPtrDecl = nullptr;
329     for (FieldDecl *Field : BarFields) {
330       if (Field->getNameAsString() == "FooRef") {
331         FooRefDecl = Field;
332       } else if (Field->getNameAsString() == "FooPtr") {
333         FooPtrDecl = Field;
334       } else if (Field->getNameAsString() == "BazRef") {
335         BazRefDecl = Field;
336       } else if (Field->getNameAsString() == "BazPtr") {
337         BazPtrDecl = Field;
338       } else {
339         FAIL() << "Unexpected field: " << Field->getNameAsString();
340       }
341     }
342     ASSERT_THAT(FooRefDecl, NotNull());
343     ASSERT_THAT(FooPtrDecl, NotNull());
344     ASSERT_THAT(BazRefDecl, NotNull());
345     ASSERT_THAT(BazPtrDecl, NotNull());
346 
347     const auto *FooLoc = cast<ScalarStorageLocation>(
348         Env.getStorageLocation(*FooDecl, SkipPast::None));
349     const auto *FooVal = cast<ReferenceValue>(Env.getValue(*FooLoc));
350     const auto *FooPointeeVal =
351         cast<StructValue>(Env.getValue(FooVal->getPointeeLoc()));
352 
353     const auto *BarVal =
354         cast<ReferenceValue>(FooPointeeVal->getChild(*BarDecl));
355     const auto *BarPointeeVal =
356         cast<StructValue>(Env.getValue(BarVal->getPointeeLoc()));
357 
358     const auto *FooRefVal =
359         cast<ReferenceValue>(BarPointeeVal->getChild(*FooRefDecl));
360     const StorageLocation &FooRefPointeeLoc = FooRefVal->getPointeeLoc();
361     EXPECT_THAT(Env.getValue(FooRefPointeeLoc), IsNull());
362 
363     const auto *FooPtrVal =
364         cast<PointerValue>(BarPointeeVal->getChild(*FooPtrDecl));
365     const StorageLocation &FooPtrPointeeLoc = FooPtrVal->getPointeeLoc();
366     EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull());
367 
368     const auto *BazRefVal =
369         cast<ReferenceValue>(BarPointeeVal->getChild(*BazRefDecl));
370     const StorageLocation &BazRefPointeeLoc = BazRefVal->getPointeeLoc();
371     EXPECT_THAT(Env.getValue(BazRefPointeeLoc), NotNull());
372 
373     const auto *BazPtrVal =
374         cast<PointerValue>(BarPointeeVal->getChild(*BazPtrDecl));
375     const StorageLocation &BazPtrPointeeLoc = BazPtrVal->getPointeeLoc();
376     EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull());
377   });
378 }
379 
380 TEST_F(TransferTest, PointerVarDecl) {
381   std::string Code = R"(
382     struct A {};
383 
384     A *getA();
385 
386     void target() {
387       A *Foo = getA();
388       // [[p]]
389     }
390   )";
391   runDataflow(
392       Code, [](llvm::ArrayRef<
393                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
394                    Results,
395                ASTContext &ASTCtx) {
396         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
397         const Environment &Env = Results[0].second.Env;
398 
399         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
400         ASSERT_THAT(FooDecl, NotNull());
401 
402         const StorageLocation *FooLoc =
403             Env.getStorageLocation(*FooDecl, SkipPast::None);
404         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
405 
406         const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));
407         const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
408         EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc));
409 
410         const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
411         EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal));
412       });
413 }
414 
415 TEST_F(TransferTest, SelfReferentialPointerVarDecl) {
416   std::string Code = R"(
417     struct A;
418 
419     struct B {};
420 
421     struct C {
422       A &FooRef;
423       A *FooPtr;
424       B &BazRef;
425       B *BazPtr;
426     };
427 
428     struct A {
429       C *Bar;
430     };
431 
432     A *getA();
433 
434     void target() {
435       A *Foo = getA();
436       // [[p]]
437     }
438   )";
439   runDataflow(
440       Code, [](llvm::ArrayRef<
441                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
442                    Results,
443                ASTContext &ASTCtx) {
444         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
445         const Environment &Env = Results[0].second.Env;
446 
447         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
448         ASSERT_THAT(FooDecl, NotNull());
449 
450         ASSERT_TRUE(FooDecl->getType()->isPointerType());
451         ASSERT_TRUE(FooDecl->getType()
452                         ->getAs<PointerType>()
453                         ->getPointeeType()
454                         ->isStructureType());
455         const auto FooFields = FooDecl->getType()
456                                    ->getAs<PointerType>()
457                                    ->getPointeeType()
458                                    ->getAsRecordDecl()
459                                    ->fields();
460 
461         FieldDecl *BarDecl = nullptr;
462         for (FieldDecl *Field : FooFields) {
463           if (Field->getNameAsString() == "Bar") {
464             BarDecl = Field;
465           } else {
466             FAIL() << "Unexpected field: " << Field->getNameAsString();
467           }
468         }
469         ASSERT_THAT(BarDecl, NotNull());
470 
471         ASSERT_TRUE(BarDecl->getType()->isPointerType());
472         ASSERT_TRUE(BarDecl->getType()
473                         ->getAs<PointerType>()
474                         ->getPointeeType()
475                         ->isStructureType());
476         const auto BarFields = BarDecl->getType()
477                                    ->getAs<PointerType>()
478                                    ->getPointeeType()
479                                    ->getAsRecordDecl()
480                                    ->fields();
481 
482         FieldDecl *FooRefDecl = nullptr;
483         FieldDecl *FooPtrDecl = nullptr;
484         FieldDecl *BazRefDecl = nullptr;
485         FieldDecl *BazPtrDecl = nullptr;
486         for (FieldDecl *Field : BarFields) {
487           if (Field->getNameAsString() == "FooRef") {
488             FooRefDecl = Field;
489           } else if (Field->getNameAsString() == "FooPtr") {
490             FooPtrDecl = Field;
491           } else if (Field->getNameAsString() == "BazRef") {
492             BazRefDecl = Field;
493           } else if (Field->getNameAsString() == "BazPtr") {
494             BazPtrDecl = Field;
495           } else {
496             FAIL() << "Unexpected field: " << Field->getNameAsString();
497           }
498         }
499         ASSERT_THAT(FooRefDecl, NotNull());
500         ASSERT_THAT(FooPtrDecl, NotNull());
501         ASSERT_THAT(BazRefDecl, NotNull());
502         ASSERT_THAT(BazPtrDecl, NotNull());
503 
504         const auto *FooLoc = cast<ScalarStorageLocation>(
505             Env.getStorageLocation(*FooDecl, SkipPast::None));
506         const auto *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));
507         const auto *FooPointeeVal =
508             cast<StructValue>(Env.getValue(FooVal->getPointeeLoc()));
509 
510         const auto *BarVal =
511             cast<PointerValue>(FooPointeeVal->getChild(*BarDecl));
512         const auto *BarPointeeVal =
513             cast<StructValue>(Env.getValue(BarVal->getPointeeLoc()));
514 
515         const auto *FooRefVal =
516             cast<ReferenceValue>(BarPointeeVal->getChild(*FooRefDecl));
517         const StorageLocation &FooRefPointeeLoc = FooRefVal->getPointeeLoc();
518         EXPECT_THAT(Env.getValue(FooRefPointeeLoc), IsNull());
519 
520         const auto *FooPtrVal =
521             cast<PointerValue>(BarPointeeVal->getChild(*FooPtrDecl));
522         const StorageLocation &FooPtrPointeeLoc = FooPtrVal->getPointeeLoc();
523         EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull());
524 
525         const auto *BazRefVal =
526             cast<ReferenceValue>(BarPointeeVal->getChild(*BazRefDecl));
527         const StorageLocation &BazRefPointeeLoc = BazRefVal->getPointeeLoc();
528         EXPECT_THAT(Env.getValue(BazRefPointeeLoc), NotNull());
529 
530         const auto *BazPtrVal =
531             cast<PointerValue>(BarPointeeVal->getChild(*BazPtrDecl));
532         const StorageLocation &BazPtrPointeeLoc = BazPtrVal->getPointeeLoc();
533         EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull());
534       });
535 }
536 
537 TEST_F(TransferTest, MultipleVarsDecl) {
538   std::string Code = R"(
539     void target() {
540       int Foo, Bar;
541       (void)0;
542       // [[p]]
543     }
544   )";
545   runDataflow(Code,
546               [](llvm::ArrayRef<
547                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
548                      Results,
549                  ASTContext &ASTCtx) {
550                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
551                 const Environment &Env = Results[0].second.Env;
552 
553                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
554                 ASSERT_THAT(FooDecl, NotNull());
555 
556                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
557                 ASSERT_THAT(BarDecl, NotNull());
558 
559                 const StorageLocation *FooLoc =
560                     Env.getStorageLocation(*FooDecl, SkipPast::None);
561                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
562 
563                 const StorageLocation *BarLoc =
564                     Env.getStorageLocation(*BarDecl, SkipPast::None);
565                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
566 
567                 const Value *FooVal = Env.getValue(*FooLoc);
568                 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
569 
570                 const Value *BarVal = Env.getValue(*BarLoc);
571                 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
572               });
573 }
574 
575 TEST_F(TransferTest, JoinVarDecl) {
576   std::string Code = R"(
577     void target(bool B) {
578       int Foo;
579       // [[p1]]
580       if (B) {
581         int Bar;
582         // [[p2]]
583       } else {
584         int Baz;
585         // [[p3]]
586       }
587       (void)0;
588       // [[p4]]
589     }
590   )";
591   runDataflow(Code, [](llvm::ArrayRef<std::pair<
592                            std::string, DataflowAnalysisState<NoopLattice>>>
593                            Results,
594                        ASTContext &ASTCtx) {
595     ASSERT_THAT(Results, ElementsAre(Pair("p4", _), Pair("p3", _),
596                                      Pair("p2", _), Pair("p1", _)));
597     const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
598     ASSERT_THAT(FooDecl, NotNull());
599 
600     const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
601     ASSERT_THAT(BarDecl, NotNull());
602 
603     const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
604     ASSERT_THAT(BazDecl, NotNull());
605 
606     const Environment &Env1 = Results[3].second.Env;
607     const StorageLocation *FooLoc =
608         Env1.getStorageLocation(*FooDecl, SkipPast::None);
609     EXPECT_THAT(FooLoc, NotNull());
610     EXPECT_THAT(Env1.getStorageLocation(*BarDecl, SkipPast::None), IsNull());
611     EXPECT_THAT(Env1.getStorageLocation(*BazDecl, SkipPast::None), IsNull());
612 
613     const Environment &Env2 = Results[2].second.Env;
614     EXPECT_EQ(Env2.getStorageLocation(*FooDecl, SkipPast::None), FooLoc);
615     EXPECT_THAT(Env2.getStorageLocation(*BarDecl, SkipPast::None), NotNull());
616     EXPECT_THAT(Env2.getStorageLocation(*BazDecl, SkipPast::None), IsNull());
617 
618     const Environment &Env3 = Results[1].second.Env;
619     EXPECT_EQ(Env3.getStorageLocation(*FooDecl, SkipPast::None), FooLoc);
620     EXPECT_THAT(Env3.getStorageLocation(*BarDecl, SkipPast::None), IsNull());
621     EXPECT_THAT(Env3.getStorageLocation(*BazDecl, SkipPast::None), NotNull());
622 
623     const Environment &Env4 = Results[0].second.Env;
624     EXPECT_EQ(Env4.getStorageLocation(*FooDecl, SkipPast::None), FooLoc);
625     EXPECT_THAT(Env4.getStorageLocation(*BarDecl, SkipPast::None), IsNull());
626     EXPECT_THAT(Env4.getStorageLocation(*BazDecl, SkipPast::None), IsNull());
627   });
628 }
629 
630 TEST_F(TransferTest, BinaryOperatorAssign) {
631   std::string Code = R"(
632     void target() {
633       int Foo;
634       int Bar;
635       (Bar) = (Foo);
636       // [[p]]
637     }
638   )";
639   runDataflow(Code,
640               [](llvm::ArrayRef<
641                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
642                      Results,
643                  ASTContext &ASTCtx) {
644                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
645                 const Environment &Env = Results[0].second.Env;
646 
647                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
648                 ASSERT_THAT(FooDecl, NotNull());
649 
650                 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
651                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
652 
653                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
654                 ASSERT_THAT(BarDecl, NotNull());
655 
656                 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal);
657               });
658 }
659 
660 TEST_F(TransferTest, VarDeclInitAssign) {
661   std::string Code = R"(
662     void target() {
663       int Foo;
664       int Bar = Foo;
665       // [[p]]
666     }
667   )";
668   runDataflow(Code,
669               [](llvm::ArrayRef<
670                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
671                      Results,
672                  ASTContext &ASTCtx) {
673                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
674                 const Environment &Env = Results[0].second.Env;
675 
676                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
677                 ASSERT_THAT(FooDecl, NotNull());
678 
679                 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
680                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
681 
682                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
683                 ASSERT_THAT(BarDecl, NotNull());
684 
685                 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal);
686               });
687 }
688 
689 TEST_F(TransferTest, VarDeclInitAssignChained) {
690   std::string Code = R"(
691     void target() {
692       int Foo;
693       int Bar;
694       int Baz = (Bar = Foo);
695       // [[p]]
696     }
697   )";
698   runDataflow(Code,
699               [](llvm::ArrayRef<
700                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
701                      Results,
702                  ASTContext &ASTCtx) {
703                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
704                 const Environment &Env = Results[0].second.Env;
705 
706                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
707                 ASSERT_THAT(FooDecl, NotNull());
708 
709                 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
710                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
711 
712                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
713                 ASSERT_THAT(BarDecl, NotNull());
714 
715                 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
716                 ASSERT_THAT(BazDecl, NotNull());
717 
718                 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal);
719                 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), FooVal);
720               });
721 }
722 
723 TEST_F(TransferTest, VarDeclInitAssignPtrDeref) {
724   std::string Code = R"(
725     void target() {
726       int Foo;
727       int *Bar;
728       *(Bar) = Foo;
729       int Baz = *(Bar);
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 Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
745                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
746 
747                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
748                 ASSERT_THAT(BarDecl, NotNull());
749 
750                 const auto *BarVal =
751                     cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None));
752                 EXPECT_EQ(Env.getValue(BarVal->getPointeeLoc()), FooVal);
753 
754                 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
755                 ASSERT_THAT(BazDecl, NotNull());
756 
757                 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), FooVal);
758               });
759 }
760 
761 TEST_F(TransferTest, AssignToAndFromReference) {
762   std::string Code = R"(
763     void target() {
764       int Foo;
765       int Bar;
766       int &Baz = Foo;
767       // [[p1]]
768       Baz = Bar;
769       int Qux = Baz;
770       int &Quux = Baz;
771       // [[p2]]
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("p1", _), Pair("p2", _)));
780         const Environment &Env1 = Results[0].second.Env;
781         const Environment &Env2 = Results[1].second.Env;
782 
783         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
784         ASSERT_THAT(FooDecl, NotNull());
785 
786         const Value *FooVal = Env1.getValue(*FooDecl, SkipPast::None);
787         ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
788 
789         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
790         ASSERT_THAT(BarDecl, NotNull());
791 
792         const Value *BarVal = Env1.getValue(*BarDecl, SkipPast::None);
793         ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
794 
795         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
796         ASSERT_THAT(BazDecl, NotNull());
797 
798         EXPECT_EQ(Env1.getValue(*BazDecl, SkipPast::Reference), FooVal);
799 
800         EXPECT_EQ(Env2.getValue(*BazDecl, SkipPast::Reference), BarVal);
801         EXPECT_EQ(Env2.getValue(*FooDecl, SkipPast::None), BarVal);
802 
803         const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
804         ASSERT_THAT(QuxDecl, NotNull());
805         EXPECT_EQ(Env2.getValue(*QuxDecl, SkipPast::None), BarVal);
806 
807         const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
808         ASSERT_THAT(QuuxDecl, NotNull());
809         EXPECT_EQ(Env2.getValue(*QuuxDecl, SkipPast::Reference), BarVal);
810       });
811 }
812 
813 TEST_F(TransferTest, MultipleParamDecls) {
814   std::string Code = R"(
815     void target(int Foo, int Bar) {
816       (void)0;
817       // [[p]]
818     }
819   )";
820   runDataflow(Code,
821               [](llvm::ArrayRef<
822                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
823                      Results,
824                  ASTContext &ASTCtx) {
825                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
826                 const Environment &Env = Results[0].second.Env;
827 
828                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
829                 ASSERT_THAT(FooDecl, NotNull());
830 
831                 const StorageLocation *FooLoc =
832                     Env.getStorageLocation(*FooDecl, SkipPast::None);
833                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
834 
835                 const Value *FooVal = Env.getValue(*FooLoc);
836                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
837 
838                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
839                 ASSERT_THAT(BarDecl, NotNull());
840 
841                 const StorageLocation *BarLoc =
842                     Env.getStorageLocation(*BarDecl, SkipPast::None);
843                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
844 
845                 const Value *BarVal = Env.getValue(*BarLoc);
846                 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
847               });
848 }
849 
850 TEST_F(TransferTest, StructParamDecl) {
851   std::string Code = R"(
852     struct A {
853       int Bar;
854     };
855 
856     void target(A Foo) {
857       (void)0;
858       // [[p]]
859     }
860   )";
861   runDataflow(
862       Code, [](llvm::ArrayRef<
863                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
864                    Results,
865                ASTContext &ASTCtx) {
866         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
867         const Environment &Env = Results[0].second.Env;
868 
869         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
870         ASSERT_THAT(FooDecl, NotNull());
871 
872         ASSERT_TRUE(FooDecl->getType()->isStructureType());
873         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
874 
875         FieldDecl *BarDecl = nullptr;
876         for (FieldDecl *Field : FooFields) {
877           if (Field->getNameAsString() == "Bar") {
878             BarDecl = Field;
879           } else {
880             FAIL() << "Unexpected field: " << Field->getNameAsString();
881           }
882         }
883         ASSERT_THAT(BarDecl, NotNull());
884 
885         const auto *FooLoc = cast<AggregateStorageLocation>(
886             Env.getStorageLocation(*FooDecl, SkipPast::None));
887         const auto *BarLoc =
888             cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
889 
890         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
891         const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl));
892         EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
893       });
894 }
895 
896 TEST_F(TransferTest, ReferenceParamDecl) {
897   std::string Code = R"(
898     struct A {};
899 
900     void target(A &Foo) {
901       (void)0;
902       // [[p]]
903     }
904   )";
905   runDataflow(Code,
906               [](llvm::ArrayRef<
907                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
908                      Results,
909                  ASTContext &ASTCtx) {
910                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
911                 const Environment &Env = Results[0].second.Env;
912 
913                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
914                 ASSERT_THAT(FooDecl, NotNull());
915 
916                 const StorageLocation *FooLoc =
917                     Env.getStorageLocation(*FooDecl, SkipPast::None);
918                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
919 
920                 const ReferenceValue *FooVal =
921                     dyn_cast<ReferenceValue>(Env.getValue(*FooLoc));
922                 ASSERT_THAT(FooVal, NotNull());
923 
924                 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
925                 EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc));
926 
927                 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
928                 EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal));
929               });
930 }
931 
932 TEST_F(TransferTest, PointerParamDecl) {
933   std::string Code = R"(
934     struct A {};
935 
936     void target(A *Foo) {
937       (void)0;
938       // [[p]]
939     }
940   )";
941   runDataflow(
942       Code, [](llvm::ArrayRef<
943                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
944                    Results,
945                ASTContext &ASTCtx) {
946         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
947         const Environment &Env = Results[0].second.Env;
948 
949         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
950         ASSERT_THAT(FooDecl, NotNull());
951 
952         const StorageLocation *FooLoc =
953             Env.getStorageLocation(*FooDecl, SkipPast::None);
954         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
955 
956         const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));
957         const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
958         EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc));
959 
960         const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
961         EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal));
962       });
963 }
964 
965 TEST_F(TransferTest, StructMember) {
966   std::string Code = R"(
967     struct A {
968       int Bar;
969     };
970 
971     void target(A Foo) {
972       int Baz = Foo.Bar;
973       // [[p]]
974     }
975   )";
976   runDataflow(
977       Code, [](llvm::ArrayRef<
978                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
979                    Results,
980                ASTContext &ASTCtx) {
981         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
982         const Environment &Env = Results[0].second.Env;
983 
984         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
985         ASSERT_THAT(FooDecl, NotNull());
986 
987         ASSERT_TRUE(FooDecl->getType()->isStructureType());
988         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
989 
990         FieldDecl *BarDecl = nullptr;
991         for (FieldDecl *Field : FooFields) {
992           if (Field->getNameAsString() == "Bar") {
993             BarDecl = Field;
994           } else {
995             FAIL() << "Unexpected field: " << Field->getNameAsString();
996           }
997         }
998         ASSERT_THAT(BarDecl, NotNull());
999 
1000         const auto *FooLoc = cast<AggregateStorageLocation>(
1001             Env.getStorageLocation(*FooDecl, SkipPast::None));
1002         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1003         const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl));
1004 
1005         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1006         ASSERT_THAT(BazDecl, NotNull());
1007 
1008         EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarVal);
1009       });
1010 }
1011 
1012 TEST_F(TransferTest, ClassMember) {
1013   std::string Code = R"(
1014     class A {
1015     public:
1016       int Bar;
1017     };
1018 
1019     void target(A Foo) {
1020       int Baz = Foo.Bar;
1021       // [[p]]
1022     }
1023   )";
1024   runDataflow(
1025       Code, [](llvm::ArrayRef<
1026                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1027                    Results,
1028                ASTContext &ASTCtx) {
1029         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1030         const Environment &Env = Results[0].second.Env;
1031 
1032         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1033         ASSERT_THAT(FooDecl, NotNull());
1034 
1035         ASSERT_TRUE(FooDecl->getType()->isClassType());
1036         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1037 
1038         FieldDecl *BarDecl = nullptr;
1039         for (FieldDecl *Field : FooFields) {
1040           if (Field->getNameAsString() == "Bar") {
1041             BarDecl = Field;
1042           } else {
1043             FAIL() << "Unexpected field: " << Field->getNameAsString();
1044           }
1045         }
1046         ASSERT_THAT(BarDecl, NotNull());
1047 
1048         const auto *FooLoc = cast<AggregateStorageLocation>(
1049             Env.getStorageLocation(*FooDecl, SkipPast::None));
1050         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1051         const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl));
1052 
1053         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1054         ASSERT_THAT(BazDecl, NotNull());
1055 
1056         EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarVal);
1057       });
1058 }
1059 
1060 TEST_F(TransferTest, ReferenceMember) {
1061   std::string Code = R"(
1062     struct A {
1063       int &Bar;
1064     };
1065 
1066     void target(A Foo) {
1067       int Baz = Foo.Bar;
1068       // [[p]]
1069     }
1070   )";
1071   runDataflow(
1072       Code, [](llvm::ArrayRef<
1073                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1074                    Results,
1075                ASTContext &ASTCtx) {
1076         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1077         const Environment &Env = Results[0].second.Env;
1078 
1079         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1080         ASSERT_THAT(FooDecl, NotNull());
1081 
1082         ASSERT_TRUE(FooDecl->getType()->isStructureType());
1083         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1084 
1085         FieldDecl *BarDecl = nullptr;
1086         for (FieldDecl *Field : FooFields) {
1087           if (Field->getNameAsString() == "Bar") {
1088             BarDecl = Field;
1089           } else {
1090             FAIL() << "Unexpected field: " << Field->getNameAsString();
1091           }
1092         }
1093         ASSERT_THAT(BarDecl, NotNull());
1094 
1095         const auto *FooLoc = cast<AggregateStorageLocation>(
1096             Env.getStorageLocation(*FooDecl, SkipPast::None));
1097         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1098         const auto *BarVal = cast<ReferenceValue>(FooVal->getChild(*BarDecl));
1099         const auto *BarPointeeVal =
1100             cast<IntegerValue>(Env.getValue(BarVal->getPointeeLoc()));
1101 
1102         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1103         ASSERT_THAT(BazDecl, NotNull());
1104 
1105         EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarPointeeVal);
1106       });
1107 }
1108 
1109 TEST_F(TransferTest, StructThisMember) {
1110   std::string Code = R"(
1111     struct A {
1112       int Bar;
1113 
1114       struct B {
1115         int Baz;
1116       };
1117 
1118       B Qux;
1119 
1120       void target() {
1121         int Foo = Bar;
1122         int Quux = Qux.Baz;
1123         // [[p]]
1124       }
1125     };
1126   )";
1127   runDataflow(
1128       Code, [](llvm::ArrayRef<
1129                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1130                    Results,
1131                ASTContext &ASTCtx) {
1132         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1133         const Environment &Env = Results[0].second.Env;
1134 
1135         const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1136             Env.getThisPointeeStorageLocation());
1137         ASSERT_THAT(ThisLoc, NotNull());
1138 
1139         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1140         ASSERT_THAT(BarDecl, NotNull());
1141 
1142         const auto *BarLoc =
1143             cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl));
1144         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1145 
1146         const Value *BarVal = Env.getValue(*BarLoc);
1147         ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1148 
1149         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1150         ASSERT_THAT(FooDecl, NotNull());
1151         EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal);
1152 
1153         const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1154         ASSERT_THAT(QuxDecl, NotNull());
1155 
1156         ASSERT_TRUE(QuxDecl->getType()->isStructureType());
1157         auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields();
1158 
1159         FieldDecl *BazDecl = nullptr;
1160         for (FieldDecl *Field : QuxFields) {
1161           if (Field->getNameAsString() == "Baz") {
1162             BazDecl = Field;
1163           } else {
1164             FAIL() << "Unexpected field: " << Field->getNameAsString();
1165           }
1166         }
1167         ASSERT_THAT(BazDecl, NotNull());
1168 
1169         const auto *QuxLoc =
1170             cast<AggregateStorageLocation>(&ThisLoc->getChild(*QuxDecl));
1171         const auto *QuxVal = dyn_cast<StructValue>(Env.getValue(*QuxLoc));
1172         ASSERT_THAT(QuxVal, NotNull());
1173 
1174         const auto *BazLoc =
1175             cast<ScalarStorageLocation>(&QuxLoc->getChild(*BazDecl));
1176         const auto *BazVal = cast<IntegerValue>(QuxVal->getChild(*BazDecl));
1177         EXPECT_EQ(Env.getValue(*BazLoc), BazVal);
1178 
1179         const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
1180         ASSERT_THAT(QuuxDecl, NotNull());
1181         EXPECT_EQ(Env.getValue(*QuuxDecl, SkipPast::None), BazVal);
1182       });
1183 }
1184 
1185 TEST_F(TransferTest, ClassThisMember) {
1186   std::string Code = R"(
1187     class A {
1188       int Bar;
1189 
1190       class B {
1191       public:
1192         int Baz;
1193       };
1194 
1195       B Qux;
1196 
1197       void target() {
1198         int Foo = Bar;
1199         int Quux = Qux.Baz;
1200         // [[p]]
1201       }
1202     };
1203   )";
1204   runDataflow(
1205       Code, [](llvm::ArrayRef<
1206                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1207                    Results,
1208                ASTContext &ASTCtx) {
1209         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1210         const Environment &Env = Results[0].second.Env;
1211 
1212         const auto *ThisLoc =
1213             cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation());
1214 
1215         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1216         ASSERT_THAT(BarDecl, NotNull());
1217 
1218         const auto *BarLoc =
1219             cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl));
1220         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1221 
1222         const Value *BarVal = Env.getValue(*BarLoc);
1223         ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1224 
1225         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1226         ASSERT_THAT(FooDecl, NotNull());
1227         EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal);
1228 
1229         const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1230         ASSERT_THAT(QuxDecl, NotNull());
1231 
1232         ASSERT_TRUE(QuxDecl->getType()->isClassType());
1233         auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields();
1234 
1235         FieldDecl *BazDecl = nullptr;
1236         for (FieldDecl *Field : QuxFields) {
1237           if (Field->getNameAsString() == "Baz") {
1238             BazDecl = Field;
1239           } else {
1240             FAIL() << "Unexpected field: " << Field->getNameAsString();
1241           }
1242         }
1243         ASSERT_THAT(BazDecl, NotNull());
1244 
1245         const auto *QuxLoc =
1246             cast<AggregateStorageLocation>(&ThisLoc->getChild(*QuxDecl));
1247         const auto *QuxVal = dyn_cast<StructValue>(Env.getValue(*QuxLoc));
1248         ASSERT_THAT(QuxVal, NotNull());
1249 
1250         const auto *BazLoc =
1251             cast<ScalarStorageLocation>(&QuxLoc->getChild(*BazDecl));
1252         const auto *BazVal = cast<IntegerValue>(QuxVal->getChild(*BazDecl));
1253         EXPECT_EQ(Env.getValue(*BazLoc), BazVal);
1254 
1255         const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
1256         ASSERT_THAT(QuuxDecl, NotNull());
1257         EXPECT_EQ(Env.getValue(*QuuxDecl, SkipPast::None), BazVal);
1258       });
1259 }
1260 
1261 TEST_F(TransferTest, ConstructorInitializer) {
1262   std::string Code = R"(
1263     struct target {
1264       int Bar;
1265 
1266       target(int Foo) : Bar(Foo) {
1267         int Qux = Bar;
1268         // [[p]]
1269       }
1270     };
1271   )";
1272   runDataflow(Code,
1273               [](llvm::ArrayRef<
1274                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1275                      Results,
1276                  ASTContext &ASTCtx) {
1277                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1278                 const Environment &Env = Results[0].second.Env;
1279 
1280                 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1281                     Env.getThisPointeeStorageLocation());
1282                 ASSERT_THAT(ThisLoc, NotNull());
1283 
1284                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1285                 ASSERT_THAT(FooDecl, NotNull());
1286 
1287                 const auto *FooVal =
1288                     cast<IntegerValue>(Env.getValue(*FooDecl, SkipPast::None));
1289 
1290                 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1291                 ASSERT_THAT(QuxDecl, NotNull());
1292                 EXPECT_EQ(Env.getValue(*QuxDecl, SkipPast::None), FooVal);
1293               });
1294 }
1295 
1296 TEST_F(TransferTest, DefaultInitializer) {
1297   std::string Code = R"(
1298     struct target {
1299       int Bar;
1300       int Baz = Bar;
1301 
1302       target(int Foo) : Bar(Foo) {
1303         int Qux = Baz;
1304         // [[p]]
1305       }
1306     };
1307   )";
1308   runDataflow(Code,
1309               [](llvm::ArrayRef<
1310                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1311                      Results,
1312                  ASTContext &ASTCtx) {
1313                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1314                 const Environment &Env = Results[0].second.Env;
1315 
1316                 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1317                     Env.getThisPointeeStorageLocation());
1318                 ASSERT_THAT(ThisLoc, NotNull());
1319 
1320                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1321                 ASSERT_THAT(FooDecl, NotNull());
1322 
1323                 const auto *FooVal =
1324                     cast<IntegerValue>(Env.getValue(*FooDecl, SkipPast::None));
1325 
1326                 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1327                 ASSERT_THAT(QuxDecl, NotNull());
1328                 EXPECT_EQ(Env.getValue(*QuxDecl, SkipPast::None), FooVal);
1329               });
1330 }
1331 
1332 TEST_F(TransferTest, DefaultInitializerReference) {
1333   std::string Code = R"(
1334     struct target {
1335       int &Bar;
1336       int &Baz = Bar;
1337 
1338       target(int &Foo) : Bar(Foo) {
1339         int &Qux = Baz;
1340         // [[p]]
1341       }
1342     };
1343   )";
1344   runDataflow(
1345       Code, [](llvm::ArrayRef<
1346                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1347                    Results,
1348                ASTContext &ASTCtx) {
1349         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1350         const Environment &Env = Results[0].second.Env;
1351 
1352         const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1353             Env.getThisPointeeStorageLocation());
1354         ASSERT_THAT(ThisLoc, NotNull());
1355 
1356         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1357         ASSERT_THAT(FooDecl, NotNull());
1358 
1359         const auto *FooVal =
1360             cast<ReferenceValue>(Env.getValue(*FooDecl, SkipPast::None));
1361 
1362         const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1363         ASSERT_THAT(QuxDecl, NotNull());
1364 
1365         const auto *QuxVal =
1366             cast<ReferenceValue>(Env.getValue(*QuxDecl, SkipPast::None));
1367         EXPECT_EQ(&QuxVal->getPointeeLoc(), &FooVal->getPointeeLoc());
1368       });
1369 }
1370 
1371 TEST_F(TransferTest, TemporaryObject) {
1372   std::string Code = R"(
1373     struct A {
1374       int Bar;
1375     };
1376 
1377     void target() {
1378       A Foo = A();
1379       // [[p]]
1380     }
1381   )";
1382   runDataflow(
1383       Code, [](llvm::ArrayRef<
1384                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1385                    Results,
1386                ASTContext &ASTCtx) {
1387         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1388         const Environment &Env = Results[0].second.Env;
1389 
1390         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1391         ASSERT_THAT(FooDecl, NotNull());
1392 
1393         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1394         ASSERT_THAT(BarDecl, NotNull());
1395 
1396         const auto *FooLoc = cast<AggregateStorageLocation>(
1397             Env.getStorageLocation(*FooDecl, SkipPast::None));
1398         const auto *BarLoc =
1399             cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
1400 
1401         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1402         const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl));
1403         EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
1404       });
1405 }
1406 
1407 TEST_F(TransferTest, ElidableConstructor) {
1408   // This test is effectively the same as TransferTest.TemporaryObject, but
1409   // the code is compiled as C++ 14.
1410   std::string Code = R"(
1411     struct A {
1412       int Bar;
1413     };
1414 
1415     void target() {
1416       A Foo = A();
1417       // [[p]]
1418     }
1419   )";
1420   runDataflow(
1421       Code,
1422       [](llvm::ArrayRef<
1423              std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1424              Results,
1425          ASTContext &ASTCtx) {
1426         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1427         const Environment &Env = Results[0].second.Env;
1428 
1429         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1430         ASSERT_THAT(FooDecl, NotNull());
1431 
1432         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1433         ASSERT_THAT(BarDecl, NotNull());
1434 
1435         const auto *FooLoc = cast<AggregateStorageLocation>(
1436             Env.getStorageLocation(*FooDecl, SkipPast::None));
1437         const auto *BarLoc =
1438             cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
1439 
1440         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1441         const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl));
1442         EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
1443       },
1444       LangStandard::lang_cxx14);
1445 }
1446 
1447 TEST_F(TransferTest, AssignmentOperator) {
1448   std::string Code = R"(
1449     struct A {
1450       int Baz;
1451     };
1452 
1453     void target() {
1454       A Foo;
1455       A Bar;
1456       // [[p1]]
1457       Foo = Bar;
1458       // [[p2]]
1459     }
1460   )";
1461   runDataflow(
1462       Code, [](llvm::ArrayRef<
1463                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1464                    Results,
1465                ASTContext &ASTCtx) {
1466         ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _)));
1467         const Environment &Env1 = Results[0].second.Env;
1468         const Environment &Env2 = Results[1].second.Env;
1469 
1470         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1471         ASSERT_THAT(FooDecl, NotNull());
1472 
1473         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1474         ASSERT_THAT(BarDecl, NotNull());
1475 
1476         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1477         ASSERT_THAT(BazDecl, NotNull());
1478 
1479         const auto *FooLoc1 = cast<AggregateStorageLocation>(
1480             Env1.getStorageLocation(*FooDecl, SkipPast::None));
1481         const auto *BarLoc1 = cast<AggregateStorageLocation>(
1482             Env1.getStorageLocation(*BarDecl, SkipPast::None));
1483 
1484         const auto *FooVal1 = cast<StructValue>(Env1.getValue(*FooLoc1));
1485         const auto *BarVal1 = cast<StructValue>(Env1.getValue(*BarLoc1));
1486         EXPECT_NE(FooVal1, BarVal1);
1487 
1488         const auto *FooBazVal1 =
1489             cast<IntegerValue>(Env1.getValue(FooLoc1->getChild(*BazDecl)));
1490         const auto *BarBazVal1 =
1491             cast<IntegerValue>(Env1.getValue(BarLoc1->getChild(*BazDecl)));
1492         EXPECT_NE(FooBazVal1, BarBazVal1);
1493 
1494         const auto *FooLoc2 = cast<AggregateStorageLocation>(
1495             Env2.getStorageLocation(*FooDecl, SkipPast::None));
1496         const auto *BarLoc2 = cast<AggregateStorageLocation>(
1497             Env2.getStorageLocation(*BarDecl, SkipPast::None));
1498 
1499         const auto *FooVal2 = cast<StructValue>(Env2.getValue(*FooLoc2));
1500         const auto *BarVal2 = cast<StructValue>(Env2.getValue(*BarLoc2));
1501         EXPECT_EQ(FooVal2, BarVal2);
1502 
1503         const auto *FooBazVal2 =
1504             cast<IntegerValue>(Env2.getValue(FooLoc1->getChild(*BazDecl)));
1505         const auto *BarBazVal2 =
1506             cast<IntegerValue>(Env2.getValue(BarLoc1->getChild(*BazDecl)));
1507         EXPECT_EQ(FooBazVal2, BarBazVal2);
1508       });
1509 }
1510 
1511 TEST_F(TransferTest, CopyConstructor) {
1512   std::string Code = R"(
1513     struct A {
1514       int Baz;
1515     };
1516 
1517     void target() {
1518       A Foo;
1519       A Bar = Foo;
1520       // [[p]]
1521     }
1522   )";
1523   runDataflow(
1524       Code, [](llvm::ArrayRef<
1525                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1526                    Results,
1527                ASTContext &ASTCtx) {
1528         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1529         const Environment &Env = Results[0].second.Env;
1530 
1531         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1532         ASSERT_THAT(FooDecl, NotNull());
1533 
1534         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1535         ASSERT_THAT(BarDecl, NotNull());
1536 
1537         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1538         ASSERT_THAT(BazDecl, NotNull());
1539 
1540         const auto *FooLoc = cast<AggregateStorageLocation>(
1541             Env.getStorageLocation(*FooDecl, SkipPast::None));
1542         const auto *BarLoc = cast<AggregateStorageLocation>(
1543             Env.getStorageLocation(*BarDecl, SkipPast::None));
1544 
1545         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1546         const auto *BarVal = cast<StructValue>(Env.getValue(*BarLoc));
1547         EXPECT_EQ(FooVal, BarVal);
1548 
1549         const auto *FooBazVal =
1550             cast<IntegerValue>(Env.getValue(FooLoc->getChild(*BazDecl)));
1551         const auto *BarBazVal =
1552             cast<IntegerValue>(Env.getValue(BarLoc->getChild(*BazDecl)));
1553         EXPECT_EQ(FooBazVal, BarBazVal);
1554       });
1555 }
1556 
1557 TEST_F(TransferTest, CopyConstructorWithParens) {
1558   std::string Code = R"(
1559     struct A {
1560       int Baz;
1561     };
1562 
1563     void target() {
1564       A Foo;
1565       A Bar((A(Foo)));
1566       // [[p]]
1567     }
1568   )";
1569   runDataflow(
1570       Code, [](llvm::ArrayRef<
1571                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1572                    Results,
1573                ASTContext &ASTCtx) {
1574         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1575         const Environment &Env = Results[0].second.Env;
1576 
1577         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1578         ASSERT_THAT(FooDecl, NotNull());
1579 
1580         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1581         ASSERT_THAT(BarDecl, NotNull());
1582 
1583         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1584         ASSERT_THAT(BazDecl, NotNull());
1585 
1586         const auto *FooLoc = cast<AggregateStorageLocation>(
1587             Env.getStorageLocation(*FooDecl, SkipPast::None));
1588         const auto *BarLoc = cast<AggregateStorageLocation>(
1589             Env.getStorageLocation(*BarDecl, SkipPast::None));
1590 
1591         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1592         const auto *BarVal = cast<StructValue>(Env.getValue(*BarLoc));
1593         EXPECT_EQ(FooVal, BarVal);
1594 
1595         const auto *FooBazVal =
1596             cast<IntegerValue>(Env.getValue(FooLoc->getChild(*BazDecl)));
1597         const auto *BarBazVal =
1598             cast<IntegerValue>(Env.getValue(BarLoc->getChild(*BazDecl)));
1599         EXPECT_EQ(FooBazVal, BarBazVal);
1600       });
1601 }
1602 
1603 TEST_F(TransferTest, MoveConstructor) {
1604   std::string Code = R"(
1605     namespace std {
1606 
1607     template <typename T> struct remove_reference      { using type = T; };
1608     template <typename T> struct remove_reference<T&>  { using type = T; };
1609     template <typename T> struct remove_reference<T&&> { using type = T; };
1610 
1611     template <typename T>
1612     using remove_reference_t = typename remove_reference<T>::type;
1613 
1614     template <typename T>
1615     std::remove_reference_t<T>&& move(T&& x);
1616 
1617     } // namespace std
1618 
1619     struct A {
1620       int Baz;
1621     };
1622 
1623     void target() {
1624       A Foo;
1625       A Bar;
1626       // [[p1]]
1627       Foo = std::move(Bar);
1628       // [[p2]]
1629     }
1630   )";
1631   runDataflow(
1632       Code, [](llvm::ArrayRef<
1633                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1634                    Results,
1635                ASTContext &ASTCtx) {
1636         ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _)));
1637         const Environment &Env1 = Results[0].second.Env;
1638         const Environment &Env2 = Results[1].second.Env;
1639 
1640         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1641         ASSERT_THAT(FooDecl, NotNull());
1642 
1643         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1644         ASSERT_THAT(BarDecl, NotNull());
1645 
1646         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1647         ASSERT_THAT(BazDecl, NotNull());
1648 
1649         const auto *FooLoc1 = cast<AggregateStorageLocation>(
1650             Env1.getStorageLocation(*FooDecl, SkipPast::None));
1651         const auto *BarLoc1 = cast<AggregateStorageLocation>(
1652             Env1.getStorageLocation(*BarDecl, SkipPast::None));
1653 
1654         const auto *FooVal1 = cast<StructValue>(Env1.getValue(*FooLoc1));
1655         const auto *BarVal1 = cast<StructValue>(Env1.getValue(*BarLoc1));
1656         EXPECT_NE(FooVal1, BarVal1);
1657 
1658         const auto *FooBazVal1 =
1659             cast<IntegerValue>(Env1.getValue(FooLoc1->getChild(*BazDecl)));
1660         const auto *BarBazVal1 =
1661             cast<IntegerValue>(Env1.getValue(BarLoc1->getChild(*BazDecl)));
1662         EXPECT_NE(FooBazVal1, BarBazVal1);
1663 
1664         const auto *FooLoc2 = cast<AggregateStorageLocation>(
1665             Env2.getStorageLocation(*FooDecl, SkipPast::None));
1666         const auto *FooVal2 = cast<StructValue>(Env2.getValue(*FooLoc2));
1667         EXPECT_EQ(FooVal2, BarVal1);
1668 
1669         const auto *FooBazVal2 =
1670             cast<IntegerValue>(Env2.getValue(FooLoc1->getChild(*BazDecl)));
1671         EXPECT_EQ(FooBazVal2, BarBazVal1);
1672       });
1673 }
1674 
1675 TEST_F(TransferTest, BindTemporary) {
1676   std::string Code = R"(
1677     struct A {
1678       virtual ~A() = default;
1679 
1680       int Baz;
1681     };
1682 
1683     void target(A Foo) {
1684       int Bar = A(Foo).Baz;
1685       // [[p]]
1686     }
1687   )";
1688   runDataflow(Code,
1689               [](llvm::ArrayRef<
1690                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1691                      Results,
1692                  ASTContext &ASTCtx) {
1693                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1694                 const Environment &Env = Results[0].second.Env;
1695 
1696                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1697                 ASSERT_THAT(FooDecl, NotNull());
1698 
1699                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1700                 ASSERT_THAT(BarDecl, NotNull());
1701 
1702                 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1703                 ASSERT_THAT(BazDecl, NotNull());
1704 
1705                 const auto &FooVal =
1706                     *cast<StructValue>(Env.getValue(*FooDecl, SkipPast::None));
1707                 const auto *BarVal =
1708                     cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None));
1709                 EXPECT_EQ(BarVal, FooVal.getChild(*BazDecl));
1710               });
1711 }
1712 
1713 TEST_F(TransferTest, StaticCast) {
1714   std::string Code = R"(
1715     void target(int Foo) {
1716       int Bar = static_cast<int>(Foo);
1717       // [[p]]
1718     }
1719   )";
1720   runDataflow(Code,
1721               [](llvm::ArrayRef<
1722                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1723                      Results,
1724                  ASTContext &ASTCtx) {
1725                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1726                 const Environment &Env = Results[0].second.Env;
1727 
1728                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1729                 ASSERT_THAT(FooDecl, NotNull());
1730 
1731                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1732                 ASSERT_THAT(BarDecl, NotNull());
1733 
1734                 const auto *FooVal =
1735                     cast<IntegerValue>(Env.getValue(*FooDecl, SkipPast::None));
1736                 const auto *BarVal =
1737                     cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None));
1738                 EXPECT_EQ(FooVal, BarVal);
1739               });
1740 }
1741 
1742 TEST_F(TransferTest, AddrOfValue) {
1743   std::string Code = R"(
1744     void target() {
1745       int Foo;
1746       int *Bar = &Foo;
1747       // [[p]]
1748     }
1749   )";
1750   runDataflow(Code,
1751               [](llvm::ArrayRef<
1752                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1753                      Results,
1754                  ASTContext &ASTCtx) {
1755                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1756                 const Environment &Env = Results[0].second.Env;
1757 
1758                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1759                 ASSERT_THAT(FooDecl, NotNull());
1760 
1761                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1762                 ASSERT_THAT(BarDecl, NotNull());
1763 
1764                 const auto *FooLoc = cast<ScalarStorageLocation>(
1765                     Env.getStorageLocation(*FooDecl, SkipPast::None));
1766                 const auto *BarVal =
1767                     cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None));
1768                 EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc);
1769               });
1770 }
1771 
1772 TEST_F(TransferTest, AddrOfReference) {
1773   std::string Code = R"(
1774     void target(int *Foo) {
1775       int *Bar = &(*Foo);
1776       // [[p]]
1777     }
1778   )";
1779   runDataflow(Code,
1780               [](llvm::ArrayRef<
1781                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1782                      Results,
1783                  ASTContext &ASTCtx) {
1784                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1785                 const Environment &Env = Results[0].second.Env;
1786 
1787                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1788                 ASSERT_THAT(FooDecl, NotNull());
1789 
1790                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1791                 ASSERT_THAT(BarDecl, NotNull());
1792 
1793                 const auto *FooVal =
1794                     cast<PointerValue>(Env.getValue(*FooDecl, SkipPast::None));
1795                 const auto *BarVal =
1796                     cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None));
1797                 EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc());
1798               });
1799 }
1800 
1801 TEST_F(TransferTest, DerefDependentPtr) {
1802   std::string Code = R"(
1803     template <typename T>
1804     void target(T *Foo) {
1805       T &Bar = *Foo;
1806       /*[[p]]*/
1807     }
1808   )";
1809   runDataflow(
1810       Code, [](llvm::ArrayRef<
1811                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1812                    Results,
1813                ASTContext &ASTCtx) {
1814         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1815         const Environment &Env = Results[0].second.Env;
1816 
1817         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1818         ASSERT_THAT(FooDecl, NotNull());
1819 
1820         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1821         ASSERT_THAT(BarDecl, NotNull());
1822 
1823         const auto *FooVal =
1824             cast<PointerValue>(Env.getValue(*FooDecl, SkipPast::None));
1825         const auto *BarVal =
1826             cast<ReferenceValue>(Env.getValue(*BarDecl, SkipPast::None));
1827         EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc());
1828       });
1829 }
1830 
1831 TEST_F(TransferTest, VarDeclInitAssignConditionalOperator) {
1832   std::string Code = R"(
1833     struct A {};
1834 
1835     void target(A Foo, A Bar, bool Cond) {
1836       A Baz = Cond ?  Foo : Bar;
1837       /*[[p]]*/
1838     }
1839   )";
1840   runDataflow(
1841       Code, [](llvm::ArrayRef<
1842                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1843                    Results,
1844                ASTContext &ASTCtx) {
1845         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1846         const Environment &Env = Results[0].second.Env;
1847 
1848         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1849         ASSERT_THAT(FooDecl, NotNull());
1850 
1851         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1852         ASSERT_THAT(BarDecl, NotNull());
1853 
1854         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1855         ASSERT_THAT(BazDecl, NotNull());
1856 
1857         const auto *FooVal =
1858             cast<StructValue>(Env.getValue(*FooDecl, SkipPast::None));
1859         const auto *BarVal =
1860             cast<StructValue>(Env.getValue(*BarDecl, SkipPast::None));
1861 
1862         const auto *BazVal =
1863             dyn_cast<StructValue>(Env.getValue(*BazDecl, SkipPast::None));
1864         ASSERT_THAT(BazVal, NotNull());
1865 
1866         EXPECT_NE(BazVal, FooVal);
1867         EXPECT_NE(BazVal, BarVal);
1868       });
1869 }
1870 
1871 TEST_F(TransferTest, VarDeclInDoWhile) {
1872   std::string Code = R"(
1873     void target(int *Foo) {
1874       do {
1875         int Bar = *Foo;
1876       } while (true);
1877       (void)0;
1878       /*[[p]]*/
1879     }
1880   )";
1881   runDataflow(Code,
1882               [](llvm::ArrayRef<
1883                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1884                      Results,
1885                  ASTContext &ASTCtx) {
1886                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1887                 const Environment &Env = Results[0].second.Env;
1888 
1889                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1890                 ASSERT_THAT(FooDecl, NotNull());
1891 
1892                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1893                 ASSERT_THAT(BarDecl, NotNull());
1894 
1895                 const auto *FooVal =
1896                     cast<PointerValue>(Env.getValue(*FooDecl, SkipPast::None));
1897                 const auto *FooPointeeVal =
1898                     cast<IntegerValue>(Env.getValue(FooVal->getPointeeLoc()));
1899 
1900                 const auto *BarVal = dyn_cast_or_null<IntegerValue>(
1901                     Env.getValue(*BarDecl, SkipPast::None));
1902                 ASSERT_THAT(BarVal, NotNull());
1903 
1904                 EXPECT_EQ(BarVal, FooPointeeVal);
1905               });
1906 }
1907 
1908 TEST_F(TransferTest, AggregateInitialization) {
1909   std::string BracesCode = R"(
1910     struct A {
1911       int Foo;
1912     };
1913 
1914     struct B {
1915       int Bar;
1916       A Baz;
1917       int Qux;
1918     };
1919 
1920     void target(int BarArg, int FooArg, int QuxArg) {
1921       B Quux{BarArg, {FooArg}, QuxArg};
1922       /*[[p]]*/
1923     }
1924   )";
1925   std::string BraceEllisionCode = R"(
1926     struct A {
1927       int Foo;
1928     };
1929 
1930     struct B {
1931       int Bar;
1932       A Baz;
1933       int Qux;
1934     };
1935 
1936     void target(int BarArg, int FooArg, int QuxArg) {
1937       B Quux = {BarArg, FooArg, QuxArg};
1938       /*[[p]]*/
1939     }
1940   )";
1941   for (const std::string &Code : {BracesCode, BraceEllisionCode}) {
1942     runDataflow(
1943         Code, [](llvm::ArrayRef<
1944                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1945                      Results,
1946                  ASTContext &ASTCtx) {
1947           ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1948           const Environment &Env = Results[0].second.Env;
1949 
1950           const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1951           ASSERT_THAT(FooDecl, NotNull());
1952 
1953           const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1954           ASSERT_THAT(BarDecl, NotNull());
1955 
1956           const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1957           ASSERT_THAT(BazDecl, NotNull());
1958 
1959           const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1960           ASSERT_THAT(QuxDecl, NotNull());
1961 
1962           const ValueDecl *FooArgDecl = findValueDecl(ASTCtx, "FooArg");
1963           ASSERT_THAT(FooArgDecl, NotNull());
1964 
1965           const ValueDecl *BarArgDecl = findValueDecl(ASTCtx, "BarArg");
1966           ASSERT_THAT(BarArgDecl, NotNull());
1967 
1968           const ValueDecl *QuxArgDecl = findValueDecl(ASTCtx, "QuxArg");
1969           ASSERT_THAT(QuxArgDecl, NotNull());
1970 
1971           const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
1972           ASSERT_THAT(QuuxDecl, NotNull());
1973 
1974           const auto *FooArgVal =
1975               cast<IntegerValue>(Env.getValue(*FooArgDecl, SkipPast::None));
1976           const auto *BarArgVal =
1977               cast<IntegerValue>(Env.getValue(*BarArgDecl, SkipPast::None));
1978           const auto *QuxArgVal =
1979               cast<IntegerValue>(Env.getValue(*QuxArgDecl, SkipPast::None));
1980 
1981           const auto *QuuxVal =
1982               cast<StructValue>(Env.getValue(*QuuxDecl, SkipPast::None));
1983           ASSERT_THAT(QuuxVal, NotNull());
1984 
1985           const auto *BazVal = cast<StructValue>(QuuxVal->getChild(*BazDecl));
1986           ASSERT_THAT(BazVal, NotNull());
1987 
1988           EXPECT_EQ(QuuxVal->getChild(*BarDecl), BarArgVal);
1989           EXPECT_EQ(BazVal->getChild(*FooDecl), FooArgVal);
1990           EXPECT_EQ(QuuxVal->getChild(*QuxDecl), QuxArgVal);
1991         });
1992   }
1993 }
1994 
1995 TEST_F(TransferTest, AssignToUnionMember) {
1996   std::string Code = R"(
1997     union A {
1998       int Foo;
1999     };
2000 
2001     void target(int Bar) {
2002       A Baz;
2003       Baz.Foo = Bar;
2004       // [[p]]
2005     }
2006   )";
2007   runDataflow(Code,
2008               [](llvm::ArrayRef<
2009                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2010                      Results,
2011                  ASTContext &ASTCtx) {
2012                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2013                 const Environment &Env = Results[0].second.Env;
2014 
2015                 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2016                 ASSERT_THAT(BazDecl, NotNull());
2017                 ASSERT_TRUE(BazDecl->getType()->isUnionType());
2018 
2019                 const auto *BazLoc = dyn_cast_or_null<AggregateStorageLocation>(
2020                     Env.getStorageLocation(*BazDecl, SkipPast::None));
2021                 ASSERT_THAT(BazLoc, NotNull());
2022 
2023                 // FIXME: Add support for union types.
2024                 EXPECT_THAT(Env.getValue(*BazLoc), IsNull());
2025               });
2026 }
2027 
2028 TEST_F(TransferTest, AssignFromBoolLiteral) {
2029   std::string Code = R"(
2030     void target() {
2031       bool Foo = true;
2032       bool Bar = false;
2033       // [[p]]
2034     }
2035   )";
2036   runDataflow(Code,
2037               [](llvm::ArrayRef<
2038                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2039                      Results,
2040                  ASTContext &ASTCtx) {
2041                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2042                 const Environment &Env = Results[0].second.Env;
2043 
2044                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2045                 ASSERT_THAT(FooDecl, NotNull());
2046 
2047                 const auto *FooVal = dyn_cast_or_null<AtomicBoolValue>(
2048                     Env.getValue(*FooDecl, SkipPast::None));
2049                 ASSERT_THAT(FooVal, NotNull());
2050 
2051                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2052                 ASSERT_THAT(BarDecl, NotNull());
2053 
2054                 const auto *BarVal = dyn_cast_or_null<AtomicBoolValue>(
2055                     Env.getValue(*BarDecl, SkipPast::None));
2056                 ASSERT_THAT(BarVal, NotNull());
2057 
2058                 EXPECT_EQ(FooVal, &Env.getBoolLiteralValue(true));
2059                 EXPECT_EQ(BarVal, &Env.getBoolLiteralValue(false));
2060               });
2061 }
2062 
2063 TEST_F(TransferTest, AssignFromBoolConjunction) {
2064   std::string Code = R"(
2065     void target(bool Foo, bool Bar) {
2066       bool Baz = (Foo) && (Bar);
2067       // [[p]]
2068     }
2069   )";
2070   runDataflow(
2071       Code, [](llvm::ArrayRef<
2072                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2073                    Results,
2074                ASTContext &ASTCtx) {
2075         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2076         const Environment &Env = Results[0].second.Env;
2077 
2078         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2079         ASSERT_THAT(FooDecl, NotNull());
2080 
2081         const auto *FooVal =
2082             dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl, SkipPast::None));
2083         ASSERT_THAT(FooVal, NotNull());
2084 
2085         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2086         ASSERT_THAT(BarDecl, NotNull());
2087 
2088         const auto *BarVal =
2089             dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl, SkipPast::None));
2090         ASSERT_THAT(BarVal, NotNull());
2091 
2092         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2093         ASSERT_THAT(BazDecl, NotNull());
2094 
2095         const auto *BazVal = dyn_cast_or_null<ConjunctionValue>(
2096             Env.getValue(*BazDecl, SkipPast::None));
2097         ASSERT_THAT(BazVal, NotNull());
2098 
2099         EXPECT_EQ(&BazVal->getLeftSubValue(), FooVal);
2100         EXPECT_EQ(&BazVal->getRightSubValue(), BarVal);
2101       });
2102 }
2103 
2104 TEST_F(TransferTest, AssignFromBoolDisjunction) {
2105   std::string Code = R"(
2106     void target(bool Foo, bool Bar) {
2107       bool Baz = (Foo) || (Bar);
2108       // [[p]]
2109     }
2110   )";
2111   runDataflow(
2112       Code, [](llvm::ArrayRef<
2113                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2114                    Results,
2115                ASTContext &ASTCtx) {
2116         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2117         const Environment &Env = Results[0].second.Env;
2118 
2119         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2120         ASSERT_THAT(FooDecl, NotNull());
2121 
2122         const auto *FooVal =
2123             dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl, SkipPast::None));
2124         ASSERT_THAT(FooVal, NotNull());
2125 
2126         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2127         ASSERT_THAT(BarDecl, NotNull());
2128 
2129         const auto *BarVal =
2130             dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl, SkipPast::None));
2131         ASSERT_THAT(BarVal, NotNull());
2132 
2133         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2134         ASSERT_THAT(BazDecl, NotNull());
2135 
2136         const auto *BazVal = dyn_cast_or_null<DisjunctionValue>(
2137             Env.getValue(*BazDecl, SkipPast::None));
2138         ASSERT_THAT(BazVal, NotNull());
2139 
2140         EXPECT_EQ(&BazVal->getLeftSubValue(), FooVal);
2141         EXPECT_EQ(&BazVal->getRightSubValue(), BarVal);
2142       });
2143 }
2144 
2145 TEST_F(TransferTest, AssignFromBoolNegation) {
2146   std::string Code = R"(
2147     void target() {
2148       bool Foo = true;
2149       bool Bar = !(Foo);
2150       // [[p]]
2151     }
2152   )";
2153   runDataflow(Code,
2154               [](llvm::ArrayRef<
2155                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2156                      Results,
2157                  ASTContext &ASTCtx) {
2158                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2159                 const Environment &Env = Results[0].second.Env;
2160 
2161                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2162                 ASSERT_THAT(FooDecl, NotNull());
2163 
2164                 const auto *FooVal = dyn_cast_or_null<AtomicBoolValue>(
2165                     Env.getValue(*FooDecl, SkipPast::None));
2166                 ASSERT_THAT(FooVal, NotNull());
2167 
2168                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2169                 ASSERT_THAT(BarDecl, NotNull());
2170 
2171                 const auto *BarVal = dyn_cast_or_null<NegationValue>(
2172                     Env.getValue(*BarDecl, SkipPast::None));
2173                 ASSERT_THAT(BarVal, NotNull());
2174 
2175                 EXPECT_EQ(&BarVal->getSubVal(), FooVal);
2176               });
2177 }
2178 
2179 TEST_F(TransferTest, StaticIntSingleVarDecl) {
2180   std::string Code = R"(
2181     void target() {
2182       static int Foo;
2183       // [[p]]
2184     }
2185   )";
2186   runDataflow(Code,
2187               [](llvm::ArrayRef<
2188                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2189                      Results,
2190                  ASTContext &ASTCtx) {
2191                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2192                 const Environment &Env = Results[0].second.Env;
2193 
2194                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2195                 ASSERT_THAT(FooDecl, NotNull());
2196 
2197                 const StorageLocation *FooLoc =
2198                     Env.getStorageLocation(*FooDecl, SkipPast::None);
2199                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
2200 
2201                 const Value *FooVal = Env.getValue(*FooLoc);
2202                 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
2203               });
2204 }
2205 
2206 TEST_F(TransferTest, StaticIntGroupVarDecl) {
2207   std::string Code = R"(
2208     void target() {
2209       static int Foo, Bar;
2210       (void)0;
2211       // [[p]]
2212     }
2213   )";
2214   runDataflow(Code,
2215               [](llvm::ArrayRef<
2216                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2217                      Results,
2218                  ASTContext &ASTCtx) {
2219                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2220                 const Environment &Env = Results[0].second.Env;
2221 
2222                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2223                 ASSERT_THAT(FooDecl, NotNull());
2224 
2225                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2226                 ASSERT_THAT(BarDecl, NotNull());
2227 
2228                 const StorageLocation *FooLoc =
2229                     Env.getStorageLocation(*FooDecl, SkipPast::None);
2230                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
2231 
2232                 const StorageLocation *BarLoc =
2233                     Env.getStorageLocation(*BarDecl, SkipPast::None);
2234                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
2235 
2236                 const Value *FooVal = Env.getValue(*FooLoc);
2237                 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
2238 
2239                 const Value *BarVal = Env.getValue(*BarLoc);
2240                 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
2241 
2242                 EXPECT_NE(FooVal, BarVal);
2243               });
2244 }
2245 
2246 TEST_F(TransferTest, GlobalIntVarDecl) {
2247   std::string Code = R"(
2248     static int Foo;
2249 
2250     void target() {
2251       int Bar = Foo;
2252       int Baz = Foo;
2253       // [[p]]
2254     }
2255   )";
2256   runDataflow(Code,
2257               [](llvm::ArrayRef<
2258                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2259                      Results,
2260                  ASTContext &ASTCtx) {
2261                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2262                 const Environment &Env = Results[0].second.Env;
2263 
2264                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2265                 ASSERT_THAT(BarDecl, NotNull());
2266 
2267                 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2268                 ASSERT_THAT(BazDecl, NotNull());
2269 
2270                 const Value *BarVal =
2271                     cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None));
2272                 const Value *BazVal =
2273                     cast<IntegerValue>(Env.getValue(*BazDecl, SkipPast::None));
2274                 EXPECT_EQ(BarVal, BazVal);
2275               });
2276 }
2277 
2278 TEST_F(TransferTest, StaticMemberIntVarDecl) {
2279   std::string Code = R"(
2280     struct A {
2281       static int Foo;
2282     };
2283 
2284     void target(A a) {
2285       int Bar = a.Foo;
2286       int Baz = a.Foo;
2287       // [[p]]
2288     }
2289   )";
2290   runDataflow(Code,
2291               [](llvm::ArrayRef<
2292                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2293                      Results,
2294                  ASTContext &ASTCtx) {
2295                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2296                 const Environment &Env = Results[0].second.Env;
2297 
2298                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2299                 ASSERT_THAT(BarDecl, NotNull());
2300 
2301                 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2302                 ASSERT_THAT(BazDecl, NotNull());
2303 
2304                 const Value *BarVal =
2305                     cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None));
2306                 const Value *BazVal =
2307                     cast<IntegerValue>(Env.getValue(*BazDecl, SkipPast::None));
2308                 EXPECT_EQ(BarVal, BazVal);
2309               });
2310 }
2311 
2312 TEST_F(TransferTest, StaticMemberRefVarDecl) {
2313   std::string Code = R"(
2314     struct A {
2315       static int &Foo;
2316     };
2317 
2318     void target(A a) {
2319       int Bar = a.Foo;
2320       int Baz = a.Foo;
2321       // [[p]]
2322     }
2323   )";
2324   runDataflow(Code,
2325               [](llvm::ArrayRef<
2326                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2327                      Results,
2328                  ASTContext &ASTCtx) {
2329                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2330                 const Environment &Env = Results[0].second.Env;
2331 
2332                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2333                 ASSERT_THAT(BarDecl, NotNull());
2334 
2335                 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2336                 ASSERT_THAT(BazDecl, NotNull());
2337 
2338                 const Value *BarVal =
2339                     cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None));
2340                 const Value *BazVal =
2341                     cast<IntegerValue>(Env.getValue(*BazDecl, SkipPast::None));
2342                 EXPECT_EQ(BarVal, BazVal);
2343               });
2344 }
2345 
2346 TEST_F(TransferTest, AssignMemberBeforeCopy) {
2347   std::string Code = R"(
2348     struct A {
2349       int Foo;
2350     };
2351 
2352     void target() {
2353       A A1;
2354       A A2;
2355       int Bar;
2356       A1.Foo = Bar;
2357       A2 = A1;
2358       // [[p]]
2359     }
2360   )";
2361   runDataflow(Code,
2362               [](llvm::ArrayRef<
2363                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2364                      Results,
2365                  ASTContext &ASTCtx) {
2366                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2367                 const Environment &Env = Results[0].second.Env;
2368 
2369                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2370                 ASSERT_THAT(FooDecl, NotNull());
2371 
2372                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2373                 ASSERT_THAT(BarDecl, NotNull());
2374 
2375                 const ValueDecl *A1Decl = findValueDecl(ASTCtx, "A1");
2376                 ASSERT_THAT(A1Decl, NotNull());
2377 
2378                 const ValueDecl *A2Decl = findValueDecl(ASTCtx, "A2");
2379                 ASSERT_THAT(A2Decl, NotNull());
2380 
2381                 const auto *BarVal =
2382                     cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None));
2383 
2384                 const auto *A2Val =
2385                     cast<StructValue>(Env.getValue(*A2Decl, SkipPast::None));
2386                 EXPECT_EQ(A2Val->getChild(*FooDecl), BarVal);
2387               });
2388 }
2389 
2390 } // namespace
2391