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