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 "TestingSupport.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/Decl.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/ASTMatchers/ASTMatchers.h"
14 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
15 #include "clang/Analysis/FlowSensitive/NoopAnalysis.h"
16 #include "clang/Analysis/FlowSensitive/StorageLocation.h"
17 #include "clang/Analysis/FlowSensitive/Value.h"
18 #include "clang/Basic/LangStandard.h"
19 #include "llvm/ADT/ArrayRef.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/Support/Casting.h"
22 #include "llvm/Testing/Support/Error.h"
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include <string>
26 #include <utility>
27
28 namespace {
29
30 using namespace clang;
31 using namespace dataflow;
32 using namespace test;
33 using ::testing::_;
34 using ::testing::ElementsAre;
35 using ::testing::IsNull;
36 using ::testing::NotNull;
37 using ::testing::Pair;
38 using ::testing::SizeIs;
39
40 template <typename Matcher>
runDataflow(llvm::StringRef Code,Matcher Match,DataflowAnalysisOptions Options,LangStandard::Kind Std=LangStandard::lang_cxx17,llvm::StringRef TargetFun="target")41 void runDataflow(llvm::StringRef Code, Matcher Match,
42 DataflowAnalysisOptions Options,
43 LangStandard::Kind Std = LangStandard::lang_cxx17,
44 llvm::StringRef TargetFun = "target") {
45 ASSERT_THAT_ERROR(
46 test::checkDataflow<NoopAnalysis>(
47 Code, TargetFun,
48 [Options](ASTContext &C, Environment &) {
49 return NoopAnalysis(C, Options);
50 },
51 [&Match](
52 llvm::ArrayRef<
53 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
54 Results,
55 ASTContext &ASTCtx) { Match(Results, ASTCtx); },
56 {"-fsyntax-only", "-fno-delayed-template-parsing",
57 "-std=" + std::string(
58 LangStandard::getLangStandardForKind(Std).getName())}),
59 llvm::Succeeded());
60 }
61
62 template <typename Matcher>
runDataflow(llvm::StringRef Code,Matcher Match,LangStandard::Kind Std=LangStandard::lang_cxx17,bool ApplyBuiltinTransfer=true,llvm::StringRef TargetFun="target")63 void runDataflow(llvm::StringRef Code, Matcher Match,
64 LangStandard::Kind Std = LangStandard::lang_cxx17,
65 bool ApplyBuiltinTransfer = true,
66 llvm::StringRef TargetFun = "target") {
67 runDataflow(Code, Match, {ApplyBuiltinTransfer, {}}, Std, TargetFun);
68 }
69
TEST(TransferTest,IntVarDeclNotTrackedWhenTransferDisabled)70 TEST(TransferTest, IntVarDeclNotTrackedWhenTransferDisabled) {
71 std::string Code = R"(
72 void target() {
73 int Foo;
74 // [[p]]
75 }
76 )";
77 runDataflow(
78 Code,
79 [](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 EXPECT_EQ(Env.getStorageLocation(*FooDecl, SkipPast::None), nullptr);
90 },
91 LangStandard::lang_cxx17,
92 /*ApplyBuiltinTransfer=*/false);
93 }
94
TEST(TransferTest,BoolVarDecl)95 TEST(TransferTest, BoolVarDecl) {
96 std::string Code = R"(
97 void target() {
98 bool Foo;
99 // [[p]]
100 }
101 )";
102 runDataflow(Code,
103 [](llvm::ArrayRef<
104 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
105 Results,
106 ASTContext &ASTCtx) {
107 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
108 const Environment &Env = Results[0].second.Env;
109
110 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
111 ASSERT_THAT(FooDecl, NotNull());
112
113 const StorageLocation *FooLoc =
114 Env.getStorageLocation(*FooDecl, SkipPast::None);
115 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
116
117 const Value *FooVal = Env.getValue(*FooLoc);
118 EXPECT_TRUE(isa_and_nonnull<BoolValue>(FooVal));
119 });
120 }
121
TEST(TransferTest,IntVarDecl)122 TEST(TransferTest, IntVarDecl) {
123 std::string Code = R"(
124 void target() {
125 int Foo;
126 // [[p]]
127 }
128 )";
129 runDataflow(Code,
130 [](llvm::ArrayRef<
131 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
132 Results,
133 ASTContext &ASTCtx) {
134 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
135 const Environment &Env = Results[0].second.Env;
136
137 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
138 ASSERT_THAT(FooDecl, NotNull());
139
140 const StorageLocation *FooLoc =
141 Env.getStorageLocation(*FooDecl, SkipPast::None);
142 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
143
144 const Value *FooVal = Env.getValue(*FooLoc);
145 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
146 });
147 }
148
TEST(TransferTest,StructVarDecl)149 TEST(TransferTest, StructVarDecl) {
150 std::string Code = R"(
151 struct A {
152 int Bar;
153 };
154
155 void target() {
156 A Foo;
157 // [[p]]
158 }
159 )";
160 runDataflow(
161 Code, [](llvm::ArrayRef<
162 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
163 Results,
164 ASTContext &ASTCtx) {
165 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
166 const Environment &Env = Results[0].second.Env;
167
168 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
169 ASSERT_THAT(FooDecl, NotNull());
170
171 ASSERT_TRUE(FooDecl->getType()->isStructureType());
172 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
173
174 FieldDecl *BarDecl = nullptr;
175 for (FieldDecl *Field : FooFields) {
176 if (Field->getNameAsString() == "Bar") {
177 BarDecl = Field;
178 } else {
179 FAIL() << "Unexpected field: " << Field->getNameAsString();
180 }
181 }
182 ASSERT_THAT(BarDecl, NotNull());
183
184 const auto *FooLoc = cast<AggregateStorageLocation>(
185 Env.getStorageLocation(*FooDecl, SkipPast::None));
186 const auto *BarLoc =
187 cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
188
189 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
190 const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl));
191 EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
192 });
193 }
194
TEST(TransferTest,StructVarDeclWithInit)195 TEST(TransferTest, StructVarDeclWithInit) {
196 std::string Code = R"(
197 struct A {
198 int Bar;
199 };
200
201 A Gen();
202
203 void target() {
204 A Foo = Gen();
205 // [[p]]
206 }
207 )";
208 runDataflow(
209 Code, [](llvm::ArrayRef<
210 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
211 Results,
212 ASTContext &ASTCtx) {
213 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
214 const Environment &Env = Results[0].second.Env;
215
216 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
217 ASSERT_THAT(FooDecl, NotNull());
218
219 ASSERT_TRUE(FooDecl->getType()->isStructureType());
220 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
221
222 FieldDecl *BarDecl = nullptr;
223 for (FieldDecl *Field : FooFields) {
224 if (Field->getNameAsString() == "Bar") {
225 BarDecl = Field;
226 } else {
227 FAIL() << "Unexpected field: " << Field->getNameAsString();
228 }
229 }
230 ASSERT_THAT(BarDecl, NotNull());
231
232 const auto *FooLoc = cast<AggregateStorageLocation>(
233 Env.getStorageLocation(*FooDecl, SkipPast::None));
234 const auto *BarLoc =
235 cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
236
237 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
238 const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl));
239 EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
240 });
241 }
242
TEST(TransferTest,ClassVarDecl)243 TEST(TransferTest, ClassVarDecl) {
244 std::string Code = R"(
245 class A {
246 int Bar;
247 };
248
249 void target() {
250 A Foo;
251 // [[p]]
252 }
253 )";
254 runDataflow(
255 Code, [](llvm::ArrayRef<
256 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
257 Results,
258 ASTContext &ASTCtx) {
259 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
260 const Environment &Env = Results[0].second.Env;
261
262 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
263 ASSERT_THAT(FooDecl, NotNull());
264
265 ASSERT_TRUE(FooDecl->getType()->isClassType());
266 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
267
268 FieldDecl *BarDecl = nullptr;
269 for (FieldDecl *Field : FooFields) {
270 if (Field->getNameAsString() == "Bar") {
271 BarDecl = Field;
272 } else {
273 FAIL() << "Unexpected field: " << Field->getNameAsString();
274 }
275 }
276 ASSERT_THAT(BarDecl, NotNull());
277
278 const auto *FooLoc = cast<AggregateStorageLocation>(
279 Env.getStorageLocation(*FooDecl, SkipPast::None));
280 const auto *BarLoc =
281 cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
282
283 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
284 const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl));
285 EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
286 });
287 }
288
TEST(TransferTest,ReferenceVarDecl)289 TEST(TransferTest, ReferenceVarDecl) {
290 std::string Code = R"(
291 struct A {};
292
293 A &getA();
294
295 void target() {
296 A &Foo = getA();
297 // [[p]]
298 }
299 )";
300 runDataflow(
301 Code, [](llvm::ArrayRef<
302 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
303 Results,
304 ASTContext &ASTCtx) {
305 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
306 const Environment &Env = Results[0].second.Env;
307
308 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
309 ASSERT_THAT(FooDecl, NotNull());
310
311 const StorageLocation *FooLoc =
312 Env.getStorageLocation(*FooDecl, SkipPast::None);
313 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
314
315 const ReferenceValue *FooVal =
316 cast<ReferenceValue>(Env.getValue(*FooLoc));
317 const StorageLocation &FooReferentLoc = FooVal->getReferentLoc();
318 EXPECT_TRUE(isa<AggregateStorageLocation>(&FooReferentLoc));
319
320 const Value *FooReferentVal = Env.getValue(FooReferentLoc);
321 EXPECT_TRUE(isa_and_nonnull<StructValue>(FooReferentVal));
322 });
323 }
324
TEST(TransferTest,SelfReferentialReferenceVarDecl)325 TEST(TransferTest, SelfReferentialReferenceVarDecl) {
326 std::string Code = R"(
327 struct A;
328
329 struct B {};
330
331 struct C {
332 A &FooRef;
333 A *FooPtr;
334 B &BazRef;
335 B *BazPtr;
336 };
337
338 struct A {
339 C &Bar;
340 };
341
342 A &getA();
343
344 void target() {
345 A &Foo = getA();
346 // [[p]]
347 }
348 )";
349 runDataflow(Code, [](llvm::ArrayRef<std::pair<
350 std::string, DataflowAnalysisState<NoopLattice>>>
351 Results,
352 ASTContext &ASTCtx) {
353 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
354 const Environment &Env = Results[0].second.Env;
355
356 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
357 ASSERT_THAT(FooDecl, NotNull());
358
359 ASSERT_TRUE(FooDecl->getType()->isReferenceType());
360 ASSERT_TRUE(FooDecl->getType().getNonReferenceType()->isStructureType());
361 const auto FooFields =
362 FooDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields();
363
364 FieldDecl *BarDecl = nullptr;
365 for (FieldDecl *Field : FooFields) {
366 if (Field->getNameAsString() == "Bar") {
367 BarDecl = Field;
368 } else {
369 FAIL() << "Unexpected field: " << Field->getNameAsString();
370 }
371 }
372 ASSERT_THAT(BarDecl, NotNull());
373
374 ASSERT_TRUE(BarDecl->getType()->isReferenceType());
375 ASSERT_TRUE(BarDecl->getType().getNonReferenceType()->isStructureType());
376 const auto BarFields =
377 BarDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields();
378
379 FieldDecl *FooRefDecl = nullptr;
380 FieldDecl *FooPtrDecl = nullptr;
381 FieldDecl *BazRefDecl = nullptr;
382 FieldDecl *BazPtrDecl = nullptr;
383 for (FieldDecl *Field : BarFields) {
384 if (Field->getNameAsString() == "FooRef") {
385 FooRefDecl = Field;
386 } else if (Field->getNameAsString() == "FooPtr") {
387 FooPtrDecl = Field;
388 } else if (Field->getNameAsString() == "BazRef") {
389 BazRefDecl = Field;
390 } else if (Field->getNameAsString() == "BazPtr") {
391 BazPtrDecl = Field;
392 } else {
393 FAIL() << "Unexpected field: " << Field->getNameAsString();
394 }
395 }
396 ASSERT_THAT(FooRefDecl, NotNull());
397 ASSERT_THAT(FooPtrDecl, NotNull());
398 ASSERT_THAT(BazRefDecl, NotNull());
399 ASSERT_THAT(BazPtrDecl, NotNull());
400
401 const auto *FooLoc = cast<ScalarStorageLocation>(
402 Env.getStorageLocation(*FooDecl, SkipPast::None));
403 const auto *FooVal = cast<ReferenceValue>(Env.getValue(*FooLoc));
404 const auto *FooReferentVal =
405 cast<StructValue>(Env.getValue(FooVal->getReferentLoc()));
406
407 const auto *BarVal =
408 cast<ReferenceValue>(FooReferentVal->getChild(*BarDecl));
409 const auto *BarReferentVal =
410 cast<StructValue>(Env.getValue(BarVal->getReferentLoc()));
411
412 const auto *FooRefVal =
413 cast<ReferenceValue>(BarReferentVal->getChild(*FooRefDecl));
414 const StorageLocation &FooReferentLoc = FooRefVal->getReferentLoc();
415 EXPECT_THAT(Env.getValue(FooReferentLoc), IsNull());
416
417 const auto *FooPtrVal =
418 cast<PointerValue>(BarReferentVal->getChild(*FooPtrDecl));
419 const StorageLocation &FooPtrPointeeLoc = FooPtrVal->getPointeeLoc();
420 EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull());
421
422 const auto *BazRefVal =
423 cast<ReferenceValue>(BarReferentVal->getChild(*BazRefDecl));
424 const StorageLocation &BazReferentLoc = BazRefVal->getReferentLoc();
425 EXPECT_THAT(Env.getValue(BazReferentLoc), NotNull());
426
427 const auto *BazPtrVal =
428 cast<PointerValue>(BarReferentVal->getChild(*BazPtrDecl));
429 const StorageLocation &BazPtrPointeeLoc = BazPtrVal->getPointeeLoc();
430 EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull());
431 });
432 }
433
TEST(TransferTest,PointerVarDecl)434 TEST(TransferTest, PointerVarDecl) {
435 std::string Code = R"(
436 struct A {};
437
438 A *getA();
439
440 void target() {
441 A *Foo = getA();
442 // [[p]]
443 }
444 )";
445 runDataflow(
446 Code, [](llvm::ArrayRef<
447 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
448 Results,
449 ASTContext &ASTCtx) {
450 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
451 const Environment &Env = Results[0].second.Env;
452
453 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
454 ASSERT_THAT(FooDecl, NotNull());
455
456 const StorageLocation *FooLoc =
457 Env.getStorageLocation(*FooDecl, SkipPast::None);
458 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
459
460 const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));
461 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
462 EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc));
463
464 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
465 EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal));
466 });
467 }
468
TEST(TransferTest,SelfReferentialPointerVarDecl)469 TEST(TransferTest, SelfReferentialPointerVarDecl) {
470 std::string Code = R"(
471 struct A;
472
473 struct B {};
474
475 struct C {
476 A &FooRef;
477 A *FooPtr;
478 B &BazRef;
479 B *BazPtr;
480 };
481
482 struct A {
483 C *Bar;
484 };
485
486 A *getA();
487
488 void target() {
489 A *Foo = getA();
490 // [[p]]
491 }
492 )";
493 runDataflow(
494 Code, [](llvm::ArrayRef<
495 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
496 Results,
497 ASTContext &ASTCtx) {
498 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
499 const Environment &Env = Results[0].second.Env;
500
501 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
502 ASSERT_THAT(FooDecl, NotNull());
503
504 ASSERT_TRUE(FooDecl->getType()->isPointerType());
505 ASSERT_TRUE(FooDecl->getType()
506 ->getAs<PointerType>()
507 ->getPointeeType()
508 ->isStructureType());
509 const auto FooFields = FooDecl->getType()
510 ->getAs<PointerType>()
511 ->getPointeeType()
512 ->getAsRecordDecl()
513 ->fields();
514
515 FieldDecl *BarDecl = nullptr;
516 for (FieldDecl *Field : FooFields) {
517 if (Field->getNameAsString() == "Bar") {
518 BarDecl = Field;
519 } else {
520 FAIL() << "Unexpected field: " << Field->getNameAsString();
521 }
522 }
523 ASSERT_THAT(BarDecl, NotNull());
524
525 ASSERT_TRUE(BarDecl->getType()->isPointerType());
526 ASSERT_TRUE(BarDecl->getType()
527 ->getAs<PointerType>()
528 ->getPointeeType()
529 ->isStructureType());
530 const auto BarFields = BarDecl->getType()
531 ->getAs<PointerType>()
532 ->getPointeeType()
533 ->getAsRecordDecl()
534 ->fields();
535
536 FieldDecl *FooRefDecl = nullptr;
537 FieldDecl *FooPtrDecl = nullptr;
538 FieldDecl *BazRefDecl = nullptr;
539 FieldDecl *BazPtrDecl = nullptr;
540 for (FieldDecl *Field : BarFields) {
541 if (Field->getNameAsString() == "FooRef") {
542 FooRefDecl = Field;
543 } else if (Field->getNameAsString() == "FooPtr") {
544 FooPtrDecl = Field;
545 } else if (Field->getNameAsString() == "BazRef") {
546 BazRefDecl = Field;
547 } else if (Field->getNameAsString() == "BazPtr") {
548 BazPtrDecl = Field;
549 } else {
550 FAIL() << "Unexpected field: " << Field->getNameAsString();
551 }
552 }
553 ASSERT_THAT(FooRefDecl, NotNull());
554 ASSERT_THAT(FooPtrDecl, NotNull());
555 ASSERT_THAT(BazRefDecl, NotNull());
556 ASSERT_THAT(BazPtrDecl, NotNull());
557
558 const auto *FooLoc = cast<ScalarStorageLocation>(
559 Env.getStorageLocation(*FooDecl, SkipPast::None));
560 const auto *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));
561 const auto *FooPointeeVal =
562 cast<StructValue>(Env.getValue(FooVal->getPointeeLoc()));
563
564 const auto *BarVal =
565 cast<PointerValue>(FooPointeeVal->getChild(*BarDecl));
566 const auto *BarPointeeVal =
567 cast<StructValue>(Env.getValue(BarVal->getPointeeLoc()));
568
569 const auto *FooRefVal =
570 cast<ReferenceValue>(BarPointeeVal->getChild(*FooRefDecl));
571 const StorageLocation &FooReferentLoc = FooRefVal->getReferentLoc();
572 EXPECT_THAT(Env.getValue(FooReferentLoc), IsNull());
573
574 const auto *FooPtrVal =
575 cast<PointerValue>(BarPointeeVal->getChild(*FooPtrDecl));
576 const StorageLocation &FooPtrPointeeLoc = FooPtrVal->getPointeeLoc();
577 EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull());
578
579 const auto *BazRefVal =
580 cast<ReferenceValue>(BarPointeeVal->getChild(*BazRefDecl));
581 const StorageLocation &BazReferentLoc = BazRefVal->getReferentLoc();
582 EXPECT_THAT(Env.getValue(BazReferentLoc), NotNull());
583
584 const auto *BazPtrVal =
585 cast<PointerValue>(BarPointeeVal->getChild(*BazPtrDecl));
586 const StorageLocation &BazPtrPointeeLoc = BazPtrVal->getPointeeLoc();
587 EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull());
588 });
589 }
590
TEST(TransferTest,MultipleVarsDecl)591 TEST(TransferTest, MultipleVarsDecl) {
592 std::string Code = R"(
593 void target() {
594 int Foo, Bar;
595 (void)0;
596 // [[p]]
597 }
598 )";
599 runDataflow(Code,
600 [](llvm::ArrayRef<
601 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
602 Results,
603 ASTContext &ASTCtx) {
604 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
605 const Environment &Env = Results[0].second.Env;
606
607 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
608 ASSERT_THAT(FooDecl, NotNull());
609
610 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
611 ASSERT_THAT(BarDecl, NotNull());
612
613 const StorageLocation *FooLoc =
614 Env.getStorageLocation(*FooDecl, SkipPast::None);
615 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
616
617 const StorageLocation *BarLoc =
618 Env.getStorageLocation(*BarDecl, SkipPast::None);
619 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
620
621 const Value *FooVal = Env.getValue(*FooLoc);
622 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
623
624 const Value *BarVal = Env.getValue(*BarLoc);
625 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
626 });
627 }
628
TEST(TransferTest,JoinVarDecl)629 TEST(TransferTest, JoinVarDecl) {
630 std::string Code = R"(
631 void target(bool B) {
632 int Foo;
633 // [[p1]]
634 if (B) {
635 int Bar;
636 // [[p2]]
637 } else {
638 int Baz;
639 // [[p3]]
640 }
641 (void)0;
642 // [[p4]]
643 }
644 )";
645 runDataflow(Code, [](llvm::ArrayRef<std::pair<
646 std::string, DataflowAnalysisState<NoopLattice>>>
647 Results,
648 ASTContext &ASTCtx) {
649 ASSERT_THAT(Results, ElementsAre(Pair("p4", _), Pair("p3", _),
650 Pair("p2", _), Pair("p1", _)));
651 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
652 ASSERT_THAT(FooDecl, NotNull());
653
654 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
655 ASSERT_THAT(BarDecl, NotNull());
656
657 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
658 ASSERT_THAT(BazDecl, NotNull());
659
660 const Environment &Env1 = Results[3].second.Env;
661 const StorageLocation *FooLoc =
662 Env1.getStorageLocation(*FooDecl, SkipPast::None);
663 EXPECT_THAT(FooLoc, NotNull());
664 EXPECT_THAT(Env1.getStorageLocation(*BarDecl, SkipPast::None), IsNull());
665 EXPECT_THAT(Env1.getStorageLocation(*BazDecl, SkipPast::None), IsNull());
666
667 const Environment &Env2 = Results[2].second.Env;
668 EXPECT_EQ(Env2.getStorageLocation(*FooDecl, SkipPast::None), FooLoc);
669 EXPECT_THAT(Env2.getStorageLocation(*BarDecl, SkipPast::None), NotNull());
670 EXPECT_THAT(Env2.getStorageLocation(*BazDecl, SkipPast::None), IsNull());
671
672 const Environment &Env3 = Results[1].second.Env;
673 EXPECT_EQ(Env3.getStorageLocation(*FooDecl, SkipPast::None), FooLoc);
674 EXPECT_THAT(Env3.getStorageLocation(*BarDecl, SkipPast::None), IsNull());
675 EXPECT_THAT(Env3.getStorageLocation(*BazDecl, SkipPast::None), NotNull());
676
677 const Environment &Env4 = Results[0].second.Env;
678 EXPECT_EQ(Env4.getStorageLocation(*FooDecl, SkipPast::None), FooLoc);
679 EXPECT_THAT(Env4.getStorageLocation(*BarDecl, SkipPast::None), IsNull());
680 EXPECT_THAT(Env4.getStorageLocation(*BazDecl, SkipPast::None), IsNull());
681 });
682 }
683
TEST(TransferTest,BinaryOperatorAssign)684 TEST(TransferTest, BinaryOperatorAssign) {
685 std::string Code = R"(
686 void target() {
687 int Foo;
688 int Bar;
689 (Bar) = (Foo);
690 // [[p]]
691 }
692 )";
693 runDataflow(Code,
694 [](llvm::ArrayRef<
695 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
696 Results,
697 ASTContext &ASTCtx) {
698 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
699 const Environment &Env = Results[0].second.Env;
700
701 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
702 ASSERT_THAT(FooDecl, NotNull());
703
704 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
705 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
706
707 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
708 ASSERT_THAT(BarDecl, NotNull());
709
710 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal);
711 });
712 }
713
TEST(TransferTest,VarDeclInitAssign)714 TEST(TransferTest, VarDeclInitAssign) {
715 std::string Code = R"(
716 void target() {
717 int Foo;
718 int Bar = Foo;
719 // [[p]]
720 }
721 )";
722 runDataflow(Code,
723 [](llvm::ArrayRef<
724 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
725 Results,
726 ASTContext &ASTCtx) {
727 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
728 const Environment &Env = Results[0].second.Env;
729
730 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
731 ASSERT_THAT(FooDecl, NotNull());
732
733 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
734 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
735
736 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
737 ASSERT_THAT(BarDecl, NotNull());
738
739 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal);
740 });
741 }
742
TEST(TransferTest,VarDeclInitAssignChained)743 TEST(TransferTest, VarDeclInitAssignChained) {
744 std::string Code = R"(
745 void target() {
746 int Foo;
747 int Bar;
748 int Baz = (Bar = Foo);
749 // [[p]]
750 }
751 )";
752 runDataflow(Code,
753 [](llvm::ArrayRef<
754 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
755 Results,
756 ASTContext &ASTCtx) {
757 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
758 const Environment &Env = Results[0].second.Env;
759
760 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
761 ASSERT_THAT(FooDecl, NotNull());
762
763 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
764 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
765
766 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
767 ASSERT_THAT(BarDecl, NotNull());
768
769 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
770 ASSERT_THAT(BazDecl, NotNull());
771
772 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal);
773 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), FooVal);
774 });
775 }
776
TEST(TransferTest,VarDeclInitAssignPtrDeref)777 TEST(TransferTest, VarDeclInitAssignPtrDeref) {
778 std::string Code = R"(
779 void target() {
780 int Foo;
781 int *Bar;
782 *(Bar) = Foo;
783 int Baz = *(Bar);
784 // [[p]]
785 }
786 )";
787 runDataflow(Code,
788 [](llvm::ArrayRef<
789 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
790 Results,
791 ASTContext &ASTCtx) {
792 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
793 const Environment &Env = Results[0].second.Env;
794
795 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
796 ASSERT_THAT(FooDecl, NotNull());
797
798 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None);
799 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
800
801 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
802 ASSERT_THAT(BarDecl, NotNull());
803
804 const auto *BarVal =
805 cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None));
806 EXPECT_EQ(Env.getValue(BarVal->getPointeeLoc()), FooVal);
807
808 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
809 ASSERT_THAT(BazDecl, NotNull());
810
811 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), FooVal);
812 });
813 }
814
TEST(TransferTest,AssignToAndFromReference)815 TEST(TransferTest, AssignToAndFromReference) {
816 std::string Code = R"(
817 void target() {
818 int Foo;
819 int Bar;
820 int &Baz = Foo;
821 // [[p1]]
822 Baz = Bar;
823 int Qux = Baz;
824 int &Quux = Baz;
825 // [[p2]]
826 }
827 )";
828 runDataflow(
829 Code, [](llvm::ArrayRef<
830 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
831 Results,
832 ASTContext &ASTCtx) {
833 ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _)));
834 const Environment &Env1 = Results[0].second.Env;
835 const Environment &Env2 = Results[1].second.Env;
836
837 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
838 ASSERT_THAT(FooDecl, NotNull());
839
840 const Value *FooVal = Env1.getValue(*FooDecl, SkipPast::None);
841 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
842
843 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
844 ASSERT_THAT(BarDecl, NotNull());
845
846 const Value *BarVal = Env1.getValue(*BarDecl, SkipPast::None);
847 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
848
849 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
850 ASSERT_THAT(BazDecl, NotNull());
851
852 EXPECT_EQ(Env1.getValue(*BazDecl, SkipPast::Reference), FooVal);
853
854 EXPECT_EQ(Env2.getValue(*BazDecl, SkipPast::Reference), BarVal);
855 EXPECT_EQ(Env2.getValue(*FooDecl, SkipPast::None), BarVal);
856
857 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
858 ASSERT_THAT(QuxDecl, NotNull());
859 EXPECT_EQ(Env2.getValue(*QuxDecl, SkipPast::None), BarVal);
860
861 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
862 ASSERT_THAT(QuuxDecl, NotNull());
863 EXPECT_EQ(Env2.getValue(*QuuxDecl, SkipPast::Reference), BarVal);
864 });
865 }
866
TEST(TransferTest,MultipleParamDecls)867 TEST(TransferTest, MultipleParamDecls) {
868 std::string Code = R"(
869 void target(int Foo, int Bar) {
870 (void)0;
871 // [[p]]
872 }
873 )";
874 runDataflow(Code,
875 [](llvm::ArrayRef<
876 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
877 Results,
878 ASTContext &ASTCtx) {
879 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
880 const Environment &Env = Results[0].second.Env;
881
882 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
883 ASSERT_THAT(FooDecl, NotNull());
884
885 const StorageLocation *FooLoc =
886 Env.getStorageLocation(*FooDecl, SkipPast::None);
887 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
888
889 const Value *FooVal = Env.getValue(*FooLoc);
890 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
891
892 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
893 ASSERT_THAT(BarDecl, NotNull());
894
895 const StorageLocation *BarLoc =
896 Env.getStorageLocation(*BarDecl, SkipPast::None);
897 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
898
899 const Value *BarVal = Env.getValue(*BarLoc);
900 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
901 });
902 }
903
TEST(TransferTest,StructParamDecl)904 TEST(TransferTest, StructParamDecl) {
905 std::string Code = R"(
906 struct A {
907 int Bar;
908 };
909
910 void target(A Foo) {
911 (void)0;
912 // [[p]]
913 }
914 )";
915 runDataflow(
916 Code, [](llvm::ArrayRef<
917 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
918 Results,
919 ASTContext &ASTCtx) {
920 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
921 const Environment &Env = Results[0].second.Env;
922
923 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
924 ASSERT_THAT(FooDecl, NotNull());
925
926 ASSERT_TRUE(FooDecl->getType()->isStructureType());
927 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
928
929 FieldDecl *BarDecl = nullptr;
930 for (FieldDecl *Field : FooFields) {
931 if (Field->getNameAsString() == "Bar") {
932 BarDecl = Field;
933 } else {
934 FAIL() << "Unexpected field: " << Field->getNameAsString();
935 }
936 }
937 ASSERT_THAT(BarDecl, NotNull());
938
939 const auto *FooLoc = cast<AggregateStorageLocation>(
940 Env.getStorageLocation(*FooDecl, SkipPast::None));
941 const auto *BarLoc =
942 cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
943
944 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
945 const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl));
946 EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
947 });
948 }
949
TEST(TransferTest,ReferenceParamDecl)950 TEST(TransferTest, ReferenceParamDecl) {
951 std::string Code = R"(
952 struct A {};
953
954 void target(A &Foo) {
955 (void)0;
956 // [[p]]
957 }
958 )";
959 runDataflow(
960 Code, [](llvm::ArrayRef<
961 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
962 Results,
963 ASTContext &ASTCtx) {
964 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
965 const Environment &Env = Results[0].second.Env;
966
967 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
968 ASSERT_THAT(FooDecl, NotNull());
969
970 const StorageLocation *FooLoc =
971 Env.getStorageLocation(*FooDecl, SkipPast::None);
972 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
973
974 const ReferenceValue *FooVal =
975 dyn_cast<ReferenceValue>(Env.getValue(*FooLoc));
976 ASSERT_THAT(FooVal, NotNull());
977
978 const StorageLocation &FooReferentLoc = FooVal->getReferentLoc();
979 EXPECT_TRUE(isa<AggregateStorageLocation>(&FooReferentLoc));
980
981 const Value *FooReferentVal = Env.getValue(FooReferentLoc);
982 EXPECT_TRUE(isa_and_nonnull<StructValue>(FooReferentVal));
983 });
984 }
985
TEST(TransferTest,PointerParamDecl)986 TEST(TransferTest, PointerParamDecl) {
987 std::string Code = R"(
988 struct A {};
989
990 void target(A *Foo) {
991 (void)0;
992 // [[p]]
993 }
994 )";
995 runDataflow(
996 Code, [](llvm::ArrayRef<
997 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
998 Results,
999 ASTContext &ASTCtx) {
1000 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1001 const Environment &Env = Results[0].second.Env;
1002
1003 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1004 ASSERT_THAT(FooDecl, NotNull());
1005
1006 const StorageLocation *FooLoc =
1007 Env.getStorageLocation(*FooDecl, SkipPast::None);
1008 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
1009
1010 const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));
1011 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();
1012 EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc));
1013
1014 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc);
1015 EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal));
1016 });
1017 }
1018
TEST(TransferTest,StructMember)1019 TEST(TransferTest, StructMember) {
1020 std::string Code = R"(
1021 struct A {
1022 int Bar;
1023 };
1024
1025 void target(A Foo) {
1026 int Baz = Foo.Bar;
1027 // [[p]]
1028 }
1029 )";
1030 runDataflow(
1031 Code, [](llvm::ArrayRef<
1032 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1033 Results,
1034 ASTContext &ASTCtx) {
1035 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1036 const Environment &Env = Results[0].second.Env;
1037
1038 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1039 ASSERT_THAT(FooDecl, NotNull());
1040
1041 ASSERT_TRUE(FooDecl->getType()->isStructureType());
1042 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1043
1044 FieldDecl *BarDecl = nullptr;
1045 for (FieldDecl *Field : FooFields) {
1046 if (Field->getNameAsString() == "Bar") {
1047 BarDecl = Field;
1048 } else {
1049 FAIL() << "Unexpected field: " << Field->getNameAsString();
1050 }
1051 }
1052 ASSERT_THAT(BarDecl, NotNull());
1053
1054 const auto *FooLoc = cast<AggregateStorageLocation>(
1055 Env.getStorageLocation(*FooDecl, SkipPast::None));
1056 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1057 const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl));
1058
1059 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1060 ASSERT_THAT(BazDecl, NotNull());
1061
1062 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarVal);
1063 });
1064 }
1065
TEST(TransferTest,DerivedBaseMemberClass)1066 TEST(TransferTest, DerivedBaseMemberClass) {
1067 std::string Code = R"(
1068 class A {
1069 int ADefault;
1070 protected:
1071 int AProtected;
1072 private:
1073 int APrivate;
1074 public:
1075 int APublic;
1076 };
1077
1078 class B : public A {
1079 int BDefault;
1080 protected:
1081 int BProtected;
1082 private:
1083 int BPrivate;
1084 };
1085
1086 void target() {
1087 B Foo;
1088 // [[p]]
1089 }
1090 )";
1091 runDataflow(
1092 Code, [](llvm::ArrayRef<
1093 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1094 Results,
1095 ASTContext &ASTCtx) {
1096 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1097 const Environment &Env = Results[0].second.Env;
1098
1099 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1100 ASSERT_THAT(FooDecl, NotNull());
1101 ASSERT_TRUE(FooDecl->getType()->isRecordType());
1102
1103 // Derived-class fields.
1104 const FieldDecl *BDefaultDecl = nullptr;
1105 const FieldDecl *BProtectedDecl = nullptr;
1106 const FieldDecl *BPrivateDecl = nullptr;
1107 for (const FieldDecl *Field :
1108 FooDecl->getType()->getAsRecordDecl()->fields()) {
1109 if (Field->getNameAsString() == "BDefault") {
1110 BDefaultDecl = Field;
1111 } else if (Field->getNameAsString() == "BProtected") {
1112 BProtectedDecl = Field;
1113 } else if (Field->getNameAsString() == "BPrivate") {
1114 BPrivateDecl = Field;
1115 } else {
1116 FAIL() << "Unexpected field: " << Field->getNameAsString();
1117 }
1118 }
1119 ASSERT_THAT(BDefaultDecl, NotNull());
1120 ASSERT_THAT(BProtectedDecl, NotNull());
1121 ASSERT_THAT(BPrivateDecl, NotNull());
1122
1123 // Base-class fields.
1124 const FieldDecl *ADefaultDecl = nullptr;
1125 const FieldDecl *APrivateDecl = nullptr;
1126 const FieldDecl *AProtectedDecl = nullptr;
1127 const FieldDecl *APublicDecl = nullptr;
1128 for (const clang::CXXBaseSpecifier &Base :
1129 FooDecl->getType()->getAsCXXRecordDecl()->bases()) {
1130 QualType BaseType = Base.getType();
1131 ASSERT_TRUE(BaseType->isRecordType());
1132 for (const FieldDecl *Field : BaseType->getAsRecordDecl()->fields()) {
1133 if (Field->getNameAsString() == "ADefault") {
1134 ADefaultDecl = Field;
1135 } else if (Field->getNameAsString() == "AProtected") {
1136 AProtectedDecl = Field;
1137 } else if (Field->getNameAsString() == "APrivate") {
1138 APrivateDecl = Field;
1139 } else if (Field->getNameAsString() == "APublic") {
1140 APublicDecl = Field;
1141 } else {
1142 FAIL() << "Unexpected field: " << Field->getNameAsString();
1143 }
1144 }
1145 }
1146 ASSERT_THAT(ADefaultDecl, NotNull());
1147 ASSERT_THAT(AProtectedDecl, NotNull());
1148 ASSERT_THAT(APrivateDecl, NotNull());
1149 ASSERT_THAT(APublicDecl, NotNull());
1150
1151 const auto &FooLoc = *cast<AggregateStorageLocation>(
1152 Env.getStorageLocation(*FooDecl, SkipPast::None));
1153 const auto &FooVal = *cast<StructValue>(Env.getValue(FooLoc));
1154
1155 // Note: we can't test presence of children in `FooLoc`, because
1156 // `getChild` requires its argument be present (or fails an assert). So,
1157 // we limit to testing presence in `FooVal` and coherence between the
1158 // two.
1159
1160 // Base-class fields.
1161 EXPECT_THAT(FooVal.getChild(*ADefaultDecl), NotNull());
1162 EXPECT_THAT(FooVal.getChild(*APrivateDecl), NotNull());
1163
1164 EXPECT_THAT(FooVal.getChild(*AProtectedDecl), NotNull());
1165 EXPECT_EQ(Env.getValue(FooLoc.getChild(*APublicDecl)),
1166 FooVal.getChild(*APublicDecl));
1167 EXPECT_THAT(FooVal.getChild(*APublicDecl), NotNull());
1168 EXPECT_EQ(Env.getValue(FooLoc.getChild(*AProtectedDecl)),
1169 FooVal.getChild(*AProtectedDecl));
1170
1171 // Derived-class fields.
1172 EXPECT_THAT(FooVal.getChild(*BDefaultDecl), NotNull());
1173 EXPECT_EQ(Env.getValue(FooLoc.getChild(*BDefaultDecl)),
1174 FooVal.getChild(*BDefaultDecl));
1175 EXPECT_THAT(FooVal.getChild(*BProtectedDecl), NotNull());
1176 EXPECT_EQ(Env.getValue(FooLoc.getChild(*BProtectedDecl)),
1177 FooVal.getChild(*BProtectedDecl));
1178 EXPECT_THAT(FooVal.getChild(*BPrivateDecl), NotNull());
1179 EXPECT_EQ(Env.getValue(FooLoc.getChild(*BPrivateDecl)),
1180 FooVal.getChild(*BPrivateDecl));
1181 });
1182 }
1183
derivedBaseMemberExpectations(llvm::ArrayRef<std::pair<std::string,DataflowAnalysisState<NoopLattice>>> Results,ASTContext & ASTCtx)1184 static void derivedBaseMemberExpectations(
1185 llvm::ArrayRef<std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1186 Results,
1187 ASTContext &ASTCtx) {
1188 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1189 const Environment &Env = Results[0].second.Env;
1190
1191 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1192 ASSERT_THAT(FooDecl, NotNull());
1193
1194 ASSERT_TRUE(FooDecl->getType()->isRecordType());
1195 const FieldDecl *BarDecl = nullptr;
1196 for (const clang::CXXBaseSpecifier &Base :
1197 FooDecl->getType()->getAsCXXRecordDecl()->bases()) {
1198 QualType BaseType = Base.getType();
1199 ASSERT_TRUE(BaseType->isStructureType());
1200
1201 for (const FieldDecl *Field : BaseType->getAsRecordDecl()->fields()) {
1202 if (Field->getNameAsString() == "Bar") {
1203 BarDecl = Field;
1204 } else {
1205 FAIL() << "Unexpected field: " << Field->getNameAsString();
1206 }
1207 }
1208 }
1209 ASSERT_THAT(BarDecl, NotNull());
1210
1211 const auto &FooLoc = *cast<AggregateStorageLocation>(
1212 Env.getStorageLocation(*FooDecl, SkipPast::None));
1213 const auto &FooVal = *cast<StructValue>(Env.getValue(FooLoc));
1214 EXPECT_THAT(FooVal.getChild(*BarDecl), NotNull());
1215 EXPECT_EQ(Env.getValue(FooLoc.getChild(*BarDecl)), FooVal.getChild(*BarDecl));
1216 }
1217
TEST(TransferTest,DerivedBaseMemberStructDefault)1218 TEST(TransferTest, DerivedBaseMemberStructDefault) {
1219 std::string Code = R"(
1220 struct A {
1221 int Bar;
1222 };
1223 struct B : public A {
1224 };
1225
1226 void target() {
1227 B Foo;
1228 // [[p]]
1229 }
1230 )";
1231 runDataflow(Code, derivedBaseMemberExpectations);
1232 }
1233
TEST(TransferTest,DerivedBaseMemberPrivateFriend)1234 TEST(TransferTest, DerivedBaseMemberPrivateFriend) {
1235 // Include an access to `Foo.Bar` to verify the analysis doesn't crash on that
1236 // access.
1237 std::string Code = R"(
1238 struct A {
1239 private:
1240 friend void target();
1241 int Bar;
1242 };
1243 struct B : public A {
1244 };
1245
1246 void target() {
1247 B Foo;
1248 (void)Foo.Bar;
1249 // [[p]]
1250 }
1251 )";
1252 runDataflow(Code, derivedBaseMemberExpectations);
1253 }
1254
TEST(TransferTest,ClassMember)1255 TEST(TransferTest, ClassMember) {
1256 std::string Code = R"(
1257 class A {
1258 public:
1259 int Bar;
1260 };
1261
1262 void target(A Foo) {
1263 int Baz = Foo.Bar;
1264 // [[p]]
1265 }
1266 )";
1267 runDataflow(
1268 Code, [](llvm::ArrayRef<
1269 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1270 Results,
1271 ASTContext &ASTCtx) {
1272 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1273 const Environment &Env = Results[0].second.Env;
1274
1275 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1276 ASSERT_THAT(FooDecl, NotNull());
1277
1278 ASSERT_TRUE(FooDecl->getType()->isClassType());
1279 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1280
1281 FieldDecl *BarDecl = nullptr;
1282 for (FieldDecl *Field : FooFields) {
1283 if (Field->getNameAsString() == "Bar") {
1284 BarDecl = Field;
1285 } else {
1286 FAIL() << "Unexpected field: " << Field->getNameAsString();
1287 }
1288 }
1289 ASSERT_THAT(BarDecl, NotNull());
1290
1291 const auto *FooLoc = cast<AggregateStorageLocation>(
1292 Env.getStorageLocation(*FooDecl, SkipPast::None));
1293 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1294 const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl));
1295
1296 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1297 ASSERT_THAT(BazDecl, NotNull());
1298
1299 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarVal);
1300 });
1301 }
1302
TEST(TransferTest,BaseClassInitializer)1303 TEST(TransferTest, BaseClassInitializer) {
1304 using ast_matchers::cxxConstructorDecl;
1305 using ast_matchers::hasName;
1306 using ast_matchers::ofClass;
1307
1308 std::string Code = R"(
1309 class A {
1310 public:
1311 A(int I) : Bar(I) {}
1312 int Bar;
1313 };
1314
1315 class B : public A {
1316 public:
1317 B(int I) : A(I) {
1318 (void)0;
1319 // [[p]]
1320 }
1321 };
1322 )";
1323 ASSERT_THAT_ERROR(
1324 test::checkDataflow<NoopAnalysis>(
1325 Code, cxxConstructorDecl(ofClass(hasName("B"))),
1326 [](ASTContext &C, Environment &) {
1327 return NoopAnalysis(C, /*ApplyBuiltinTransfer=*/true);
1328 },
1329 [](llvm::ArrayRef<
1330 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1331 Results,
1332 ASTContext &ASTCtx) {
1333 // Regression test to verify that base-class initializers do not
1334 // trigger an assertion. If we add support for such initializers in
1335 // the future, we can expand this test to check more specific
1336 // properties.
1337 EXPECT_THAT(Results, ElementsAre(Pair("p", _)));
1338 },
1339 {"-fsyntax-only", "-fno-delayed-template-parsing",
1340 "-std=" + std::string(LangStandard::getLangStandardForKind(
1341 LangStandard::lang_cxx17)
1342 .getName())}),
1343 llvm::Succeeded());
1344 }
1345
TEST(TransferTest,ReferenceMember)1346 TEST(TransferTest, ReferenceMember) {
1347 std::string Code = R"(
1348 struct A {
1349 int &Bar;
1350 };
1351
1352 void target(A Foo) {
1353 int Baz = Foo.Bar;
1354 // [[p]]
1355 }
1356 )";
1357 runDataflow(
1358 Code, [](llvm::ArrayRef<
1359 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1360 Results,
1361 ASTContext &ASTCtx) {
1362 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1363 const Environment &Env = Results[0].second.Env;
1364
1365 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1366 ASSERT_THAT(FooDecl, NotNull());
1367
1368 ASSERT_TRUE(FooDecl->getType()->isStructureType());
1369 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
1370
1371 FieldDecl *BarDecl = nullptr;
1372 for (FieldDecl *Field : FooFields) {
1373 if (Field->getNameAsString() == "Bar") {
1374 BarDecl = Field;
1375 } else {
1376 FAIL() << "Unexpected field: " << Field->getNameAsString();
1377 }
1378 }
1379 ASSERT_THAT(BarDecl, NotNull());
1380
1381 const auto *FooLoc = cast<AggregateStorageLocation>(
1382 Env.getStorageLocation(*FooDecl, SkipPast::None));
1383 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1384 const auto *BarVal = cast<ReferenceValue>(FooVal->getChild(*BarDecl));
1385 const auto *BarReferentVal =
1386 cast<IntegerValue>(Env.getValue(BarVal->getReferentLoc()));
1387
1388 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1389 ASSERT_THAT(BazDecl, NotNull());
1390
1391 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarReferentVal);
1392 });
1393 }
1394
TEST(TransferTest,StructThisMember)1395 TEST(TransferTest, StructThisMember) {
1396 std::string Code = R"(
1397 struct A {
1398 int Bar;
1399
1400 struct B {
1401 int Baz;
1402 };
1403
1404 B Qux;
1405
1406 void target() {
1407 int Foo = Bar;
1408 int Quux = Qux.Baz;
1409 // [[p]]
1410 }
1411 };
1412 )";
1413 runDataflow(
1414 Code, [](llvm::ArrayRef<
1415 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1416 Results,
1417 ASTContext &ASTCtx) {
1418 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1419 const Environment &Env = Results[0].second.Env;
1420
1421 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1422 Env.getThisPointeeStorageLocation());
1423 ASSERT_THAT(ThisLoc, NotNull());
1424
1425 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1426 ASSERT_THAT(BarDecl, NotNull());
1427
1428 const auto *BarLoc =
1429 cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl));
1430 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1431
1432 const Value *BarVal = Env.getValue(*BarLoc);
1433 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1434
1435 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1436 ASSERT_THAT(FooDecl, NotNull());
1437 EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal);
1438
1439 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1440 ASSERT_THAT(QuxDecl, NotNull());
1441
1442 ASSERT_TRUE(QuxDecl->getType()->isStructureType());
1443 auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields();
1444
1445 FieldDecl *BazDecl = nullptr;
1446 for (FieldDecl *Field : QuxFields) {
1447 if (Field->getNameAsString() == "Baz") {
1448 BazDecl = Field;
1449 } else {
1450 FAIL() << "Unexpected field: " << Field->getNameAsString();
1451 }
1452 }
1453 ASSERT_THAT(BazDecl, NotNull());
1454
1455 const auto *QuxLoc =
1456 cast<AggregateStorageLocation>(&ThisLoc->getChild(*QuxDecl));
1457 const auto *QuxVal = dyn_cast<StructValue>(Env.getValue(*QuxLoc));
1458 ASSERT_THAT(QuxVal, NotNull());
1459
1460 const auto *BazLoc =
1461 cast<ScalarStorageLocation>(&QuxLoc->getChild(*BazDecl));
1462 const auto *BazVal = cast<IntegerValue>(QuxVal->getChild(*BazDecl));
1463 EXPECT_EQ(Env.getValue(*BazLoc), BazVal);
1464
1465 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
1466 ASSERT_THAT(QuuxDecl, NotNull());
1467 EXPECT_EQ(Env.getValue(*QuuxDecl, SkipPast::None), BazVal);
1468 });
1469 }
1470
TEST(TransferTest,ClassThisMember)1471 TEST(TransferTest, ClassThisMember) {
1472 std::string Code = R"(
1473 class A {
1474 int Bar;
1475
1476 class B {
1477 public:
1478 int Baz;
1479 };
1480
1481 B Qux;
1482
1483 void target() {
1484 int Foo = Bar;
1485 int Quux = Qux.Baz;
1486 // [[p]]
1487 }
1488 };
1489 )";
1490 runDataflow(
1491 Code, [](llvm::ArrayRef<
1492 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1493 Results,
1494 ASTContext &ASTCtx) {
1495 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1496 const Environment &Env = Results[0].second.Env;
1497
1498 const auto *ThisLoc =
1499 cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation());
1500
1501 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1502 ASSERT_THAT(BarDecl, NotNull());
1503
1504 const auto *BarLoc =
1505 cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl));
1506 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1507
1508 const Value *BarVal = Env.getValue(*BarLoc);
1509 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1510
1511 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1512 ASSERT_THAT(FooDecl, NotNull());
1513 EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal);
1514
1515 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1516 ASSERT_THAT(QuxDecl, NotNull());
1517
1518 ASSERT_TRUE(QuxDecl->getType()->isClassType());
1519 auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields();
1520
1521 FieldDecl *BazDecl = nullptr;
1522 for (FieldDecl *Field : QuxFields) {
1523 if (Field->getNameAsString() == "Baz") {
1524 BazDecl = Field;
1525 } else {
1526 FAIL() << "Unexpected field: " << Field->getNameAsString();
1527 }
1528 }
1529 ASSERT_THAT(BazDecl, NotNull());
1530
1531 const auto *QuxLoc =
1532 cast<AggregateStorageLocation>(&ThisLoc->getChild(*QuxDecl));
1533 const auto *QuxVal = dyn_cast<StructValue>(Env.getValue(*QuxLoc));
1534 ASSERT_THAT(QuxVal, NotNull());
1535
1536 const auto *BazLoc =
1537 cast<ScalarStorageLocation>(&QuxLoc->getChild(*BazDecl));
1538 const auto *BazVal = cast<IntegerValue>(QuxVal->getChild(*BazDecl));
1539 EXPECT_EQ(Env.getValue(*BazLoc), BazVal);
1540
1541 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
1542 ASSERT_THAT(QuuxDecl, NotNull());
1543 EXPECT_EQ(Env.getValue(*QuuxDecl, SkipPast::None), BazVal);
1544 });
1545 }
1546
TEST(TransferTest,StructThisInLambda)1547 TEST(TransferTest, StructThisInLambda) {
1548 std::string ThisCaptureCode = R"(
1549 struct A {
1550 void frob() {
1551 [this]() {
1552 int Foo = Bar;
1553 // [[p1]]
1554 }();
1555 }
1556
1557 int Bar;
1558 };
1559 )";
1560 runDataflow(
1561 ThisCaptureCode,
1562 [](llvm::ArrayRef<
1563 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1564 Results,
1565 ASTContext &ASTCtx) {
1566 ASSERT_THAT(Results, ElementsAre(Pair("p1", _)));
1567 const Environment &Env = Results[0].second.Env;
1568
1569 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1570 Env.getThisPointeeStorageLocation());
1571 ASSERT_THAT(ThisLoc, NotNull());
1572
1573 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1574 ASSERT_THAT(BarDecl, NotNull());
1575
1576 const auto *BarLoc =
1577 cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl));
1578 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1579
1580 const Value *BarVal = Env.getValue(*BarLoc);
1581 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1582
1583 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1584 ASSERT_THAT(FooDecl, NotNull());
1585 EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal);
1586 },
1587 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()");
1588
1589 std::string RefCaptureDefaultCode = R"(
1590 struct A {
1591 void frob() {
1592 [&]() {
1593 int Foo = Bar;
1594 // [[p2]]
1595 }();
1596 }
1597
1598 int Bar;
1599 };
1600 )";
1601 runDataflow(
1602 RefCaptureDefaultCode,
1603 [](llvm::ArrayRef<
1604 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1605 Results,
1606 ASTContext &ASTCtx) {
1607 ASSERT_THAT(Results, ElementsAre(Pair("p2", _)));
1608 const Environment &Env = Results[0].second.Env;
1609
1610 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1611 Env.getThisPointeeStorageLocation());
1612 ASSERT_THAT(ThisLoc, NotNull());
1613
1614 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1615 ASSERT_THAT(BarDecl, NotNull());
1616
1617 const auto *BarLoc =
1618 cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl));
1619 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
1620
1621 const Value *BarVal = Env.getValue(*BarLoc);
1622 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
1623
1624 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1625 ASSERT_THAT(FooDecl, NotNull());
1626 EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal);
1627 },
1628 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()");
1629
1630 std::string FreeFunctionLambdaCode = R"(
1631 void foo() {
1632 int Bar;
1633 [&]() {
1634 int Foo = Bar;
1635 // [[p3]]
1636 }();
1637 }
1638 )";
1639 runDataflow(
1640 FreeFunctionLambdaCode,
1641 [](llvm::ArrayRef<
1642 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1643 Results,
1644 ASTContext &ASTCtx) {
1645 ASSERT_THAT(Results, ElementsAre(Pair("p3", _)));
1646 const Environment &Env = Results[0].second.Env;
1647
1648 EXPECT_THAT(Env.getThisPointeeStorageLocation(), IsNull());
1649 },
1650 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()");
1651 }
1652
TEST(TransferTest,ConstructorInitializer)1653 TEST(TransferTest, ConstructorInitializer) {
1654 std::string Code = R"(
1655 struct target {
1656 int Bar;
1657
1658 target(int Foo) : Bar(Foo) {
1659 int Qux = Bar;
1660 // [[p]]
1661 }
1662 };
1663 )";
1664 runDataflow(Code,
1665 [](llvm::ArrayRef<
1666 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1667 Results,
1668 ASTContext &ASTCtx) {
1669 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1670 const Environment &Env = Results[0].second.Env;
1671
1672 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1673 Env.getThisPointeeStorageLocation());
1674 ASSERT_THAT(ThisLoc, NotNull());
1675
1676 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1677 ASSERT_THAT(FooDecl, NotNull());
1678
1679 const auto *FooVal =
1680 cast<IntegerValue>(Env.getValue(*FooDecl, SkipPast::None));
1681
1682 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1683 ASSERT_THAT(QuxDecl, NotNull());
1684 EXPECT_EQ(Env.getValue(*QuxDecl, SkipPast::None), FooVal);
1685 });
1686 }
1687
TEST(TransferTest,DefaultInitializer)1688 TEST(TransferTest, DefaultInitializer) {
1689 std::string Code = R"(
1690 struct target {
1691 int Bar;
1692 int Baz = Bar;
1693
1694 target(int Foo) : Bar(Foo) {
1695 int Qux = Baz;
1696 // [[p]]
1697 }
1698 };
1699 )";
1700 runDataflow(Code,
1701 [](llvm::ArrayRef<
1702 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1703 Results,
1704 ASTContext &ASTCtx) {
1705 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1706 const Environment &Env = Results[0].second.Env;
1707
1708 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1709 Env.getThisPointeeStorageLocation());
1710 ASSERT_THAT(ThisLoc, NotNull());
1711
1712 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1713 ASSERT_THAT(FooDecl, NotNull());
1714
1715 const auto *FooVal =
1716 cast<IntegerValue>(Env.getValue(*FooDecl, SkipPast::None));
1717
1718 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1719 ASSERT_THAT(QuxDecl, NotNull());
1720 EXPECT_EQ(Env.getValue(*QuxDecl, SkipPast::None), FooVal);
1721 });
1722 }
1723
TEST(TransferTest,DefaultInitializerReference)1724 TEST(TransferTest, DefaultInitializerReference) {
1725 std::string Code = R"(
1726 struct target {
1727 int &Bar;
1728 int &Baz = Bar;
1729
1730 target(int &Foo) : Bar(Foo) {
1731 int &Qux = Baz;
1732 // [[p]]
1733 }
1734 };
1735 )";
1736 runDataflow(
1737 Code, [](llvm::ArrayRef<
1738 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1739 Results,
1740 ASTContext &ASTCtx) {
1741 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1742 const Environment &Env = Results[0].second.Env;
1743
1744 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>(
1745 Env.getThisPointeeStorageLocation());
1746 ASSERT_THAT(ThisLoc, NotNull());
1747
1748 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1749 ASSERT_THAT(FooDecl, NotNull());
1750
1751 const auto *FooVal =
1752 cast<ReferenceValue>(Env.getValue(*FooDecl, SkipPast::None));
1753
1754 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
1755 ASSERT_THAT(QuxDecl, NotNull());
1756
1757 const auto *QuxVal =
1758 cast<ReferenceValue>(Env.getValue(*QuxDecl, SkipPast::None));
1759 EXPECT_EQ(&QuxVal->getReferentLoc(), &FooVal->getReferentLoc());
1760 });
1761 }
1762
TEST(TransferTest,TemporaryObject)1763 TEST(TransferTest, TemporaryObject) {
1764 std::string Code = R"(
1765 struct A {
1766 int Bar;
1767 };
1768
1769 void target() {
1770 A Foo = A();
1771 // [[p]]
1772 }
1773 )";
1774 runDataflow(
1775 Code, [](llvm::ArrayRef<
1776 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1777 Results,
1778 ASTContext &ASTCtx) {
1779 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1780 const Environment &Env = Results[0].second.Env;
1781
1782 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1783 ASSERT_THAT(FooDecl, NotNull());
1784
1785 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1786 ASSERT_THAT(BarDecl, NotNull());
1787
1788 const auto *FooLoc = cast<AggregateStorageLocation>(
1789 Env.getStorageLocation(*FooDecl, SkipPast::None));
1790 const auto *BarLoc =
1791 cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
1792
1793 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1794 const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl));
1795 EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
1796 });
1797 }
1798
TEST(TransferTest,ElidableConstructor)1799 TEST(TransferTest, ElidableConstructor) {
1800 // This test is effectively the same as TransferTest.TemporaryObject, but
1801 // the code is compiled as C++ 14.
1802 std::string Code = R"(
1803 struct A {
1804 int Bar;
1805 };
1806
1807 void target() {
1808 A Foo = A();
1809 // [[p]]
1810 }
1811 )";
1812 runDataflow(
1813 Code,
1814 [](llvm::ArrayRef<
1815 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1816 Results,
1817 ASTContext &ASTCtx) {
1818 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1819 const Environment &Env = Results[0].second.Env;
1820
1821 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1822 ASSERT_THAT(FooDecl, NotNull());
1823
1824 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1825 ASSERT_THAT(BarDecl, NotNull());
1826
1827 const auto *FooLoc = cast<AggregateStorageLocation>(
1828 Env.getStorageLocation(*FooDecl, SkipPast::None));
1829 const auto *BarLoc =
1830 cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
1831
1832 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1833 const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl));
1834 EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
1835 },
1836 LangStandard::lang_cxx14);
1837 }
1838
TEST(TransferTest,AssignmentOperator)1839 TEST(TransferTest, AssignmentOperator) {
1840 std::string Code = R"(
1841 struct A {
1842 int Baz;
1843 };
1844
1845 void target() {
1846 A Foo;
1847 A Bar;
1848 // [[p1]]
1849 Foo = Bar;
1850 // [[p2]]
1851 }
1852 )";
1853 runDataflow(
1854 Code, [](llvm::ArrayRef<
1855 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1856 Results,
1857 ASTContext &ASTCtx) {
1858 ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _)));
1859 const Environment &Env1 = Results[0].second.Env;
1860 const Environment &Env2 = Results[1].second.Env;
1861
1862 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1863 ASSERT_THAT(FooDecl, NotNull());
1864
1865 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1866 ASSERT_THAT(BarDecl, NotNull());
1867
1868 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1869 ASSERT_THAT(BazDecl, NotNull());
1870
1871 const auto *FooLoc1 = cast<AggregateStorageLocation>(
1872 Env1.getStorageLocation(*FooDecl, SkipPast::None));
1873 const auto *BarLoc1 = cast<AggregateStorageLocation>(
1874 Env1.getStorageLocation(*BarDecl, SkipPast::None));
1875
1876 const auto *FooVal1 = cast<StructValue>(Env1.getValue(*FooLoc1));
1877 const auto *BarVal1 = cast<StructValue>(Env1.getValue(*BarLoc1));
1878 EXPECT_NE(FooVal1, BarVal1);
1879
1880 const auto *FooBazVal1 =
1881 cast<IntegerValue>(Env1.getValue(FooLoc1->getChild(*BazDecl)));
1882 const auto *BarBazVal1 =
1883 cast<IntegerValue>(Env1.getValue(BarLoc1->getChild(*BazDecl)));
1884 EXPECT_NE(FooBazVal1, BarBazVal1);
1885
1886 const auto *FooLoc2 = cast<AggregateStorageLocation>(
1887 Env2.getStorageLocation(*FooDecl, SkipPast::None));
1888 const auto *BarLoc2 = cast<AggregateStorageLocation>(
1889 Env2.getStorageLocation(*BarDecl, SkipPast::None));
1890
1891 const auto *FooVal2 = cast<StructValue>(Env2.getValue(*FooLoc2));
1892 const auto *BarVal2 = cast<StructValue>(Env2.getValue(*BarLoc2));
1893 EXPECT_EQ(FooVal2, BarVal2);
1894
1895 const auto *FooBazVal2 =
1896 cast<IntegerValue>(Env2.getValue(FooLoc1->getChild(*BazDecl)));
1897 const auto *BarBazVal2 =
1898 cast<IntegerValue>(Env2.getValue(BarLoc1->getChild(*BazDecl)));
1899 EXPECT_EQ(FooBazVal2, BarBazVal2);
1900 });
1901 }
1902
TEST(TransferTest,CopyConstructor)1903 TEST(TransferTest, CopyConstructor) {
1904 std::string Code = R"(
1905 struct A {
1906 int Baz;
1907 };
1908
1909 void target() {
1910 A Foo;
1911 A Bar = Foo;
1912 // [[p]]
1913 }
1914 )";
1915 runDataflow(
1916 Code, [](llvm::ArrayRef<
1917 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1918 Results,
1919 ASTContext &ASTCtx) {
1920 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1921 const Environment &Env = Results[0].second.Env;
1922
1923 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1924 ASSERT_THAT(FooDecl, NotNull());
1925
1926 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1927 ASSERT_THAT(BarDecl, NotNull());
1928
1929 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1930 ASSERT_THAT(BazDecl, NotNull());
1931
1932 const auto *FooLoc = cast<AggregateStorageLocation>(
1933 Env.getStorageLocation(*FooDecl, SkipPast::None));
1934 const auto *BarLoc = cast<AggregateStorageLocation>(
1935 Env.getStorageLocation(*BarDecl, SkipPast::None));
1936
1937 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1938 const auto *BarVal = cast<StructValue>(Env.getValue(*BarLoc));
1939 EXPECT_EQ(FooVal, BarVal);
1940
1941 const auto *FooBazVal =
1942 cast<IntegerValue>(Env.getValue(FooLoc->getChild(*BazDecl)));
1943 const auto *BarBazVal =
1944 cast<IntegerValue>(Env.getValue(BarLoc->getChild(*BazDecl)));
1945 EXPECT_EQ(FooBazVal, BarBazVal);
1946 });
1947 }
1948
TEST(TransferTest,CopyConstructorWithParens)1949 TEST(TransferTest, CopyConstructorWithParens) {
1950 std::string Code = R"(
1951 struct A {
1952 int Baz;
1953 };
1954
1955 void target() {
1956 A Foo;
1957 A Bar((A(Foo)));
1958 // [[p]]
1959 }
1960 )";
1961 runDataflow(
1962 Code, [](llvm::ArrayRef<
1963 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1964 Results,
1965 ASTContext &ASTCtx) {
1966 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
1967 const Environment &Env = Results[0].second.Env;
1968
1969 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
1970 ASSERT_THAT(FooDecl, NotNull());
1971
1972 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
1973 ASSERT_THAT(BarDecl, NotNull());
1974
1975 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
1976 ASSERT_THAT(BazDecl, NotNull());
1977
1978 const auto *FooLoc = cast<AggregateStorageLocation>(
1979 Env.getStorageLocation(*FooDecl, SkipPast::None));
1980 const auto *BarLoc = cast<AggregateStorageLocation>(
1981 Env.getStorageLocation(*BarDecl, SkipPast::None));
1982
1983 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
1984 const auto *BarVal = cast<StructValue>(Env.getValue(*BarLoc));
1985 EXPECT_EQ(FooVal, BarVal);
1986
1987 const auto *FooBazVal =
1988 cast<IntegerValue>(Env.getValue(FooLoc->getChild(*BazDecl)));
1989 const auto *BarBazVal =
1990 cast<IntegerValue>(Env.getValue(BarLoc->getChild(*BazDecl)));
1991 EXPECT_EQ(FooBazVal, BarBazVal);
1992 });
1993 }
1994
TEST(TransferTest,MoveConstructor)1995 TEST(TransferTest, MoveConstructor) {
1996 std::string Code = R"(
1997 namespace std {
1998
1999 template <typename T> struct remove_reference { using type = T; };
2000 template <typename T> struct remove_reference<T&> { using type = T; };
2001 template <typename T> struct remove_reference<T&&> { using type = T; };
2002
2003 template <typename T>
2004 using remove_reference_t = typename remove_reference<T>::type;
2005
2006 template <typename T>
2007 std::remove_reference_t<T>&& move(T&& x);
2008
2009 } // namespace std
2010
2011 struct A {
2012 int Baz;
2013 };
2014
2015 void target() {
2016 A Foo;
2017 A Bar;
2018 // [[p1]]
2019 Foo = std::move(Bar);
2020 // [[p2]]
2021 }
2022 )";
2023 runDataflow(
2024 Code, [](llvm::ArrayRef<
2025 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2026 Results,
2027 ASTContext &ASTCtx) {
2028 ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _)));
2029 const Environment &Env1 = Results[0].second.Env;
2030 const Environment &Env2 = Results[1].second.Env;
2031
2032 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2033 ASSERT_THAT(FooDecl, NotNull());
2034
2035 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2036 ASSERT_THAT(BarDecl, NotNull());
2037
2038 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2039 ASSERT_THAT(BazDecl, NotNull());
2040
2041 const auto *FooLoc1 = cast<AggregateStorageLocation>(
2042 Env1.getStorageLocation(*FooDecl, SkipPast::None));
2043 const auto *BarLoc1 = cast<AggregateStorageLocation>(
2044 Env1.getStorageLocation(*BarDecl, SkipPast::None));
2045
2046 const auto *FooVal1 = cast<StructValue>(Env1.getValue(*FooLoc1));
2047 const auto *BarVal1 = cast<StructValue>(Env1.getValue(*BarLoc1));
2048 EXPECT_NE(FooVal1, BarVal1);
2049
2050 const auto *FooBazVal1 =
2051 cast<IntegerValue>(Env1.getValue(FooLoc1->getChild(*BazDecl)));
2052 const auto *BarBazVal1 =
2053 cast<IntegerValue>(Env1.getValue(BarLoc1->getChild(*BazDecl)));
2054 EXPECT_NE(FooBazVal1, BarBazVal1);
2055
2056 const auto *FooLoc2 = cast<AggregateStorageLocation>(
2057 Env2.getStorageLocation(*FooDecl, SkipPast::None));
2058 const auto *FooVal2 = cast<StructValue>(Env2.getValue(*FooLoc2));
2059 EXPECT_EQ(FooVal2, BarVal1);
2060
2061 const auto *FooBazVal2 =
2062 cast<IntegerValue>(Env2.getValue(FooLoc1->getChild(*BazDecl)));
2063 EXPECT_EQ(FooBazVal2, BarBazVal1);
2064 });
2065 }
2066
TEST(TransferTest,BindTemporary)2067 TEST(TransferTest, BindTemporary) {
2068 std::string Code = R"(
2069 struct A {
2070 virtual ~A() = default;
2071
2072 int Baz;
2073 };
2074
2075 void target(A Foo) {
2076 int Bar = A(Foo).Baz;
2077 // [[p]]
2078 }
2079 )";
2080 runDataflow(Code,
2081 [](llvm::ArrayRef<
2082 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2083 Results,
2084 ASTContext &ASTCtx) {
2085 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2086 const Environment &Env = Results[0].second.Env;
2087
2088 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2089 ASSERT_THAT(FooDecl, NotNull());
2090
2091 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2092 ASSERT_THAT(BarDecl, NotNull());
2093
2094 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2095 ASSERT_THAT(BazDecl, NotNull());
2096
2097 const auto &FooVal =
2098 *cast<StructValue>(Env.getValue(*FooDecl, SkipPast::None));
2099 const auto *BarVal =
2100 cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None));
2101 EXPECT_EQ(BarVal, FooVal.getChild(*BazDecl));
2102 });
2103 }
2104
TEST(TransferTest,StaticCast)2105 TEST(TransferTest, StaticCast) {
2106 std::string Code = R"(
2107 void target(int Foo) {
2108 int Bar = static_cast<int>(Foo);
2109 // [[p]]
2110 }
2111 )";
2112 runDataflow(Code,
2113 [](llvm::ArrayRef<
2114 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2115 Results,
2116 ASTContext &ASTCtx) {
2117 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2118 const Environment &Env = Results[0].second.Env;
2119
2120 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2121 ASSERT_THAT(FooDecl, NotNull());
2122
2123 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2124 ASSERT_THAT(BarDecl, NotNull());
2125
2126 const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None);
2127 const auto *BarVal = Env.getValue(*BarDecl, SkipPast::None);
2128 EXPECT_TRUE(isa<IntegerValue>(FooVal));
2129 EXPECT_TRUE(isa<IntegerValue>(BarVal));
2130 EXPECT_EQ(FooVal, BarVal);
2131 });
2132 }
2133
TEST(TransferTest,IntegralCast)2134 TEST(TransferTest, IntegralCast) {
2135 std::string Code = R"(
2136 void target(int Foo) {
2137 long Bar = Foo;
2138 // [[p]]
2139 }
2140 )";
2141 runDataflow(Code,
2142 [](llvm::ArrayRef<
2143 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2144 Results,
2145 ASTContext &ASTCtx) {
2146 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2147 const Environment &Env = Results[0].second.Env;
2148
2149 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2150 ASSERT_THAT(FooDecl, NotNull());
2151
2152 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2153 ASSERT_THAT(BarDecl, NotNull());
2154
2155 const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None);
2156 const auto *BarVal = Env.getValue(*BarDecl, SkipPast::None);
2157 EXPECT_TRUE(isa<IntegerValue>(FooVal));
2158 EXPECT_TRUE(isa<IntegerValue>(BarVal));
2159 EXPECT_EQ(FooVal, BarVal);
2160 });
2161 }
2162
TEST(TransferTest,IntegraltoBooleanCast)2163 TEST(TransferTest, IntegraltoBooleanCast) {
2164 std::string Code = R"(
2165 void target(int Foo) {
2166 bool Bar = Foo;
2167 // [[p]]
2168 }
2169 )";
2170 runDataflow(Code,
2171 [](llvm::ArrayRef<
2172 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2173 Results,
2174 ASTContext &ASTCtx) {
2175 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2176 const Environment &Env = Results[0].second.Env;
2177
2178 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2179 ASSERT_THAT(FooDecl, NotNull());
2180
2181 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2182 ASSERT_THAT(BarDecl, NotNull());
2183
2184 const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None);
2185 const auto *BarVal = Env.getValue(*BarDecl, SkipPast::None);
2186 EXPECT_TRUE(isa<IntegerValue>(FooVal));
2187 EXPECT_TRUE(isa<BoolValue>(BarVal));
2188 });
2189 }
2190
TEST(TransferTest,IntegralToBooleanCastFromBool)2191 TEST(TransferTest, IntegralToBooleanCastFromBool) {
2192 std::string Code = R"(
2193 void target(bool Foo) {
2194 int Zab = Foo;
2195 bool Bar = Zab;
2196 // [[p]]
2197 }
2198 )";
2199 runDataflow(Code,
2200 [](llvm::ArrayRef<
2201 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2202 Results,
2203 ASTContext &ASTCtx) {
2204 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2205 const Environment &Env = Results[0].second.Env;
2206
2207 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2208 ASSERT_THAT(FooDecl, NotNull());
2209
2210 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2211 ASSERT_THAT(BarDecl, NotNull());
2212
2213 const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None);
2214 const auto *BarVal = Env.getValue(*BarDecl, SkipPast::None);
2215 EXPECT_TRUE(isa<BoolValue>(FooVal));
2216 EXPECT_TRUE(isa<BoolValue>(BarVal));
2217 EXPECT_EQ(FooVal, BarVal);
2218 });
2219 }
2220
TEST(TransferTest,NullToPointerCast)2221 TEST(TransferTest, NullToPointerCast) {
2222 std::string Code = R"(
2223 using my_nullptr_t = decltype(nullptr);
2224 struct Baz {};
2225 void target() {
2226 int *FooX = nullptr;
2227 int *FooY = nullptr;
2228 bool **Bar = nullptr;
2229 Baz *Baz = nullptr;
2230 my_nullptr_t Null = 0;
2231 // [[p]]
2232 }
2233 )";
2234 runDataflow(Code,
2235 [](llvm::ArrayRef<
2236 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2237 Results,
2238 ASTContext &ASTCtx) {
2239 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2240 const Environment &Env = Results[0].second.Env;
2241
2242 const ValueDecl *FooXDecl = findValueDecl(ASTCtx, "FooX");
2243 ASSERT_THAT(FooXDecl, NotNull());
2244
2245 const ValueDecl *FooYDecl = findValueDecl(ASTCtx, "FooY");
2246 ASSERT_THAT(FooYDecl, NotNull());
2247
2248 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2249 ASSERT_THAT(BarDecl, NotNull());
2250
2251 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2252 ASSERT_THAT(BazDecl, NotNull());
2253
2254 const ValueDecl *NullDecl = findValueDecl(ASTCtx, "Null");
2255 ASSERT_THAT(NullDecl, NotNull());
2256
2257 const auto *FooXVal =
2258 cast<PointerValue>(Env.getValue(*FooXDecl, SkipPast::None));
2259 const auto *FooYVal =
2260 cast<PointerValue>(Env.getValue(*FooYDecl, SkipPast::None));
2261 const auto *BarVal =
2262 cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None));
2263 const auto *BazVal =
2264 cast<PointerValue>(Env.getValue(*BazDecl, SkipPast::None));
2265 const auto *NullVal =
2266 cast<PointerValue>(Env.getValue(*NullDecl, SkipPast::None));
2267
2268 EXPECT_EQ(FooXVal, FooYVal);
2269 EXPECT_NE(FooXVal, BarVal);
2270 EXPECT_NE(FooXVal, BazVal);
2271 EXPECT_NE(BarVal, BazVal);
2272
2273 const StorageLocation &FooPointeeLoc = FooXVal->getPointeeLoc();
2274 EXPECT_TRUE(isa<ScalarStorageLocation>(FooPointeeLoc));
2275 EXPECT_THAT(Env.getValue(FooPointeeLoc), IsNull());
2276
2277 const StorageLocation &BarPointeeLoc = BarVal->getPointeeLoc();
2278 EXPECT_TRUE(isa<ScalarStorageLocation>(BarPointeeLoc));
2279 EXPECT_THAT(Env.getValue(BarPointeeLoc), IsNull());
2280
2281 const StorageLocation &BazPointeeLoc = BazVal->getPointeeLoc();
2282 EXPECT_TRUE(isa<AggregateStorageLocation>(BazPointeeLoc));
2283 EXPECT_THAT(Env.getValue(BazPointeeLoc), IsNull());
2284
2285 const StorageLocation &NullPointeeLoc =
2286 NullVal->getPointeeLoc();
2287 EXPECT_TRUE(isa<ScalarStorageLocation>(NullPointeeLoc));
2288 EXPECT_THAT(Env.getValue(NullPointeeLoc), IsNull());
2289 });
2290 }
2291
TEST(TransferTest,NullToMemberPointerCast)2292 TEST(TransferTest, NullToMemberPointerCast) {
2293 std::string Code = R"(
2294 struct Foo {};
2295 void target(Foo *Foo) {
2296 int Foo::*MemberPointer = nullptr;
2297 // [[p]]
2298 }
2299 )";
2300 runDataflow(
2301 Code, [](llvm::ArrayRef<
2302 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2303 Results,
2304 ASTContext &ASTCtx) {
2305 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2306 const Environment &Env = Results[0].second.Env;
2307
2308 const ValueDecl *MemberPointerDecl =
2309 findValueDecl(ASTCtx, "MemberPointer");
2310 ASSERT_THAT(MemberPointerDecl, NotNull());
2311
2312 const auto *MemberPointerVal = cast<PointerValue>(
2313 Env.getValue(*MemberPointerDecl, SkipPast::None));
2314
2315 const StorageLocation &MemberLoc = MemberPointerVal->getPointeeLoc();
2316 EXPECT_THAT(Env.getValue(MemberLoc), IsNull());
2317 });
2318 }
2319
TEST(TransferTest,AddrOfValue)2320 TEST(TransferTest, AddrOfValue) {
2321 std::string Code = R"(
2322 void target() {
2323 int Foo;
2324 int *Bar = &Foo;
2325 // [[p]]
2326 }
2327 )";
2328 runDataflow(Code,
2329 [](llvm::ArrayRef<
2330 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2331 Results,
2332 ASTContext &ASTCtx) {
2333 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2334 const Environment &Env = Results[0].second.Env;
2335
2336 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2337 ASSERT_THAT(FooDecl, NotNull());
2338
2339 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2340 ASSERT_THAT(BarDecl, NotNull());
2341
2342 const auto *FooLoc = cast<ScalarStorageLocation>(
2343 Env.getStorageLocation(*FooDecl, SkipPast::None));
2344 const auto *BarVal =
2345 cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None));
2346 EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc);
2347 });
2348 }
2349
TEST(TransferTest,AddrOfReference)2350 TEST(TransferTest, AddrOfReference) {
2351 std::string Code = R"(
2352 void target(int *Foo) {
2353 int *Bar = &(*Foo);
2354 // [[p]]
2355 }
2356 )";
2357 runDataflow(Code,
2358 [](llvm::ArrayRef<
2359 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2360 Results,
2361 ASTContext &ASTCtx) {
2362 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2363 const Environment &Env = Results[0].second.Env;
2364
2365 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2366 ASSERT_THAT(FooDecl, NotNull());
2367
2368 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2369 ASSERT_THAT(BarDecl, NotNull());
2370
2371 const auto *FooVal =
2372 cast<PointerValue>(Env.getValue(*FooDecl, SkipPast::None));
2373 const auto *BarVal =
2374 cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None));
2375 EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc());
2376 });
2377 }
2378
TEST(TransferTest,DerefDependentPtr)2379 TEST(TransferTest, DerefDependentPtr) {
2380 std::string Code = R"(
2381 template <typename T>
2382 void target(T *Foo) {
2383 T &Bar = *Foo;
2384 /*[[p]]*/
2385 }
2386 )";
2387 runDataflow(
2388 Code, [](llvm::ArrayRef<
2389 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2390 Results,
2391 ASTContext &ASTCtx) {
2392 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2393 const Environment &Env = Results[0].second.Env;
2394
2395 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2396 ASSERT_THAT(FooDecl, NotNull());
2397
2398 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2399 ASSERT_THAT(BarDecl, NotNull());
2400
2401 const auto *FooVal =
2402 cast<PointerValue>(Env.getValue(*FooDecl, SkipPast::None));
2403 const auto *BarVal =
2404 cast<ReferenceValue>(Env.getValue(*BarDecl, SkipPast::None));
2405 EXPECT_EQ(&BarVal->getReferentLoc(), &FooVal->getPointeeLoc());
2406 });
2407 }
2408
TEST(TransferTest,VarDeclInitAssignConditionalOperator)2409 TEST(TransferTest, VarDeclInitAssignConditionalOperator) {
2410 std::string Code = R"(
2411 struct A {};
2412
2413 void target(A Foo, A Bar, bool Cond) {
2414 A Baz = Cond ? Foo : Bar;
2415 /*[[p]]*/
2416 }
2417 )";
2418 runDataflow(
2419 Code, [](llvm::ArrayRef<
2420 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2421 Results,
2422 ASTContext &ASTCtx) {
2423 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2424 const Environment &Env = Results[0].second.Env;
2425
2426 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2427 ASSERT_THAT(FooDecl, NotNull());
2428
2429 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2430 ASSERT_THAT(BarDecl, NotNull());
2431
2432 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2433 ASSERT_THAT(BazDecl, NotNull());
2434
2435 const auto *FooVal =
2436 cast<StructValue>(Env.getValue(*FooDecl, SkipPast::None));
2437 const auto *BarVal =
2438 cast<StructValue>(Env.getValue(*BarDecl, SkipPast::None));
2439
2440 const auto *BazVal =
2441 dyn_cast<StructValue>(Env.getValue(*BazDecl, SkipPast::None));
2442 ASSERT_THAT(BazVal, NotNull());
2443
2444 EXPECT_NE(BazVal, FooVal);
2445 EXPECT_NE(BazVal, BarVal);
2446 });
2447 }
2448
TEST(TransferTest,VarDeclInDoWhile)2449 TEST(TransferTest, VarDeclInDoWhile) {
2450 std::string Code = R"(
2451 void target(int *Foo) {
2452 do {
2453 int Bar = *Foo;
2454 } while (true);
2455 (void)0;
2456 /*[[p]]*/
2457 }
2458 )";
2459 runDataflow(Code,
2460 [](llvm::ArrayRef<
2461 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2462 Results,
2463 ASTContext &ASTCtx) {
2464 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2465 const Environment &Env = Results[0].second.Env;
2466
2467 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2468 ASSERT_THAT(FooDecl, NotNull());
2469
2470 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2471 ASSERT_THAT(BarDecl, NotNull());
2472
2473 const auto *FooVal =
2474 cast<PointerValue>(Env.getValue(*FooDecl, SkipPast::None));
2475 const auto *FooPointeeVal =
2476 cast<IntegerValue>(Env.getValue(FooVal->getPointeeLoc()));
2477
2478 const auto *BarVal = dyn_cast_or_null<IntegerValue>(
2479 Env.getValue(*BarDecl, SkipPast::None));
2480 ASSERT_THAT(BarVal, NotNull());
2481
2482 EXPECT_EQ(BarVal, FooPointeeVal);
2483 });
2484 }
2485
TEST(TransferTest,AggregateInitialization)2486 TEST(TransferTest, AggregateInitialization) {
2487 std::string BracesCode = R"(
2488 struct A {
2489 int Foo;
2490 };
2491
2492 struct B {
2493 int Bar;
2494 A Baz;
2495 int Qux;
2496 };
2497
2498 void target(int BarArg, int FooArg, int QuxArg) {
2499 B Quux{BarArg, {FooArg}, QuxArg};
2500 /*[[p]]*/
2501 }
2502 )";
2503 std::string BraceEllisionCode = R"(
2504 struct A {
2505 int Foo;
2506 };
2507
2508 struct B {
2509 int Bar;
2510 A Baz;
2511 int Qux;
2512 };
2513
2514 void target(int BarArg, int FooArg, int QuxArg) {
2515 B Quux = {BarArg, FooArg, QuxArg};
2516 /*[[p]]*/
2517 }
2518 )";
2519 for (const std::string &Code : {BracesCode, BraceEllisionCode}) {
2520 runDataflow(
2521 Code, [](llvm::ArrayRef<
2522 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2523 Results,
2524 ASTContext &ASTCtx) {
2525 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2526 const Environment &Env = Results[0].second.Env;
2527
2528 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2529 ASSERT_THAT(FooDecl, NotNull());
2530
2531 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2532 ASSERT_THAT(BarDecl, NotNull());
2533
2534 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2535 ASSERT_THAT(BazDecl, NotNull());
2536
2537 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
2538 ASSERT_THAT(QuxDecl, NotNull());
2539
2540 const ValueDecl *FooArgDecl = findValueDecl(ASTCtx, "FooArg");
2541 ASSERT_THAT(FooArgDecl, NotNull());
2542
2543 const ValueDecl *BarArgDecl = findValueDecl(ASTCtx, "BarArg");
2544 ASSERT_THAT(BarArgDecl, NotNull());
2545
2546 const ValueDecl *QuxArgDecl = findValueDecl(ASTCtx, "QuxArg");
2547 ASSERT_THAT(QuxArgDecl, NotNull());
2548
2549 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
2550 ASSERT_THAT(QuuxDecl, NotNull());
2551
2552 const auto *FooArgVal =
2553 cast<IntegerValue>(Env.getValue(*FooArgDecl, SkipPast::None));
2554 const auto *BarArgVal =
2555 cast<IntegerValue>(Env.getValue(*BarArgDecl, SkipPast::None));
2556 const auto *QuxArgVal =
2557 cast<IntegerValue>(Env.getValue(*QuxArgDecl, SkipPast::None));
2558
2559 const auto *QuuxVal =
2560 cast<StructValue>(Env.getValue(*QuuxDecl, SkipPast::None));
2561 ASSERT_THAT(QuuxVal, NotNull());
2562
2563 const auto *BazVal = cast<StructValue>(QuuxVal->getChild(*BazDecl));
2564 ASSERT_THAT(BazVal, NotNull());
2565
2566 EXPECT_EQ(QuuxVal->getChild(*BarDecl), BarArgVal);
2567 EXPECT_EQ(BazVal->getChild(*FooDecl), FooArgVal);
2568 EXPECT_EQ(QuuxVal->getChild(*QuxDecl), QuxArgVal);
2569 });
2570 }
2571 }
2572
TEST(TransferTest,AssignToUnionMember)2573 TEST(TransferTest, AssignToUnionMember) {
2574 std::string Code = R"(
2575 union A {
2576 int Foo;
2577 };
2578
2579 void target(int Bar) {
2580 A Baz;
2581 Baz.Foo = Bar;
2582 // [[p]]
2583 }
2584 )";
2585 runDataflow(Code,
2586 [](llvm::ArrayRef<
2587 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2588 Results,
2589 ASTContext &ASTCtx) {
2590 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2591 const Environment &Env = Results[0].second.Env;
2592
2593 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2594 ASSERT_THAT(BazDecl, NotNull());
2595 ASSERT_TRUE(BazDecl->getType()->isUnionType());
2596
2597 const auto *BazLoc = dyn_cast_or_null<AggregateStorageLocation>(
2598 Env.getStorageLocation(*BazDecl, SkipPast::None));
2599 ASSERT_THAT(BazLoc, NotNull());
2600
2601 // FIXME: Add support for union types.
2602 EXPECT_THAT(Env.getValue(*BazLoc), IsNull());
2603 });
2604 }
2605
TEST(TransferTest,AssignFromBoolLiteral)2606 TEST(TransferTest, AssignFromBoolLiteral) {
2607 std::string Code = R"(
2608 void target() {
2609 bool Foo = true;
2610 bool Bar = false;
2611 // [[p]]
2612 }
2613 )";
2614 runDataflow(Code,
2615 [](llvm::ArrayRef<
2616 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2617 Results,
2618 ASTContext &ASTCtx) {
2619 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2620 const Environment &Env = Results[0].second.Env;
2621
2622 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2623 ASSERT_THAT(FooDecl, NotNull());
2624
2625 const auto *FooVal = dyn_cast_or_null<AtomicBoolValue>(
2626 Env.getValue(*FooDecl, SkipPast::None));
2627 ASSERT_THAT(FooVal, NotNull());
2628
2629 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2630 ASSERT_THAT(BarDecl, NotNull());
2631
2632 const auto *BarVal = dyn_cast_or_null<AtomicBoolValue>(
2633 Env.getValue(*BarDecl, SkipPast::None));
2634 ASSERT_THAT(BarVal, NotNull());
2635
2636 EXPECT_EQ(FooVal, &Env.getBoolLiteralValue(true));
2637 EXPECT_EQ(BarVal, &Env.getBoolLiteralValue(false));
2638 });
2639 }
2640
TEST(TransferTest,AssignFromCompositeBoolExpression)2641 TEST(TransferTest, AssignFromCompositeBoolExpression) {
2642 {
2643 std::string Code = R"(
2644 void target(bool Foo, bool Bar, bool Qux) {
2645 bool Baz = (Foo) && (Bar || Qux);
2646 // [[p]]
2647 }
2648 )";
2649 runDataflow(
2650 Code, [](llvm::ArrayRef<
2651 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2652 Results,
2653 ASTContext &ASTCtx) {
2654 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2655 const Environment &Env = Results[0].second.Env;
2656
2657 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2658 ASSERT_THAT(FooDecl, NotNull());
2659
2660 const auto *FooVal = dyn_cast_or_null<BoolValue>(
2661 Env.getValue(*FooDecl, SkipPast::None));
2662 ASSERT_THAT(FooVal, NotNull());
2663
2664 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2665 ASSERT_THAT(BarDecl, NotNull());
2666
2667 const auto *BarVal = dyn_cast_or_null<BoolValue>(
2668 Env.getValue(*BarDecl, SkipPast::None));
2669 ASSERT_THAT(BarVal, NotNull());
2670
2671 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
2672 ASSERT_THAT(QuxDecl, NotNull());
2673
2674 const auto *QuxVal = dyn_cast_or_null<BoolValue>(
2675 Env.getValue(*QuxDecl, SkipPast::None));
2676 ASSERT_THAT(QuxVal, NotNull());
2677
2678 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2679 ASSERT_THAT(BazDecl, NotNull());
2680
2681 const auto *BazVal = dyn_cast_or_null<ConjunctionValue>(
2682 Env.getValue(*BazDecl, SkipPast::None));
2683 ASSERT_THAT(BazVal, NotNull());
2684 EXPECT_EQ(&BazVal->getLeftSubValue(), FooVal);
2685
2686 const auto *BazRightSubValVal =
2687 cast<DisjunctionValue>(&BazVal->getRightSubValue());
2688 EXPECT_EQ(&BazRightSubValVal->getLeftSubValue(), BarVal);
2689 EXPECT_EQ(&BazRightSubValVal->getRightSubValue(), QuxVal);
2690 });
2691 }
2692
2693 {
2694 std::string Code = R"(
2695 void target(bool Foo, bool Bar, bool Qux) {
2696 bool Baz = (Foo && Qux) || (Bar);
2697 // [[p]]
2698 }
2699 )";
2700 runDataflow(
2701 Code, [](llvm::ArrayRef<
2702 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2703 Results,
2704 ASTContext &ASTCtx) {
2705 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2706 const Environment &Env = Results[0].second.Env;
2707
2708 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2709 ASSERT_THAT(FooDecl, NotNull());
2710
2711 const auto *FooVal = dyn_cast_or_null<BoolValue>(
2712 Env.getValue(*FooDecl, SkipPast::None));
2713 ASSERT_THAT(FooVal, NotNull());
2714
2715 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2716 ASSERT_THAT(BarDecl, NotNull());
2717
2718 const auto *BarVal = dyn_cast_or_null<BoolValue>(
2719 Env.getValue(*BarDecl, SkipPast::None));
2720 ASSERT_THAT(BarVal, NotNull());
2721
2722 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
2723 ASSERT_THAT(QuxDecl, NotNull());
2724
2725 const auto *QuxVal = dyn_cast_or_null<BoolValue>(
2726 Env.getValue(*QuxDecl, SkipPast::None));
2727 ASSERT_THAT(QuxVal, NotNull());
2728
2729 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
2730 ASSERT_THAT(BazDecl, NotNull());
2731
2732 const auto *BazVal = dyn_cast_or_null<DisjunctionValue>(
2733 Env.getValue(*BazDecl, SkipPast::None));
2734 ASSERT_THAT(BazVal, NotNull());
2735
2736 const auto *BazLeftSubValVal =
2737 cast<ConjunctionValue>(&BazVal->getLeftSubValue());
2738 EXPECT_EQ(&BazLeftSubValVal->getLeftSubValue(), FooVal);
2739 EXPECT_EQ(&BazLeftSubValVal->getRightSubValue(), QuxVal);
2740
2741 EXPECT_EQ(&BazVal->getRightSubValue(), BarVal);
2742 });
2743 }
2744
2745 {
2746 std::string Code = R"(
2747 void target(bool A, bool B, bool C, bool D) {
2748 bool Foo = ((A && B) && C) && D;
2749 // [[p]]
2750 }
2751 )";
2752 runDataflow(
2753 Code, [](llvm::ArrayRef<
2754 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2755 Results,
2756 ASTContext &ASTCtx) {
2757 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2758 const Environment &Env = Results[0].second.Env;
2759
2760 const ValueDecl *ADecl = findValueDecl(ASTCtx, "A");
2761 ASSERT_THAT(ADecl, NotNull());
2762
2763 const auto *AVal =
2764 dyn_cast_or_null<BoolValue>(Env.getValue(*ADecl, SkipPast::None));
2765 ASSERT_THAT(AVal, NotNull());
2766
2767 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B");
2768 ASSERT_THAT(BDecl, NotNull());
2769
2770 const auto *BVal =
2771 dyn_cast_or_null<BoolValue>(Env.getValue(*BDecl, SkipPast::None));
2772 ASSERT_THAT(BVal, NotNull());
2773
2774 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C");
2775 ASSERT_THAT(CDecl, NotNull());
2776
2777 const auto *CVal =
2778 dyn_cast_or_null<BoolValue>(Env.getValue(*CDecl, SkipPast::None));
2779 ASSERT_THAT(CVal, NotNull());
2780
2781 const ValueDecl *DDecl = findValueDecl(ASTCtx, "D");
2782 ASSERT_THAT(DDecl, NotNull());
2783
2784 const auto *DVal =
2785 dyn_cast_or_null<BoolValue>(Env.getValue(*DDecl, SkipPast::None));
2786 ASSERT_THAT(DVal, NotNull());
2787
2788 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2789 ASSERT_THAT(FooDecl, NotNull());
2790
2791 const auto *FooVal = dyn_cast_or_null<ConjunctionValue>(
2792 Env.getValue(*FooDecl, SkipPast::None));
2793 ASSERT_THAT(FooVal, NotNull());
2794
2795 const auto &FooLeftSubVal =
2796 cast<ConjunctionValue>(FooVal->getLeftSubValue());
2797 const auto &FooLeftLeftSubVal =
2798 cast<ConjunctionValue>(FooLeftSubVal.getLeftSubValue());
2799 EXPECT_EQ(&FooLeftLeftSubVal.getLeftSubValue(), AVal);
2800 EXPECT_EQ(&FooLeftLeftSubVal.getRightSubValue(), BVal);
2801 EXPECT_EQ(&FooLeftSubVal.getRightSubValue(), CVal);
2802 EXPECT_EQ(&FooVal->getRightSubValue(), DVal);
2803 });
2804 }
2805 }
2806
TEST(TransferTest,AssignFromBoolNegation)2807 TEST(TransferTest, AssignFromBoolNegation) {
2808 std::string Code = R"(
2809 void target() {
2810 bool Foo = true;
2811 bool Bar = !(Foo);
2812 // [[p]]
2813 }
2814 )";
2815 runDataflow(Code,
2816 [](llvm::ArrayRef<
2817 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2818 Results,
2819 ASTContext &ASTCtx) {
2820 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2821 const Environment &Env = Results[0].second.Env;
2822
2823 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2824 ASSERT_THAT(FooDecl, NotNull());
2825
2826 const auto *FooVal = dyn_cast_or_null<AtomicBoolValue>(
2827 Env.getValue(*FooDecl, SkipPast::None));
2828 ASSERT_THAT(FooVal, NotNull());
2829
2830 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2831 ASSERT_THAT(BarDecl, NotNull());
2832
2833 const auto *BarVal = dyn_cast_or_null<NegationValue>(
2834 Env.getValue(*BarDecl, SkipPast::None));
2835 ASSERT_THAT(BarVal, NotNull());
2836
2837 EXPECT_EQ(&BarVal->getSubVal(), FooVal);
2838 });
2839 }
2840
TEST(TransferTest,BuiltinExpect)2841 TEST(TransferTest, BuiltinExpect) {
2842 std::string Code = R"(
2843 void target(long Foo) {
2844 long Bar = __builtin_expect(Foo, true);
2845 /*[[p]]*/
2846 }
2847 )";
2848 runDataflow(Code,
2849 [](llvm::ArrayRef<
2850 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2851 Results,
2852 ASTContext &ASTCtx) {
2853 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2854 const auto &Env = Results[0].second.Env;
2855
2856 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2857 ASSERT_THAT(FooDecl, NotNull());
2858
2859 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2860 ASSERT_THAT(BarDecl, NotNull());
2861
2862 EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None),
2863 Env.getValue(*BarDecl, SkipPast::None));
2864 });
2865 }
2866
2867 // `__builtin_expect` takes and returns a `long` argument, so other types
2868 // involve casts. This verifies that we identify the input and output in that
2869 // case.
TEST(TransferTest,BuiltinExpectBoolArg)2870 TEST(TransferTest, BuiltinExpectBoolArg) {
2871 std::string Code = R"(
2872 void target(bool Foo) {
2873 bool Bar = __builtin_expect(Foo, true);
2874 /*[[p]]*/
2875 }
2876 )";
2877 runDataflow(Code,
2878 [](llvm::ArrayRef<
2879 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2880 Results,
2881 ASTContext &ASTCtx) {
2882 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2883 const auto &Env = Results[0].second.Env;
2884
2885 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2886 ASSERT_THAT(FooDecl, NotNull());
2887
2888 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2889 ASSERT_THAT(BarDecl, NotNull());
2890
2891 EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None),
2892 Env.getValue(*BarDecl, SkipPast::None));
2893 });
2894 }
2895
TEST(TransferTest,BuiltinUnreachable)2896 TEST(TransferTest, BuiltinUnreachable) {
2897 std::string Code = R"(
2898 void target(bool Foo) {
2899 bool Bar = false;
2900 if (Foo)
2901 Bar = Foo;
2902 else
2903 __builtin_unreachable();
2904 (void)0;
2905 /*[[p]]*/
2906 }
2907 )";
2908 runDataflow(Code,
2909 [](llvm::ArrayRef<
2910 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2911 Results,
2912 ASTContext &ASTCtx) {
2913 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2914 const auto &Env = Results[0].second.Env;
2915
2916 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2917 ASSERT_THAT(FooDecl, NotNull());
2918
2919 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2920 ASSERT_THAT(BarDecl, NotNull());
2921
2922 // `__builtin_unreachable` promises that the code is
2923 // unreachable, so the compiler treats the "then" branch as the
2924 // only possible predecessor of this statement.
2925 EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None),
2926 Env.getValue(*BarDecl, SkipPast::None));
2927 });
2928 }
2929
TEST(TransferTest,BuiltinTrap)2930 TEST(TransferTest, BuiltinTrap) {
2931 std::string Code = R"(
2932 void target(bool Foo) {
2933 bool Bar = false;
2934 if (Foo)
2935 Bar = Foo;
2936 else
2937 __builtin_trap();
2938 (void)0;
2939 /*[[p]]*/
2940 }
2941 )";
2942 runDataflow(Code,
2943 [](llvm::ArrayRef<
2944 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2945 Results,
2946 ASTContext &ASTCtx) {
2947 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2948 const auto &Env = Results[0].second.Env;
2949
2950 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2951 ASSERT_THAT(FooDecl, NotNull());
2952
2953 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2954 ASSERT_THAT(BarDecl, NotNull());
2955
2956 // `__builtin_trap` ensures program termination, so only the
2957 // "then" branch is a predecessor of this statement.
2958 EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None),
2959 Env.getValue(*BarDecl, SkipPast::None));
2960 });
2961 }
2962
TEST(TransferTest,BuiltinDebugTrap)2963 TEST(TransferTest, BuiltinDebugTrap) {
2964 std::string Code = R"(
2965 void target(bool Foo) {
2966 bool Bar = false;
2967 if (Foo)
2968 Bar = Foo;
2969 else
2970 __builtin_debugtrap();
2971 (void)0;
2972 /*[[p]]*/
2973 }
2974 )";
2975 runDataflow(Code,
2976 [](llvm::ArrayRef<
2977 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
2978 Results,
2979 ASTContext &ASTCtx) {
2980 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
2981 const auto &Env = Results[0].second.Env;
2982
2983 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
2984 ASSERT_THAT(FooDecl, NotNull());
2985
2986 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
2987 ASSERT_THAT(BarDecl, NotNull());
2988
2989 // `__builtin_debugtrap` doesn't ensure program termination.
2990 EXPECT_NE(Env.getValue(*FooDecl, SkipPast::None),
2991 Env.getValue(*BarDecl, SkipPast::None));
2992 });
2993 }
2994
TEST(TransferTest,StaticIntSingleVarDecl)2995 TEST(TransferTest, StaticIntSingleVarDecl) {
2996 std::string Code = R"(
2997 void target() {
2998 static int Foo;
2999 // [[p]]
3000 }
3001 )";
3002 runDataflow(Code,
3003 [](llvm::ArrayRef<
3004 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3005 Results,
3006 ASTContext &ASTCtx) {
3007 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
3008 const Environment &Env = Results[0].second.Env;
3009
3010 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3011 ASSERT_THAT(FooDecl, NotNull());
3012
3013 const StorageLocation *FooLoc =
3014 Env.getStorageLocation(*FooDecl, SkipPast::None);
3015 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
3016
3017 const Value *FooVal = Env.getValue(*FooLoc);
3018 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
3019 });
3020 }
3021
TEST(TransferTest,StaticIntGroupVarDecl)3022 TEST(TransferTest, StaticIntGroupVarDecl) {
3023 std::string Code = R"(
3024 void target() {
3025 static int Foo, Bar;
3026 (void)0;
3027 // [[p]]
3028 }
3029 )";
3030 runDataflow(Code,
3031 [](llvm::ArrayRef<
3032 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3033 Results,
3034 ASTContext &ASTCtx) {
3035 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
3036 const Environment &Env = Results[0].second.Env;
3037
3038 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3039 ASSERT_THAT(FooDecl, NotNull());
3040
3041 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3042 ASSERT_THAT(BarDecl, NotNull());
3043
3044 const StorageLocation *FooLoc =
3045 Env.getStorageLocation(*FooDecl, SkipPast::None);
3046 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
3047
3048 const StorageLocation *BarLoc =
3049 Env.getStorageLocation(*BarDecl, SkipPast::None);
3050 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
3051
3052 const Value *FooVal = Env.getValue(*FooLoc);
3053 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
3054
3055 const Value *BarVal = Env.getValue(*BarLoc);
3056 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
3057
3058 EXPECT_NE(FooVal, BarVal);
3059 });
3060 }
3061
TEST(TransferTest,GlobalIntVarDecl)3062 TEST(TransferTest, GlobalIntVarDecl) {
3063 std::string Code = R"(
3064 static int Foo;
3065
3066 void target() {
3067 int Bar = Foo;
3068 int Baz = Foo;
3069 // [[p]]
3070 }
3071 )";
3072 runDataflow(Code,
3073 [](llvm::ArrayRef<
3074 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3075 Results,
3076 ASTContext &ASTCtx) {
3077 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
3078 const Environment &Env = Results[0].second.Env;
3079
3080 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3081 ASSERT_THAT(BarDecl, NotNull());
3082
3083 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3084 ASSERT_THAT(BazDecl, NotNull());
3085
3086 const Value *BarVal =
3087 cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None));
3088 const Value *BazVal =
3089 cast<IntegerValue>(Env.getValue(*BazDecl, SkipPast::None));
3090 EXPECT_EQ(BarVal, BazVal);
3091 });
3092 }
3093
TEST(TransferTest,StaticMemberIntVarDecl)3094 TEST(TransferTest, StaticMemberIntVarDecl) {
3095 std::string Code = R"(
3096 struct A {
3097 static int Foo;
3098 };
3099
3100 void target(A a) {
3101 int Bar = a.Foo;
3102 int Baz = a.Foo;
3103 // [[p]]
3104 }
3105 )";
3106 runDataflow(Code,
3107 [](llvm::ArrayRef<
3108 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3109 Results,
3110 ASTContext &ASTCtx) {
3111 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
3112 const Environment &Env = Results[0].second.Env;
3113
3114 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3115 ASSERT_THAT(BarDecl, NotNull());
3116
3117 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3118 ASSERT_THAT(BazDecl, NotNull());
3119
3120 const Value *BarVal =
3121 cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None));
3122 const Value *BazVal =
3123 cast<IntegerValue>(Env.getValue(*BazDecl, SkipPast::None));
3124 EXPECT_EQ(BarVal, BazVal);
3125 });
3126 }
3127
TEST(TransferTest,StaticMemberRefVarDecl)3128 TEST(TransferTest, StaticMemberRefVarDecl) {
3129 std::string Code = R"(
3130 struct A {
3131 static int &Foo;
3132 };
3133
3134 void target(A a) {
3135 int Bar = a.Foo;
3136 int Baz = a.Foo;
3137 // [[p]]
3138 }
3139 )";
3140 runDataflow(Code,
3141 [](llvm::ArrayRef<
3142 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3143 Results,
3144 ASTContext &ASTCtx) {
3145 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
3146 const Environment &Env = Results[0].second.Env;
3147
3148 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3149 ASSERT_THAT(BarDecl, NotNull());
3150
3151 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3152 ASSERT_THAT(BazDecl, NotNull());
3153
3154 const Value *BarVal =
3155 cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None));
3156 const Value *BazVal =
3157 cast<IntegerValue>(Env.getValue(*BazDecl, SkipPast::None));
3158 EXPECT_EQ(BarVal, BazVal);
3159 });
3160 }
3161
TEST(TransferTest,AssignMemberBeforeCopy)3162 TEST(TransferTest, AssignMemberBeforeCopy) {
3163 std::string Code = R"(
3164 struct A {
3165 int Foo;
3166 };
3167
3168 void target() {
3169 A A1;
3170 A A2;
3171 int Bar;
3172 A1.Foo = Bar;
3173 A2 = A1;
3174 // [[p]]
3175 }
3176 )";
3177 runDataflow(Code,
3178 [](llvm::ArrayRef<
3179 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3180 Results,
3181 ASTContext &ASTCtx) {
3182 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
3183 const Environment &Env = Results[0].second.Env;
3184
3185 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3186 ASSERT_THAT(FooDecl, NotNull());
3187
3188 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3189 ASSERT_THAT(BarDecl, NotNull());
3190
3191 const ValueDecl *A1Decl = findValueDecl(ASTCtx, "A1");
3192 ASSERT_THAT(A1Decl, NotNull());
3193
3194 const ValueDecl *A2Decl = findValueDecl(ASTCtx, "A2");
3195 ASSERT_THAT(A2Decl, NotNull());
3196
3197 const auto *BarVal =
3198 cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None));
3199
3200 const auto *A2Val =
3201 cast<StructValue>(Env.getValue(*A2Decl, SkipPast::None));
3202 EXPECT_EQ(A2Val->getChild(*FooDecl), BarVal);
3203 });
3204 }
3205
TEST(TransferTest,BooleanEquality)3206 TEST(TransferTest, BooleanEquality) {
3207 std::string Code = R"(
3208 void target(bool Bar) {
3209 bool Foo = true;
3210 if (Bar == Foo) {
3211 (void)0;
3212 /*[[p-then]]*/
3213 } else {
3214 (void)0;
3215 /*[[p-else]]*/
3216 }
3217 }
3218 )";
3219 runDataflow(
3220 Code, [](llvm::ArrayRef<
3221 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3222 Results,
3223 ASTContext &ASTCtx) {
3224 ASSERT_THAT(Results, ElementsAre(Pair("p-else", _), Pair("p-then", _)));
3225 const Environment &EnvElse = Results[0].second.Env;
3226 const Environment &EnvThen = Results[1].second.Env;
3227
3228 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3229 ASSERT_THAT(BarDecl, NotNull());
3230
3231 auto &BarValThen =
3232 *cast<BoolValue>(EnvThen.getValue(*BarDecl, SkipPast::None));
3233 EXPECT_TRUE(EnvThen.flowConditionImplies(BarValThen));
3234
3235 auto &BarValElse =
3236 *cast<BoolValue>(EnvElse.getValue(*BarDecl, SkipPast::None));
3237 EXPECT_FALSE(EnvElse.flowConditionImplies(BarValElse));
3238 });
3239 }
3240
TEST(TransferTest,BooleanInequality)3241 TEST(TransferTest, BooleanInequality) {
3242 std::string Code = R"(
3243 void target(bool Bar) {
3244 bool Foo = true;
3245 if (Bar != Foo) {
3246 (void)0;
3247 /*[[p-then]]*/
3248 } else {
3249 (void)0;
3250 /*[[p-else]]*/
3251 }
3252 }
3253 )";
3254 runDataflow(
3255 Code, [](llvm::ArrayRef<
3256 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3257 Results,
3258 ASTContext &ASTCtx) {
3259 ASSERT_THAT(Results, ElementsAre(Pair("p-else", _), Pair("p-then", _)));
3260 const Environment &EnvElse = Results[0].second.Env;
3261 const Environment &EnvThen = Results[1].second.Env;
3262
3263 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3264 ASSERT_THAT(BarDecl, NotNull());
3265
3266 auto &BarValThen =
3267 *cast<BoolValue>(EnvThen.getValue(*BarDecl, SkipPast::None));
3268 EXPECT_FALSE(EnvThen.flowConditionImplies(BarValThen));
3269
3270 auto &BarValElse =
3271 *cast<BoolValue>(EnvElse.getValue(*BarDecl, SkipPast::None));
3272 EXPECT_TRUE(EnvElse.flowConditionImplies(BarValElse));
3273 });
3274 }
3275
TEST(TransferTest,CorrelatedBranches)3276 TEST(TransferTest, CorrelatedBranches) {
3277 std::string Code = R"(
3278 void target(bool B, bool C) {
3279 if (B) {
3280 return;
3281 }
3282 (void)0;
3283 /*[[p0]]*/
3284 if (C) {
3285 B = true;
3286 /*[[p1]]*/
3287 }
3288 if (B) {
3289 (void)0;
3290 /*[[p2]]*/
3291 }
3292 }
3293 )";
3294 runDataflow(
3295 Code, [](llvm::ArrayRef<
3296 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3297 Results,
3298 ASTContext &ASTCtx) {
3299 ASSERT_THAT(Results, SizeIs(3));
3300
3301 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C");
3302 ASSERT_THAT(CDecl, NotNull());
3303
3304 {
3305 ASSERT_THAT(Results[2], Pair("p0", _));
3306 const Environment &Env = Results[2].second.Env;
3307 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B");
3308 ASSERT_THAT(BDecl, NotNull());
3309 auto &BVal = *cast<BoolValue>(Env.getValue(*BDecl, SkipPast::None));
3310
3311 EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(BVal)));
3312 }
3313
3314 {
3315 ASSERT_THAT(Results[1], Pair("p1", _));
3316 const Environment &Env = Results[1].second.Env;
3317 auto &CVal = *cast<BoolValue>(Env.getValue(*CDecl, SkipPast::None));
3318 EXPECT_TRUE(Env.flowConditionImplies(CVal));
3319 }
3320
3321 {
3322 ASSERT_THAT(Results[0], Pair("p2", _));
3323 const Environment &Env = Results[0].second.Env;
3324 auto &CVal = *cast<BoolValue>(Env.getValue(*CDecl, SkipPast::None));
3325 EXPECT_TRUE(Env.flowConditionImplies(CVal));
3326 }
3327 });
3328 }
3329
TEST(TransferTest,LoopWithAssignmentConverges)3330 TEST(TransferTest, LoopWithAssignmentConverges) {
3331 std::string Code = R"(
3332
3333 bool &foo();
3334
3335 void target() {
3336 do {
3337 bool Bar = foo();
3338 if (Bar) break;
3339 (void)Bar;
3340 /*[[p]]*/
3341 } while (true);
3342 }
3343 )";
3344 // The key property that we are verifying is implicit in `runDataflow` --
3345 // namely, that the analysis succeeds, rather than hitting the maximum number
3346 // of iterations.
3347 runDataflow(
3348 Code, [](llvm::ArrayRef<
3349 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3350 Results,
3351 ASTContext &ASTCtx) {
3352 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
3353 const Environment &Env = Results[0].second.Env;
3354
3355 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3356 ASSERT_THAT(BarDecl, NotNull());
3357
3358 auto &BarVal = *cast<BoolValue>(Env.getValue(*BarDecl, SkipPast::None));
3359 EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(BarVal)));
3360 });
3361 }
3362
TEST(TransferTest,LoopWithReferenceAssignmentConverges)3363 TEST(TransferTest, LoopWithReferenceAssignmentConverges) {
3364 std::string Code = R"(
3365
3366 bool &foo();
3367
3368 void target() {
3369 do {
3370 bool& Bar = foo();
3371 if (Bar) break;
3372 (void)Bar;
3373 /*[[p]]*/
3374 } while (true);
3375 }
3376 )";
3377 // The key property that we are verifying is implicit in `runDataflow` --
3378 // namely, that the analysis succeeds, rather than hitting the maximum number
3379 // of iterations.
3380 runDataflow(
3381 Code, [](llvm::ArrayRef<
3382 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3383 Results,
3384 ASTContext &ASTCtx) {
3385 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
3386 const Environment &Env = Results[0].second.Env;
3387
3388 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3389 ASSERT_THAT(BarDecl, NotNull());
3390
3391 auto &BarVal =
3392 *cast<BoolValue>(Env.getValue(*BarDecl, SkipPast::Reference));
3393 EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(BarVal)));
3394 });
3395 }
3396
TEST(TransferTest,LoopWithStructReferenceAssignmentConverges)3397 TEST(TransferTest, LoopWithStructReferenceAssignmentConverges) {
3398 std::string Code = R"(
3399 struct Lookup {
3400 int x;
3401 };
3402
3403 void target(Lookup val, bool b) {
3404 const Lookup* l = nullptr;
3405 while (b) {
3406 l = &val;
3407 /*[[p-inner]]*/
3408 }
3409 (void)0;
3410 /*[[p-outer]]*/
3411 }
3412 )";
3413 // The key property that we are verifying is implicit in `runDataflow` --
3414 // namely, that the analysis succeeds, rather than hitting the maximum number
3415 // of iterations.
3416 runDataflow(
3417 Code, [](llvm::ArrayRef<
3418 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3419 Results,
3420 ASTContext &ASTCtx) {
3421 ASSERT_THAT(Results,
3422 ElementsAre(Pair("p-outer", _), Pair("p-inner", _)));
3423 const Environment &OuterEnv = Results[0].second.Env;
3424 const Environment &InnerEnv = Results[1].second.Env;
3425
3426 const ValueDecl *ValDecl = findValueDecl(ASTCtx, "val");
3427 ASSERT_THAT(ValDecl, NotNull());
3428
3429 const ValueDecl *LDecl = findValueDecl(ASTCtx, "l");
3430 ASSERT_THAT(LDecl, NotNull());
3431
3432 // Inner.
3433 auto *LVal =
3434 dyn_cast<PointerValue>(InnerEnv.getValue(*LDecl, SkipPast::None));
3435 ASSERT_THAT(LVal, NotNull());
3436
3437 EXPECT_EQ(&LVal->getPointeeLoc(),
3438 InnerEnv.getStorageLocation(*ValDecl, SkipPast::Reference));
3439
3440 // Outer.
3441 LVal =
3442 dyn_cast<PointerValue>(OuterEnv.getValue(*LDecl, SkipPast::None));
3443 ASSERT_THAT(LVal, NotNull());
3444
3445 // The loop body may not have been executed, so we should not conclude
3446 // that `l` points to `val`.
3447 EXPECT_NE(&LVal->getPointeeLoc(),
3448 OuterEnv.getStorageLocation(*ValDecl, SkipPast::Reference));
3449 });
3450 }
3451
TEST(TransferTest,DoesNotCrashOnUnionThisExpr)3452 TEST(TransferTest, DoesNotCrashOnUnionThisExpr) {
3453 std::string Code = R"(
3454 union Union {
3455 int A;
3456 float B;
3457 };
3458
3459 void foo() {
3460 Union A;
3461 Union B;
3462 A = B;
3463 }
3464 )";
3465 // This is a crash regression test when calling the transfer function on a
3466 // `CXXThisExpr` that refers to a union.
3467 runDataflow(
3468 Code,
3469 [](llvm::ArrayRef<
3470 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>,
3471 ASTContext &) {},
3472 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator=");
3473 }
3474
TEST(TransferTest,StructuredBindingAssignFromStructIntMembersToRefs)3475 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToRefs) {
3476 std::string Code = R"(
3477 struct A {
3478 int Foo;
3479 int Bar;
3480 };
3481
3482 void target() {
3483 int Qux;
3484 A Baz;
3485 Baz.Foo = Qux;
3486 auto &FooRef = Baz.Foo;
3487 auto &BarRef = Baz.Bar;
3488 auto &[BoundFooRef, BoundBarRef] = Baz;
3489 // [[p]]
3490 }
3491 )";
3492 runDataflow(
3493 Code, [](llvm::ArrayRef<
3494 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3495 Results,
3496 ASTContext &ASTCtx) {
3497 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
3498 const Environment &Env = Results[0].second.Env;
3499
3500 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef");
3501 ASSERT_THAT(FooRefDecl, NotNull());
3502
3503 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef");
3504 ASSERT_THAT(BarRefDecl, NotNull());
3505
3506 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
3507 ASSERT_THAT(QuxDecl, NotNull());
3508
3509 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef");
3510 ASSERT_THAT(BoundFooRefDecl, NotNull());
3511
3512 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef");
3513 ASSERT_THAT(BoundBarRefDecl, NotNull());
3514
3515 const StorageLocation *FooRefLoc =
3516 Env.getStorageLocation(*FooRefDecl, SkipPast::Reference);
3517 ASSERT_THAT(FooRefLoc, NotNull());
3518
3519 const StorageLocation *BarRefLoc =
3520 Env.getStorageLocation(*BarRefDecl, SkipPast::Reference);
3521 ASSERT_THAT(BarRefLoc, NotNull());
3522
3523 const Value *QuxVal = Env.getValue(*QuxDecl, SkipPast::None);
3524 ASSERT_THAT(QuxVal, NotNull());
3525
3526 const StorageLocation *BoundFooRefLoc =
3527 Env.getStorageLocation(*BoundFooRefDecl, SkipPast::Reference);
3528 EXPECT_EQ(BoundFooRefLoc, FooRefLoc);
3529
3530 const StorageLocation *BoundBarRefLoc =
3531 Env.getStorageLocation(*BoundBarRefDecl, SkipPast::Reference);
3532 EXPECT_EQ(BoundBarRefLoc, BarRefLoc);
3533
3534 EXPECT_EQ(Env.getValue(*BoundFooRefDecl, SkipPast::Reference), QuxVal);
3535 });
3536 }
3537
TEST(TransferTest,StructuredBindingAssignFromStructRefMembersToRefs)3538 TEST(TransferTest, StructuredBindingAssignFromStructRefMembersToRefs) {
3539 std::string Code = R"(
3540 struct A {
3541 int &Foo;
3542 int &Bar;
3543 };
3544
3545 void target(A Baz) {
3546 int Qux;
3547 Baz.Foo = Qux;
3548 auto &FooRef = Baz.Foo;
3549 auto &BarRef = Baz.Bar;
3550 auto &[BoundFooRef, BoundBarRef] = Baz;
3551 // [[p]]
3552 }
3553 )";
3554 runDataflow(
3555 Code, [](llvm::ArrayRef<
3556 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3557 Results,
3558 ASTContext &ASTCtx) {
3559 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
3560 const Environment &Env = Results[0].second.Env;
3561
3562 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef");
3563 ASSERT_THAT(FooRefDecl, NotNull());
3564
3565 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef");
3566 ASSERT_THAT(BarRefDecl, NotNull());
3567
3568 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
3569 ASSERT_THAT(QuxDecl, NotNull());
3570
3571 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef");
3572 ASSERT_THAT(BoundFooRefDecl, NotNull());
3573
3574 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef");
3575 ASSERT_THAT(BoundBarRefDecl, NotNull());
3576
3577 const StorageLocation *FooRefLoc =
3578 Env.getStorageLocation(*FooRefDecl, SkipPast::Reference);
3579 ASSERT_THAT(FooRefLoc, NotNull());
3580
3581 const StorageLocation *BarRefLoc =
3582 Env.getStorageLocation(*BarRefDecl, SkipPast::Reference);
3583 ASSERT_THAT(BarRefLoc, NotNull());
3584
3585 const Value *QuxVal = Env.getValue(*QuxDecl, SkipPast::None);
3586 ASSERT_THAT(QuxVal, NotNull());
3587
3588 const StorageLocation *BoundFooRefLoc =
3589 Env.getStorageLocation(*BoundFooRefDecl, SkipPast::Reference);
3590 EXPECT_EQ(BoundFooRefLoc, FooRefLoc);
3591
3592 const StorageLocation *BoundBarRefLoc =
3593 Env.getStorageLocation(*BoundBarRefDecl, SkipPast::Reference);
3594 EXPECT_EQ(BoundBarRefLoc, BarRefLoc);
3595
3596 EXPECT_EQ(Env.getValue(*BoundFooRefDecl, SkipPast::Reference), QuxVal);
3597 });
3598 }
3599
TEST(TransferTest,StructuredBindingAssignFromStructIntMembersToInts)3600 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToInts) {
3601 std::string Code = R"(
3602 struct A {
3603 int Foo;
3604 int Bar;
3605 };
3606
3607 void target() {
3608 int Qux;
3609 A Baz;
3610 Baz.Foo = Qux;
3611 auto &FooRef = Baz.Foo;
3612 auto &BarRef = Baz.Bar;
3613 auto [BoundFoo, BoundBar] = Baz;
3614 // [[p]]
3615 }
3616 )";
3617 runDataflow(
3618 Code, [](llvm::ArrayRef<
3619 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3620 Results,
3621 ASTContext &ASTCtx) {
3622 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
3623 const Environment &Env = Results[0].second.Env;
3624
3625 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef");
3626 ASSERT_THAT(FooRefDecl, NotNull());
3627
3628 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef");
3629 ASSERT_THAT(BarRefDecl, NotNull());
3630
3631 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo");
3632 ASSERT_THAT(BoundFooDecl, NotNull());
3633
3634 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");
3635 ASSERT_THAT(BoundBarDecl, NotNull());
3636
3637 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
3638 ASSERT_THAT(QuxDecl, NotNull());
3639
3640 const StorageLocation *FooRefLoc =
3641 Env.getStorageLocation(*FooRefDecl, SkipPast::Reference);
3642 ASSERT_THAT(FooRefLoc, NotNull());
3643
3644 const StorageLocation *BarRefLoc =
3645 Env.getStorageLocation(*BarRefDecl, SkipPast::Reference);
3646 ASSERT_THAT(BarRefLoc, NotNull());
3647
3648 const Value *QuxVal = Env.getValue(*QuxDecl, SkipPast::None);
3649 ASSERT_THAT(QuxVal, NotNull());
3650
3651 const StorageLocation *BoundFooLoc =
3652 Env.getStorageLocation(*BoundFooDecl, SkipPast::Reference);
3653 EXPECT_NE(BoundFooLoc, FooRefLoc);
3654
3655 const StorageLocation *BoundBarLoc =
3656 Env.getStorageLocation(*BoundBarDecl, SkipPast::Reference);
3657 EXPECT_NE(BoundBarLoc, BarRefLoc);
3658
3659 EXPECT_EQ(Env.getValue(*BoundFooDecl, SkipPast::Reference), QuxVal);
3660 });
3661 }
3662
TEST(TransferTest,BinaryOperatorComma)3663 TEST(TransferTest, BinaryOperatorComma) {
3664 std::string Code = R"(
3665 void target(int Foo, int Bar) {
3666 int &Baz = (Foo, Bar);
3667 // [[p]]
3668 }
3669 )";
3670 runDataflow(Code,
3671 [](llvm::ArrayRef<
3672 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3673 Results,
3674 ASTContext &ASTCtx) {
3675 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
3676 const Environment &Env = Results[0].second.Env;
3677
3678 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3679 ASSERT_THAT(BarDecl, NotNull());
3680
3681 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
3682 ASSERT_THAT(BazDecl, NotNull());
3683
3684 const StorageLocation *BarLoc =
3685 Env.getStorageLocation(*BarDecl, SkipPast::Reference);
3686 ASSERT_THAT(BarLoc, NotNull());
3687
3688 const StorageLocation *BazLoc =
3689 Env.getStorageLocation(*BazDecl, SkipPast::Reference);
3690 EXPECT_EQ(BazLoc, BarLoc);
3691 });
3692 }
3693
TEST(TransferTest,IfStmtBranchExtendsFlowCondition)3694 TEST(TransferTest, IfStmtBranchExtendsFlowCondition) {
3695 std::string Code = R"(
3696 void target(bool Foo) {
3697 if (Foo) {
3698 (void)0;
3699 // [[if_then]]
3700 } else {
3701 (void)0;
3702 // [[if_else]]
3703 }
3704 }
3705 )";
3706 runDataflow(
3707 Code, [](llvm::ArrayRef<
3708 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3709 Results,
3710 ASTContext &ASTCtx) {
3711 ASSERT_THAT(Results,
3712 ElementsAre(Pair("if_else", _), Pair("if_then", _)));
3713 const Environment &ThenEnv = Results[1].second.Env;
3714 const Environment &ElseEnv = Results[0].second.Env;
3715
3716 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3717 ASSERT_THAT(FooDecl, NotNull());
3718
3719 BoolValue &ThenFooVal =
3720 *cast<BoolValue>(ThenEnv.getValue(*FooDecl, SkipPast::None));
3721 EXPECT_TRUE(ThenEnv.flowConditionImplies(ThenFooVal));
3722
3723 BoolValue &ElseFooVal =
3724 *cast<BoolValue>(ElseEnv.getValue(*FooDecl, SkipPast::None));
3725 EXPECT_TRUE(ElseEnv.flowConditionImplies(ElseEnv.makeNot(ElseFooVal)));
3726 });
3727 }
3728
TEST(TransferTest,WhileStmtBranchExtendsFlowCondition)3729 TEST(TransferTest, WhileStmtBranchExtendsFlowCondition) {
3730 std::string Code = R"(
3731 void target(bool Foo) {
3732 while (Foo) {
3733 (void)0;
3734 // [[loop_body]]
3735 }
3736 (void)0;
3737 // [[after_loop]]
3738 }
3739 )";
3740 runDataflow(
3741 Code, [](llvm::ArrayRef<
3742 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3743 Results,
3744 ASTContext &ASTCtx) {
3745 ASSERT_THAT(Results,
3746 ElementsAre(Pair("after_loop", _), Pair("loop_body", _)));
3747 const Environment &LoopBodyEnv = Results[1].second.Env;
3748 const Environment &AfterLoopEnv = Results[0].second.Env;
3749
3750 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3751 ASSERT_THAT(FooDecl, NotNull());
3752
3753 BoolValue &LoopBodyFooVal =
3754 *cast<BoolValue>(LoopBodyEnv.getValue(*FooDecl, SkipPast::None));
3755 EXPECT_TRUE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal));
3756
3757 BoolValue &AfterLoopFooVal =
3758 *cast<BoolValue>(AfterLoopEnv.getValue(*FooDecl, SkipPast::None));
3759 EXPECT_TRUE(AfterLoopEnv.flowConditionImplies(
3760 AfterLoopEnv.makeNot(AfterLoopFooVal)));
3761 });
3762 }
3763
TEST(TransferTest,DoWhileStmtBranchExtendsFlowCondition)3764 TEST(TransferTest, DoWhileStmtBranchExtendsFlowCondition) {
3765 std::string Code = R"(
3766 void target(bool Foo) {
3767 bool Bar = true;
3768 do {
3769 (void)0;
3770 // [[loop_body]]
3771 Bar = false;
3772 } while (Foo);
3773 (void)0;
3774 // [[after_loop]]
3775 }
3776 )";
3777 runDataflow(
3778 Code, [](llvm::ArrayRef<
3779 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3780 Results,
3781 ASTContext &ASTCtx) {
3782 ASSERT_THAT(Results,
3783 ElementsAre(Pair("after_loop", _), Pair("loop_body", _)));
3784 const Environment &LoopBodyEnv = Results[1].second.Env;
3785 const Environment &AfterLoopEnv = Results[0].second.Env;
3786
3787 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3788 ASSERT_THAT(FooDecl, NotNull());
3789
3790 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3791 ASSERT_THAT(BarDecl, NotNull());
3792
3793 BoolValue &LoopBodyFooVal =
3794 *cast<BoolValue>(LoopBodyEnv.getValue(*FooDecl, SkipPast::None));
3795 BoolValue &LoopBodyBarVal =
3796 *cast<BoolValue>(LoopBodyEnv.getValue(*BarDecl, SkipPast::None));
3797 EXPECT_TRUE(LoopBodyEnv.flowConditionImplies(
3798 LoopBodyEnv.makeOr(LoopBodyBarVal, LoopBodyFooVal)));
3799
3800 BoolValue &AfterLoopFooVal =
3801 *cast<BoolValue>(AfterLoopEnv.getValue(*FooDecl, SkipPast::None));
3802 BoolValue &AfterLoopBarVal =
3803 *cast<BoolValue>(AfterLoopEnv.getValue(*BarDecl, SkipPast::None));
3804 EXPECT_TRUE(AfterLoopEnv.flowConditionImplies(
3805 AfterLoopEnv.makeNot(AfterLoopFooVal)));
3806 EXPECT_TRUE(AfterLoopEnv.flowConditionImplies(
3807 AfterLoopEnv.makeNot(AfterLoopBarVal)));
3808 });
3809 }
3810
TEST(TransferTest,ForStmtBranchExtendsFlowCondition)3811 TEST(TransferTest, ForStmtBranchExtendsFlowCondition) {
3812 std::string Code = R"(
3813 void target(bool Foo) {
3814 for (; Foo;) {
3815 (void)0;
3816 // [[loop_body]]
3817 }
3818 (void)0;
3819 // [[after_loop]]
3820 }
3821 )";
3822 runDataflow(
3823 Code, [](llvm::ArrayRef<
3824 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3825 Results,
3826 ASTContext &ASTCtx) {
3827 ASSERT_THAT(Results,
3828 ElementsAre(Pair("after_loop", _), Pair("loop_body", _)));
3829 const Environment &LoopBodyEnv = Results[1].second.Env;
3830 const Environment &AfterLoopEnv = Results[0].second.Env;
3831
3832 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3833 ASSERT_THAT(FooDecl, NotNull());
3834
3835 BoolValue &LoopBodyFooVal =
3836 *cast<BoolValue>(LoopBodyEnv.getValue(*FooDecl, SkipPast::None));
3837 EXPECT_TRUE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal));
3838
3839 BoolValue &AfterLoopFooVal =
3840 *cast<BoolValue>(AfterLoopEnv.getValue(*FooDecl, SkipPast::None));
3841 EXPECT_TRUE(AfterLoopEnv.flowConditionImplies(
3842 AfterLoopEnv.makeNot(AfterLoopFooVal)));
3843 });
3844 }
3845
TEST(TransferTest,ForStmtBranchWithoutConditionDoesNotExtendFlowCondition)3846 TEST(TransferTest, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition) {
3847 std::string Code = R"(
3848 void target(bool Foo) {
3849 for (;;) {
3850 (void)0;
3851 // [[loop_body]]
3852 }
3853 }
3854 )";
3855 runDataflow(
3856 Code, [](llvm::ArrayRef<
3857 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3858 Results,
3859 ASTContext &ASTCtx) {
3860 ASSERT_THAT(Results, ElementsAre(Pair("loop_body", _)));
3861 const Environment &LoopBodyEnv = Results[0].second.Env;
3862
3863 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3864 ASSERT_THAT(FooDecl, NotNull());
3865
3866 BoolValue &LoopBodyFooVal =
3867 *cast<BoolValue>(LoopBodyEnv.getValue(*FooDecl, SkipPast::None));
3868 EXPECT_FALSE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal));
3869 });
3870 }
3871
TEST(TransferTest,ContextSensitiveOptionDisabled)3872 TEST(TransferTest, ContextSensitiveOptionDisabled) {
3873 std::string Code = R"(
3874 bool GiveBool();
3875 void SetBool(bool &Var) { Var = true; }
3876
3877 void target() {
3878 bool Foo = GiveBool();
3879 SetBool(Foo);
3880 // [[p]]
3881 }
3882 )";
3883 runDataflow(Code,
3884 [](llvm::ArrayRef<
3885 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3886 Results,
3887 ASTContext &ASTCtx) {
3888 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
3889 const Environment &Env = Results[0].second.Env;
3890
3891 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3892 ASSERT_THAT(FooDecl, NotNull());
3893
3894 auto &FooVal =
3895 *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None));
3896 EXPECT_FALSE(Env.flowConditionImplies(FooVal));
3897 EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(FooVal)));
3898 },
3899 {/*.ApplyBuiltinTransfer=*/true,
3900 /*.BuiltinTransferOptions=*/{/*.ContextSensitive=*/false}});
3901 }
3902
TEST(TransferTest,ContextSensitiveSetTrue)3903 TEST(TransferTest, ContextSensitiveSetTrue) {
3904 std::string Code = R"(
3905 bool GiveBool();
3906 void SetBool(bool &Var) { Var = true; }
3907
3908 void target() {
3909 bool Foo = GiveBool();
3910 SetBool(Foo);
3911 // [[p]]
3912 }
3913 )";
3914 runDataflow(Code,
3915 [](llvm::ArrayRef<
3916 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3917 Results,
3918 ASTContext &ASTCtx) {
3919 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
3920 const Environment &Env = Results[0].second.Env;
3921
3922 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3923 ASSERT_THAT(FooDecl, NotNull());
3924
3925 auto &FooVal =
3926 *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None));
3927 EXPECT_TRUE(Env.flowConditionImplies(FooVal));
3928 },
3929 {/*.ApplyBuiltinTransfer=*/true,
3930 /*.BuiltinTransferOptions=*/{/*.ContextSensitive=*/true}});
3931 }
3932
TEST(TransferTest,ContextSensitiveSetFalse)3933 TEST(TransferTest, ContextSensitiveSetFalse) {
3934 std::string Code = R"(
3935 bool GiveBool();
3936 void SetBool(bool &Var) { Var = false; }
3937
3938 void target() {
3939 bool Foo = GiveBool();
3940 SetBool(Foo);
3941 // [[p]]
3942 }
3943 )";
3944 runDataflow(Code,
3945 [](llvm::ArrayRef<
3946 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
3947 Results,
3948 ASTContext &ASTCtx) {
3949 ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
3950 const Environment &Env = Results[0].second.Env;
3951
3952 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3953 ASSERT_THAT(FooDecl, NotNull());
3954
3955 auto &FooVal =
3956 *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None));
3957 EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(FooVal)));
3958 },
3959 {/*.ApplyBuiltinTransfer=*/true,
3960 /*.BuiltinTransferOptions=*/{/*.ContextSensitive=*/true}});
3961 }
3962
3963 } // namespace
3964