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