xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp (revision 7d941d6d21e91e8466bf200da094d027338b92fa)
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, JoinVarDecl) {
493   std::string Code = R"(
494     void target(bool B) {
495       int Foo;
496       // [[p1]]
497       if (B) {
498         int Bar;
499         // [[p2]]
500       } else {
501         int Baz;
502         // [[p3]]
503       }
504       (void)0;
505       // [[p4]]
506     }
507   )";
508   runDataflow(Code, [](llvm::ArrayRef<std::pair<
509                            std::string, DataflowAnalysisState<NoopLattice>>>
510                            Results,
511                        ASTContext &ASTCtx) {
512     ASSERT_THAT(Results, ElementsAre(Pair("p4", _), Pair("p3", _),
513                                      Pair("p2", _), Pair("p1", _)));
514     const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
515     ASSERT_THAT(FooDecl, NotNull());
516 
517     const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
518     ASSERT_THAT(BarDecl, NotNull());
519 
520     const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
521     ASSERT_THAT(BazDecl, NotNull());
522 
523     const Environment &Env1 = Results[3].second.Env;
524     const StorageLocation *FooLoc =
525         Env1.getStorageLocation(*FooDecl, SkipPast::None);
526     EXPECT_THAT(FooLoc, NotNull());
527     EXPECT_THAT(Env1.getStorageLocation(*BarDecl, SkipPast::None), IsNull());
528     EXPECT_THAT(Env1.getStorageLocation(*BazDecl, SkipPast::None), IsNull());
529 
530     const Environment &Env2 = Results[2].second.Env;
531     EXPECT_EQ(Env2.getStorageLocation(*FooDecl, SkipPast::None), FooLoc);
532     EXPECT_THAT(Env2.getStorageLocation(*BarDecl, SkipPast::None), NotNull());
533     EXPECT_THAT(Env2.getStorageLocation(*BazDecl, SkipPast::None), IsNull());
534 
535     const Environment &Env3 = Results[1].second.Env;
536     EXPECT_EQ(Env3.getStorageLocation(*FooDecl, SkipPast::None), FooLoc);
537     EXPECT_THAT(Env3.getStorageLocation(*BarDecl, SkipPast::None), IsNull());
538     EXPECT_THAT(Env3.getStorageLocation(*BazDecl, SkipPast::None), NotNull());
539 
540     const Environment &Env4 = Results[0].second.Env;
541     EXPECT_EQ(Env4.getStorageLocation(*FooDecl, SkipPast::None), FooLoc);
542     EXPECT_THAT(Env4.getStorageLocation(*BarDecl, SkipPast::None), IsNull());
543     EXPECT_THAT(Env4.getStorageLocation(*BazDecl, SkipPast::None), IsNull());
544   });
545 }
546 
547 TEST_F(TransferTest, BinaryOperatorAssign) {
548   std::string Code = R"(
549     void target() {
550       int Foo;
551       int Bar;
552       (Bar) = (Foo);
553       // [[p]]
554     }
555   )";
556   runDataflow(Code,
557               [](llvm::ArrayRef<
558                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
559                      Results,
560                  ASTContext &ASTCtx) {
561                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
562                 const Environment &Env = Results[0].second.Env;
563 
564                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
565                 ASSERT_THAT(FooDecl, NotNull());
566 
567                 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
568                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
569 
570                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
571                 ASSERT_THAT(BarDecl, NotNull());
572 
573                 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal);
574               });
575 }
576 
577 TEST_F(TransferTest, VarDeclInitAssign) {
578   std::string Code = R"(
579     void target() {
580       int Foo;
581       int Bar = Foo;
582       // [[p]]
583     }
584   )";
585   runDataflow(Code,
586               [](llvm::ArrayRef<
587                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
588                      Results,
589                  ASTContext &ASTCtx) {
590                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
591                 const Environment &Env = Results[0].second.Env;
592 
593                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
594                 ASSERT_THAT(FooDecl, NotNull());
595 
596                 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
597                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
598 
599                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
600                 ASSERT_THAT(BarDecl, NotNull());
601 
602                 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal);
603               });
604 }
605 
606 TEST_F(TransferTest, VarDeclInitAssignChained) {
607   std::string Code = R"(
608     void target() {
609       int Foo;
610       int Bar;
611       int Baz = (Bar = Foo);
612       // [[p]]
613     }
614   )";
615   runDataflow(Code,
616               [](llvm::ArrayRef<
617                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
618                      Results,
619                  ASTContext &ASTCtx) {
620                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
621                 const Environment &Env = Results[0].second.Env;
622 
623                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
624                 ASSERT_THAT(FooDecl, NotNull());
625 
626                 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
627                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
628 
629                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
630                 ASSERT_THAT(BarDecl, NotNull());
631 
632                 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
633                 ASSERT_THAT(BazDecl, NotNull());
634 
635                 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal);
636                 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), FooVal);
637               });
638 }
639 
640 TEST_F(TransferTest, VarDeclInitAssignPtrDeref) {
641   std::string Code = R"(
642     void target() {
643       int Foo;
644       int *Bar;
645       *(Bar) = Foo;
646       int Baz = *(Bar);
647       // [[p]]
648     }
649   )";
650   runDataflow(Code,
651               [](llvm::ArrayRef<
652                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
653                      Results,
654                  ASTContext &ASTCtx) {
655                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
656                 const Environment &Env = Results[0].second.Env;
657 
658                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
659                 ASSERT_THAT(FooDecl, NotNull());
660 
661                 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
662                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
663 
664                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
665                 ASSERT_THAT(BarDecl, NotNull());
666 
667                 const auto *BarVal =
668                     cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None));
669                 EXPECT_EQ(Env.getValue(BarVal->getPointeeLoc()), FooVal);
670 
671                 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
672                 ASSERT_THAT(BazDecl, NotNull());
673 
674                 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), FooVal);
675               });
676 }
677 
678 TEST_F(TransferTest, AssignToAndFromReference) {
679   std::string Code = R"(
680     void target() {
681       int Foo;
682       int Bar;
683       int &Baz = Foo;
684       // [[p1]]
685       Baz = Bar;
686       int Qux = Baz;
687       int &Quux = Baz;
688       // [[p2]]
689     }
690   )";
691   runDataflow(
692       Code, [](llvm::ArrayRef<
693                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
694                    Results,
695                ASTContext &ASTCtx) {
696         ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _)));
697         const Environment &Env1 = Results[0].second.Env;
698         const Environment &Env2 = Results[1].second.Env;
699 
700         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
701         ASSERT_THAT(FooDecl, NotNull());
702 
703         const Value *FooVal = Env1.getValue(*FooDecl, SkipPast::None);
704         ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
705 
706         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
707         ASSERT_THAT(BarDecl, NotNull());
708 
709         const Value *BarVal = Env1.getValue(*BarDecl, SkipPast::None);
710         ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
711 
712         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
713         ASSERT_THAT(BazDecl, NotNull());
714 
715         EXPECT_EQ(Env1.getValue(*BazDecl, SkipPast::Reference), FooVal);
716 
717         EXPECT_EQ(Env2.getValue(*BazDecl, SkipPast::Reference), BarVal);
718         EXPECT_EQ(Env2.getValue(*FooDecl, SkipPast::None), BarVal);
719 
720         const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
721         ASSERT_THAT(QuxDecl, NotNull());
722         EXPECT_EQ(Env2.getValue(*QuxDecl, SkipPast::None), BarVal);
723 
724         const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
725         ASSERT_THAT(QuuxDecl, NotNull());
726         EXPECT_EQ(Env2.getValue(*QuuxDecl, SkipPast::Reference), BarVal);
727       });
728 }
729 
730 TEST_F(TransferTest, MultipleParamDecls) {
731   std::string Code = R"(
732     void target(int Foo, int Bar) {
733       (void)0;
734       // [[p]]
735     }
736   )";
737   runDataflow(Code,
738               [](llvm::ArrayRef<
739                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
740                      Results,
741                  ASTContext &ASTCtx) {
742                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
743                 const Environment &Env = Results[0].second.Env;
744 
745                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
746                 ASSERT_THAT(FooDecl, NotNull());
747 
748                 const StorageLocation *FooLoc =
749                     Env.getStorageLocation(*FooDecl, SkipPast::None);
750                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
751 
752                 const Value *FooVal = Env.getValue(*FooLoc);
753                 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
754 
755                 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
756                 ASSERT_THAT(BarDecl, NotNull());
757 
758                 const StorageLocation *BarLoc =
759                     Env.getStorageLocation(*BarDecl, SkipPast::None);
760                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
761 
762                 const Value *BarVal = Env.getValue(*BarLoc);
763                 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
764               });
765 }
766 
767 TEST_F(TransferTest, StructParamDecl) {
768   std::string Code = R"(
769     struct A {
770       int Bar;
771     };
772 
773     void target(A Foo) {
774       (void)0;
775       // [[p]]
776     }
777   )";
778   runDataflow(
779       Code, [](llvm::ArrayRef<
780                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
781                    Results,
782                ASTContext &ASTCtx) {
783         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
784         const Environment &Env = Results[0].second.Env;
785 
786         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
787         ASSERT_THAT(FooDecl, NotNull());
788 
789         ASSERT_TRUE(FooDecl->getType()->isStructureType());
790         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
791 
792         FieldDecl *BarDecl = nullptr;
793         for (FieldDecl *Field : FooFields) {
794           if (Field->getNameAsString() == "Bar") {
795             BarDecl = Field;
796           } else {
797             FAIL() << "Unexpected field: " << Field->getNameAsString();
798           }
799         }
800         ASSERT_THAT(BarDecl, NotNull());
801 
802         const auto *FooLoc = cast<AggregateStorageLocation>(
803             Env.getStorageLocation(*FooDecl, SkipPast::None));
804         const auto *BarLoc =
805             cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
806 
807         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
808         const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl));
809         EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
810       });
811 }
812 
813 TEST_F(TransferTest, ReferenceParamDecl) {
814   std::string Code = R"(
815     struct A {};
816 
817     void target(A &Foo) {
818       (void)0;
819       // [[p]]
820     }
821   )";
822   runDataflow(Code,
823               [](llvm::ArrayRef<
824                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
825                      Results,
826                  ASTContext &ASTCtx) {
827                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
828                 const Environment &Env = Results[0].second.Env;
829 
830                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
831                 ASSERT_THAT(FooDecl, NotNull());
832 
833                 const StorageLocation *FooLoc =
834                     Env.getStorageLocation(*FooDecl, SkipPast::None);
835                 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
836 
837                 const ReferenceValue *FooVal =
838                     dyn_cast<ReferenceValue>(Env.getValue(*FooLoc));
839                 ASSERT_THAT(FooVal, NotNull());
840 
841                 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
842                 EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc));
843 
844                 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
845                 EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal));
846               });
847 }
848 
849 TEST_F(TransferTest, PointerParamDecl) {
850   std::string Code = R"(
851     struct A {};
852 
853     void target(A *Foo) {
854       (void)0;
855       // [[p]]
856     }
857   )";
858   runDataflow(
859       Code, [](llvm::ArrayRef<
860                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
861                    Results,
862                ASTContext &ASTCtx) {
863         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
864         const Environment &Env = Results[0].second.Env;
865 
866         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
867         ASSERT_THAT(FooDecl, NotNull());
868 
869         const StorageLocation *FooLoc =
870             Env.getStorageLocation(*FooDecl, SkipPast::None);
871         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
872 
873         const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));
874         const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
875         EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc));
876 
877         const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
878         EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal));
879       });
880 }
881 
882 TEST_F(TransferTest, StructMember) {
883   std::string Code = R"(
884     struct A {
885       int Bar;
886     };
887 
888     void target(A Foo) {
889       int Baz = Foo.Bar;
890       // [[p]]
891     }
892   )";
893   runDataflow(
894       Code, [](llvm::ArrayRef<
895                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
896                    Results,
897                ASTContext &ASTCtx) {
898         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
899         const Environment &Env = Results[0].second.Env;
900 
901         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
902         ASSERT_THAT(FooDecl, NotNull());
903 
904         ASSERT_TRUE(FooDecl->getType()->isStructureType());
905         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
906 
907         FieldDecl *BarDecl = nullptr;
908         for (FieldDecl *Field : FooFields) {
909           if (Field->getNameAsString() == "Bar") {
910             BarDecl = Field;
911           } else {
912             FAIL() << "Unexpected field: " << Field->getNameAsString();
913           }
914         }
915         ASSERT_THAT(BarDecl, NotNull());
916 
917         const auto *FooLoc = cast<AggregateStorageLocation>(
918             Env.getStorageLocation(*FooDecl, SkipPast::None));
919         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
920         const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl));
921 
922         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
923         ASSERT_THAT(BazDecl, NotNull());
924 
925         EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarVal);
926       });
927 }
928 
929 TEST_F(TransferTest, ClassMember) {
930   std::string Code = R"(
931     class A {
932     public:
933       int Bar;
934     };
935 
936     void target(A Foo) {
937       int Baz = Foo.Bar;
938       // [[p]]
939     }
940   )";
941   runDataflow(
942       Code, [](llvm::ArrayRef<
943                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
944                    Results,
945                ASTContext &ASTCtx) {
946         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
947         const Environment &Env = Results[0].second.Env;
948 
949         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
950         ASSERT_THAT(FooDecl, NotNull());
951 
952         ASSERT_TRUE(FooDecl->getType()->isClassType());
953         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
954 
955         FieldDecl *BarDecl = nullptr;
956         for (FieldDecl *Field : FooFields) {
957           if (Field->getNameAsString() == "Bar") {
958             BarDecl = Field;
959           } else {
960             FAIL() << "Unexpected field: " << Field->getNameAsString();
961           }
962         }
963         ASSERT_THAT(BarDecl, NotNull());
964 
965         const auto *FooLoc = cast<AggregateStorageLocation>(
966             Env.getStorageLocation(*FooDecl, SkipPast::None));
967         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
968         const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl));
969 
970         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
971         ASSERT_THAT(BazDecl, NotNull());
972 
973         EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarVal);
974       });
975 }
976 
977 TEST_F(TransferTest, ReferenceMember) {
978   std::string Code = R"(
979     struct A {
980       int &Bar;
981     };
982 
983     void target(A Foo) {
984       int Baz = Foo.Bar;
985       // [[p]]
986     }
987   )";
988   runDataflow(
989       Code, [](llvm::ArrayRef<
990                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
991                    Results,
992                ASTContext &ASTCtx) {
993         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
994         const Environment &Env = Results[0].second.Env;
995 
996         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
997         ASSERT_THAT(FooDecl, NotNull());
998 
999         ASSERT_TRUE(FooDecl->getType()->isStructureType());
1000         auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1001 
1002         FieldDecl *BarDecl = nullptr;
1003         for (FieldDecl *Field : FooFields) {
1004           if (Field->getNameAsString() == "Bar") {
1005             BarDecl = Field;
1006           } else {
1007             FAIL() << "Unexpected field: " << Field->getNameAsString();
1008           }
1009         }
1010         ASSERT_THAT(BarDecl, NotNull());
1011 
1012         const auto *FooLoc = cast<AggregateStorageLocation>(
1013             Env.getStorageLocation(*FooDecl, SkipPast::None));
1014         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1015         const auto *BarVal = cast<ReferenceValue>(&FooVal->getChild(*BarDecl));
1016         const auto *BarPointeeVal =
1017             cast<IntegerValue>(Env.getValue(BarVal->getPointeeLoc()));
1018 
1019         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1020         ASSERT_THAT(BazDecl, NotNull());
1021 
1022         EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarPointeeVal);
1023       });
1024 }
1025 
1026 TEST_F(TransferTest, StructThisMember) {
1027   std::string Code = R"(
1028     struct A {
1029       int Bar;
1030 
1031       struct B {
1032         int Baz;
1033       };
1034 
1035       B Qux;
1036 
1037       void target() {
1038         int Foo = Bar;
1039         int Quux = Qux.Baz;
1040         // [[p]]
1041       }
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 auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1053             Env.getThisPointeeStorageLocation());
1054         ASSERT_THAT(ThisLoc, NotNull());
1055 
1056         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1057         ASSERT_THAT(BarDecl, NotNull());
1058 
1059         const auto *BarLoc =
1060             cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl));
1061         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1062 
1063         const Value *BarVal = Env.getValue(*BarLoc);
1064         ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1065 
1066         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1067         ASSERT_THAT(FooDecl, NotNull());
1068         EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal);
1069 
1070         const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1071         ASSERT_THAT(QuxDecl, NotNull());
1072 
1073         ASSERT_TRUE(QuxDecl->getType()->isStructureType());
1074         auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields();
1075 
1076         FieldDecl *BazDecl = nullptr;
1077         for (FieldDecl *Field : QuxFields) {
1078           if (Field->getNameAsString() == "Baz") {
1079             BazDecl = Field;
1080           } else {
1081             FAIL() << "Unexpected field: " << Field->getNameAsString();
1082           }
1083         }
1084         ASSERT_THAT(BazDecl, NotNull());
1085 
1086         const auto *QuxLoc =
1087             cast<AggregateStorageLocation>(&ThisLoc->getChild(*QuxDecl));
1088         const auto *QuxVal = dyn_cast<StructValue>(Env.getValue(*QuxLoc));
1089         ASSERT_THAT(QuxVal, NotNull());
1090 
1091         const auto *BazLoc =
1092             cast<ScalarStorageLocation>(&QuxLoc->getChild(*BazDecl));
1093         const auto *BazVal = cast<IntegerValue>(&QuxVal->getChild(*BazDecl));
1094         EXPECT_EQ(Env.getValue(*BazLoc), BazVal);
1095 
1096         const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
1097         ASSERT_THAT(QuuxDecl, NotNull());
1098         EXPECT_EQ(Env.getValue(*QuuxDecl, SkipPast::None), BazVal);
1099       });
1100 }
1101 
1102 TEST_F(TransferTest, ClassThisMember) {
1103   std::string Code = R"(
1104     class A {
1105       int Bar;
1106 
1107       class B {
1108       public:
1109         int Baz;
1110       };
1111 
1112       B Qux;
1113 
1114       void target() {
1115         int Foo = Bar;
1116         int Quux = Qux.Baz;
1117         // [[p]]
1118       }
1119     };
1120   )";
1121   runDataflow(
1122       Code, [](llvm::ArrayRef<
1123                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1124                    Results,
1125                ASTContext &ASTCtx) {
1126         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1127         const Environment &Env = Results[0].second.Env;
1128 
1129         const auto *ThisLoc =
1130             cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation());
1131 
1132         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1133         ASSERT_THAT(BarDecl, NotNull());
1134 
1135         const auto *BarLoc =
1136             cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl));
1137         ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1138 
1139         const Value *BarVal = Env.getValue(*BarLoc);
1140         ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1141 
1142         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1143         ASSERT_THAT(FooDecl, NotNull());
1144         EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal);
1145 
1146         const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1147         ASSERT_THAT(QuxDecl, NotNull());
1148 
1149         ASSERT_TRUE(QuxDecl->getType()->isClassType());
1150         auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields();
1151 
1152         FieldDecl *BazDecl = nullptr;
1153         for (FieldDecl *Field : QuxFields) {
1154           if (Field->getNameAsString() == "Baz") {
1155             BazDecl = Field;
1156           } else {
1157             FAIL() << "Unexpected field: " << Field->getNameAsString();
1158           }
1159         }
1160         ASSERT_THAT(BazDecl, NotNull());
1161 
1162         const auto *QuxLoc =
1163             cast<AggregateStorageLocation>(&ThisLoc->getChild(*QuxDecl));
1164         const auto *QuxVal = dyn_cast<StructValue>(Env.getValue(*QuxLoc));
1165         ASSERT_THAT(QuxVal, NotNull());
1166 
1167         const auto *BazLoc =
1168             cast<ScalarStorageLocation>(&QuxLoc->getChild(*BazDecl));
1169         const auto *BazVal = cast<IntegerValue>(&QuxVal->getChild(*BazDecl));
1170         EXPECT_EQ(Env.getValue(*BazLoc), BazVal);
1171 
1172         const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
1173         ASSERT_THAT(QuuxDecl, NotNull());
1174         EXPECT_EQ(Env.getValue(*QuuxDecl, SkipPast::None), BazVal);
1175       });
1176 }
1177 
1178 TEST_F(TransferTest, ConstructorInitializer) {
1179   std::string Code = R"(
1180     struct target {
1181       int Bar;
1182 
1183       target(int Foo) : Bar(Foo) {
1184         int Qux = Bar;
1185         // [[p]]
1186       }
1187     };
1188   )";
1189   runDataflow(Code,
1190               [](llvm::ArrayRef<
1191                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1192                      Results,
1193                  ASTContext &ASTCtx) {
1194                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1195                 const Environment &Env = Results[0].second.Env;
1196 
1197                 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1198                     Env.getThisPointeeStorageLocation());
1199                 ASSERT_THAT(ThisLoc, NotNull());
1200 
1201                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1202                 ASSERT_THAT(FooDecl, NotNull());
1203 
1204                 const auto *FooVal =
1205                     cast<IntegerValue>(Env.getValue(*FooDecl, SkipPast::None));
1206 
1207                 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1208                 ASSERT_THAT(QuxDecl, NotNull());
1209                 EXPECT_EQ(Env.getValue(*QuxDecl, SkipPast::None), FooVal);
1210               });
1211 }
1212 
1213 TEST_F(TransferTest, DefaultInitializer) {
1214   std::string Code = R"(
1215     struct target {
1216       int Bar;
1217       int Baz = Bar;
1218 
1219       target(int Foo) : Bar(Foo) {
1220         int Qux = Baz;
1221         // [[p]]
1222       }
1223     };
1224   )";
1225   runDataflow(Code,
1226               [](llvm::ArrayRef<
1227                      std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1228                      Results,
1229                  ASTContext &ASTCtx) {
1230                 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1231                 const Environment &Env = Results[0].second.Env;
1232 
1233                 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1234                     Env.getThisPointeeStorageLocation());
1235                 ASSERT_THAT(ThisLoc, NotNull());
1236 
1237                 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1238                 ASSERT_THAT(FooDecl, NotNull());
1239 
1240                 const auto *FooVal =
1241                     cast<IntegerValue>(Env.getValue(*FooDecl, SkipPast::None));
1242 
1243                 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1244                 ASSERT_THAT(QuxDecl, NotNull());
1245                 EXPECT_EQ(Env.getValue(*QuxDecl, SkipPast::None), FooVal);
1246               });
1247 }
1248 
1249 TEST_F(TransferTest, DefaultInitializerReference) {
1250   std::string Code = R"(
1251     struct target {
1252       int &Bar;
1253       int &Baz = Bar;
1254 
1255       target(int &Foo) : Bar(Foo) {
1256         int &Qux = Baz;
1257         // [[p]]
1258       }
1259     };
1260   )";
1261   runDataflow(
1262       Code, [](llvm::ArrayRef<
1263                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1264                    Results,
1265                ASTContext &ASTCtx) {
1266         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1267         const Environment &Env = Results[0].second.Env;
1268 
1269         const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1270             Env.getThisPointeeStorageLocation());
1271         ASSERT_THAT(ThisLoc, NotNull());
1272 
1273         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1274         ASSERT_THAT(FooDecl, NotNull());
1275 
1276         const auto *FooVal =
1277             cast<ReferenceValue>(Env.getValue(*FooDecl, SkipPast::None));
1278 
1279         const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1280         ASSERT_THAT(QuxDecl, NotNull());
1281 
1282         const auto *QuxVal =
1283             cast<ReferenceValue>(Env.getValue(*QuxDecl, SkipPast::None));
1284         EXPECT_EQ(&QuxVal->getPointeeLoc(), &FooVal->getPointeeLoc());
1285       });
1286 }
1287 
1288 TEST_F(TransferTest, TemporaryObject) {
1289   std::string Code = R"(
1290     struct A {
1291       int Bar;
1292     };
1293 
1294     void target() {
1295       A Foo = A();
1296       // [[p]]
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 ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1308         ASSERT_THAT(FooDecl, NotNull());
1309 
1310         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1311         ASSERT_THAT(BarDecl, NotNull());
1312 
1313         const auto *FooLoc = cast<AggregateStorageLocation>(
1314             Env.getStorageLocation(*FooDecl, SkipPast::None));
1315         const auto *BarLoc =
1316             cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
1317 
1318         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1319         const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl));
1320         EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
1321       });
1322 }
1323 
1324 TEST_F(TransferTest, ElidableConstructor) {
1325   // This test is effectively the same as TransferTest.TemporaryObject, but
1326   // the code is compiled as C++ 14.
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,
1339       [](llvm::ArrayRef<
1340              std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1341              Results,
1342          ASTContext &ASTCtx) {
1343         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1344         const Environment &Env = Results[0].second.Env;
1345 
1346         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1347         ASSERT_THAT(FooDecl, NotNull());
1348 
1349         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1350         ASSERT_THAT(BarDecl, NotNull());
1351 
1352         const auto *FooLoc = cast<AggregateStorageLocation>(
1353             Env.getStorageLocation(*FooDecl, SkipPast::None));
1354         const auto *BarLoc =
1355             cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
1356 
1357         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1358         const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl));
1359         EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
1360       },
1361       LangStandard::lang_cxx14);
1362 }
1363 
1364 TEST_F(TransferTest, AssignmentOperator) {
1365   std::string Code = R"(
1366     struct A {
1367       int Baz;
1368     };
1369 
1370     void target() {
1371       A Foo;
1372       A Bar;
1373       // [[p1]]
1374       Foo = Bar;
1375       // [[p2]]
1376     }
1377   )";
1378   runDataflow(
1379       Code, [](llvm::ArrayRef<
1380                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1381                    Results,
1382                ASTContext &ASTCtx) {
1383         ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _)));
1384         const Environment &Env1 = Results[0].second.Env;
1385         const Environment &Env2 = Results[1].second.Env;
1386 
1387         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1388         ASSERT_THAT(FooDecl, NotNull());
1389 
1390         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1391         ASSERT_THAT(BarDecl, NotNull());
1392 
1393         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1394         ASSERT_THAT(BazDecl, NotNull());
1395 
1396         const auto *FooLoc1 = cast<AggregateStorageLocation>(
1397             Env1.getStorageLocation(*FooDecl, SkipPast::None));
1398         const auto *BarLoc1 = cast<AggregateStorageLocation>(
1399             Env1.getStorageLocation(*BarDecl, SkipPast::None));
1400 
1401         const auto *FooVal1 = cast<StructValue>(Env1.getValue(*FooLoc1));
1402         const auto *BarVal1 = cast<StructValue>(Env1.getValue(*BarLoc1));
1403         EXPECT_NE(FooVal1, BarVal1);
1404 
1405         const auto *FooBazVal1 =
1406             cast<IntegerValue>(Env1.getValue(FooLoc1->getChild(*BazDecl)));
1407         const auto *BarBazVal1 =
1408             cast<IntegerValue>(Env1.getValue(BarLoc1->getChild(*BazDecl)));
1409         EXPECT_NE(FooBazVal1, BarBazVal1);
1410 
1411         const auto *FooLoc2 = cast<AggregateStorageLocation>(
1412             Env2.getStorageLocation(*FooDecl, SkipPast::None));
1413         const auto *BarLoc2 = cast<AggregateStorageLocation>(
1414             Env2.getStorageLocation(*BarDecl, SkipPast::None));
1415 
1416         const auto *FooVal2 = cast<StructValue>(Env2.getValue(*FooLoc2));
1417         const auto *BarVal2 = cast<StructValue>(Env2.getValue(*BarLoc2));
1418         EXPECT_EQ(FooVal2, BarVal2);
1419 
1420         const auto *FooBazVal2 =
1421             cast<IntegerValue>(Env2.getValue(FooLoc1->getChild(*BazDecl)));
1422         const auto *BarBazVal2 =
1423             cast<IntegerValue>(Env2.getValue(BarLoc1->getChild(*BazDecl)));
1424         EXPECT_EQ(FooBazVal2, BarBazVal2);
1425       });
1426 }
1427 
1428 TEST_F(TransferTest, CopyConstructor) {
1429   std::string Code = R"(
1430     struct A {
1431       int Baz;
1432     };
1433 
1434     void target() {
1435       A Foo;
1436       A Bar = Foo;
1437       // [[p]]
1438     }
1439   )";
1440   runDataflow(
1441       Code, [](llvm::ArrayRef<
1442                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1443                    Results,
1444                ASTContext &ASTCtx) {
1445         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1446         const Environment &Env = Results[0].second.Env;
1447 
1448         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1449         ASSERT_THAT(FooDecl, NotNull());
1450 
1451         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1452         ASSERT_THAT(BarDecl, NotNull());
1453 
1454         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1455         ASSERT_THAT(BazDecl, NotNull());
1456 
1457         const auto *FooLoc = cast<AggregateStorageLocation>(
1458             Env.getStorageLocation(*FooDecl, SkipPast::None));
1459         const auto *BarLoc = cast<AggregateStorageLocation>(
1460             Env.getStorageLocation(*BarDecl, SkipPast::None));
1461 
1462         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1463         const auto *BarVal = cast<StructValue>(Env.getValue(*BarLoc));
1464         EXPECT_EQ(FooVal, BarVal);
1465 
1466         const auto *FooBazVal =
1467             cast<IntegerValue>(Env.getValue(FooLoc->getChild(*BazDecl)));
1468         const auto *BarBazVal =
1469             cast<IntegerValue>(Env.getValue(BarLoc->getChild(*BazDecl)));
1470         EXPECT_EQ(FooBazVal, BarBazVal);
1471       });
1472 }
1473 
1474 TEST_F(TransferTest, CopyConstructorWithParens) {
1475   std::string Code = R"(
1476     struct A {
1477       int Baz;
1478     };
1479 
1480     void target() {
1481       A Foo;
1482       A Bar((A(Foo)));
1483       // [[p]]
1484     }
1485   )";
1486   runDataflow(
1487       Code, [](llvm::ArrayRef<
1488                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1489                    Results,
1490                ASTContext &ASTCtx) {
1491         ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1492         const Environment &Env = Results[0].second.Env;
1493 
1494         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1495         ASSERT_THAT(FooDecl, NotNull());
1496 
1497         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1498         ASSERT_THAT(BarDecl, NotNull());
1499 
1500         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1501         ASSERT_THAT(BazDecl, NotNull());
1502 
1503         const auto *FooLoc = cast<AggregateStorageLocation>(
1504             Env.getStorageLocation(*FooDecl, SkipPast::None));
1505         const auto *BarLoc = cast<AggregateStorageLocation>(
1506             Env.getStorageLocation(*BarDecl, SkipPast::None));
1507 
1508         const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1509         const auto *BarVal = cast<StructValue>(Env.getValue(*BarLoc));
1510         EXPECT_EQ(FooVal, BarVal);
1511 
1512         const auto *FooBazVal =
1513             cast<IntegerValue>(Env.getValue(FooLoc->getChild(*BazDecl)));
1514         const auto *BarBazVal =
1515             cast<IntegerValue>(Env.getValue(BarLoc->getChild(*BazDecl)));
1516         EXPECT_EQ(FooBazVal, BarBazVal);
1517       });
1518 }
1519 
1520 TEST_F(TransferTest, MoveConstructor) {
1521   std::string Code = R"(
1522     namespace std {
1523 
1524     template <typename T> struct remove_reference      { using type = T; };
1525     template <typename T> struct remove_reference<T&>  { using type = T; };
1526     template <typename T> struct remove_reference<T&&> { using type = T; };
1527 
1528     template <typename T>
1529     using remove_reference_t = typename remove_reference<T>::type;
1530 
1531     template <typename T>
1532     std::remove_reference_t<T>&& move(T&& x);
1533 
1534     } // namespace std
1535 
1536     struct A {
1537       int Baz;
1538     };
1539 
1540     void target() {
1541       A Foo;
1542       A Bar;
1543       // [[p1]]
1544       Foo = std::move(Bar);
1545       // [[p2]]
1546     }
1547   )";
1548   runDataflow(
1549       Code, [](llvm::ArrayRef<
1550                    std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1551                    Results,
1552                ASTContext &ASTCtx) {
1553         ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _)));
1554         const Environment &Env1 = Results[0].second.Env;
1555         const Environment &Env2 = Results[1].second.Env;
1556 
1557         const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1558         ASSERT_THAT(FooDecl, NotNull());
1559 
1560         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1561         ASSERT_THAT(BarDecl, NotNull());
1562 
1563         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1564         ASSERT_THAT(BazDecl, NotNull());
1565 
1566         const auto *FooLoc1 = cast<AggregateStorageLocation>(
1567             Env1.getStorageLocation(*FooDecl, SkipPast::None));
1568         const auto *BarLoc1 = cast<AggregateStorageLocation>(
1569             Env1.getStorageLocation(*BarDecl, SkipPast::None));
1570 
1571         const auto *FooVal1 = cast<StructValue>(Env1.getValue(*FooLoc1));
1572         const auto *BarVal1 = cast<StructValue>(Env1.getValue(*BarLoc1));
1573         EXPECT_NE(FooVal1, BarVal1);
1574 
1575         const auto *FooBazVal1 =
1576             cast<IntegerValue>(Env1.getValue(FooLoc1->getChild(*BazDecl)));
1577         const auto *BarBazVal1 =
1578             cast<IntegerValue>(Env1.getValue(BarLoc1->getChild(*BazDecl)));
1579         EXPECT_NE(FooBazVal1, BarBazVal1);
1580 
1581         const auto *FooLoc2 = cast<AggregateStorageLocation>(
1582             Env2.getStorageLocation(*FooDecl, SkipPast::None));
1583         const auto *FooVal2 = cast<StructValue>(Env2.getValue(*FooLoc2));
1584         EXPECT_EQ(FooVal2, BarVal1);
1585 
1586         const auto *FooBazVal2 =
1587             cast<IntegerValue>(Env2.getValue(FooLoc1->getChild(*BazDecl)));
1588         EXPECT_EQ(FooBazVal2, BarBazVal1);
1589       });
1590 }
1591 
1592 } // namespace
1593