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