1 //===- unittests/Analysis/FlowSensitive/TransferTest.cpp ------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "NoopAnalysis.h" 10 #include "TestingSupport.h" 11 #include "clang/AST/ASTContext.h" 12 #include "clang/AST/Decl.h" 13 #include "clang/ASTMatchers/ASTMatchFinder.h" 14 #include "clang/ASTMatchers/ASTMatchers.h" 15 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" 16 #include "clang/Analysis/FlowSensitive/StorageLocation.h" 17 #include "clang/Analysis/FlowSensitive/Value.h" 18 #include "llvm/ADT/ArrayRef.h" 19 #include "llvm/ADT/StringRef.h" 20 #include "llvm/Support/Casting.h" 21 #include "gmock/gmock.h" 22 #include "gtest/gtest.h" 23 #include <cassert> 24 #include <string> 25 #include <utility> 26 27 namespace { 28 29 using namespace clang; 30 using namespace dataflow; 31 using ::testing::_; 32 using ::testing::ElementsAre; 33 using ::testing::IsNull; 34 using ::testing::NotNull; 35 using ::testing::Pair; 36 37 class TransferTest : public ::testing::Test { 38 protected: 39 template <typename Matcher> 40 void runDataflow(llvm::StringRef Code, Matcher Match) { 41 test::checkDataflow<NoopAnalysis>( 42 Code, "target", 43 [](ASTContext &C, Environment &) { return NoopAnalysis(C); }, 44 [&Match](llvm::ArrayRef< 45 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 46 Results, 47 ASTContext &ASTCtx) { Match(Results, ASTCtx); }, 48 {"-fsyntax-only", "-std=c++17"}); 49 } 50 }; 51 52 /// Returns the `ValueDecl` for the given identifier. 53 /// 54 /// Requirements: 55 /// 56 /// `Name` must be unique in `ASTCtx`. 57 static const ValueDecl *findValueDecl(ASTContext &ASTCtx, 58 llvm::StringRef Name) { 59 auto TargetNodes = ast_matchers::match( 60 ast_matchers::valueDecl(ast_matchers::hasName(Name)).bind("v"), ASTCtx); 61 assert(TargetNodes.size() == 1 && "Name must be unique"); 62 auto *const Result = ast_matchers::selectFirst<ValueDecl>("v", TargetNodes); 63 assert(Result != nullptr); 64 return Result; 65 } 66 67 TEST_F(TransferTest, IntVarDecl) { 68 std::string Code = R"( 69 void target() { 70 int Foo; 71 // [[p]] 72 } 73 )"; 74 runDataflow( 75 Code, [](llvm::ArrayRef< 76 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 77 Results, 78 ASTContext &ASTCtx) { 79 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 80 const Environment &Env = Results[0].second.Env; 81 82 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 83 ASSERT_THAT(FooDecl, NotNull()); 84 85 const StorageLocation *FooLoc = 86 Env.getStorageLocation(*FooDecl, SkipPast::None); 87 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 88 89 const Value *FooVal = Env.getValue(*FooLoc); 90 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 91 }); 92 } 93 94 TEST_F(TransferTest, StructVarDecl) { 95 std::string Code = R"( 96 struct A { 97 int Bar; 98 }; 99 100 void target() { 101 A Foo; 102 // [[p]] 103 } 104 )"; 105 runDataflow( 106 Code, [](llvm::ArrayRef< 107 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 108 Results, 109 ASTContext &ASTCtx) { 110 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 111 const Environment &Env = Results[0].second.Env; 112 113 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 114 ASSERT_THAT(FooDecl, NotNull()); 115 116 ASSERT_TRUE(FooDecl->getType()->isStructureType()); 117 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 118 119 FieldDecl *BarDecl = nullptr; 120 for (FieldDecl *Field : FooFields) { 121 if (Field->getNameAsString() == "Bar") { 122 BarDecl = Field; 123 } else { 124 FAIL() << "Unexpected field: " << Field->getNameAsString(); 125 } 126 } 127 ASSERT_THAT(BarDecl, NotNull()); 128 129 const auto *FooLoc = cast<AggregateStorageLocation>( 130 Env.getStorageLocation(*FooDecl, SkipPast::None)); 131 const auto *BarLoc = 132 cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl)); 133 134 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 135 const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl)); 136 EXPECT_EQ(Env.getValue(*BarLoc), BarVal); 137 }); 138 } 139 140 TEST_F(TransferTest, ClassVarDecl) { 141 std::string Code = R"( 142 class A { 143 int Bar; 144 }; 145 146 void target() { 147 A Foo; 148 // [[p]] 149 } 150 )"; 151 runDataflow( 152 Code, [](llvm::ArrayRef< 153 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 154 Results, 155 ASTContext &ASTCtx) { 156 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 157 const Environment &Env = Results[0].second.Env; 158 159 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 160 ASSERT_THAT(FooDecl, NotNull()); 161 162 ASSERT_TRUE(FooDecl->getType()->isClassType()); 163 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 164 165 FieldDecl *BarDecl = nullptr; 166 for (FieldDecl *Field : FooFields) { 167 if (Field->getNameAsString() == "Bar") { 168 BarDecl = Field; 169 } else { 170 FAIL() << "Unexpected field: " << Field->getNameAsString(); 171 } 172 } 173 ASSERT_THAT(BarDecl, NotNull()); 174 175 const auto *FooLoc = cast<AggregateStorageLocation>( 176 Env.getStorageLocation(*FooDecl, SkipPast::None)); 177 const auto *BarLoc = 178 cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl)); 179 180 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 181 const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl)); 182 EXPECT_EQ(Env.getValue(*BarLoc), BarVal); 183 }); 184 } 185 186 TEST_F(TransferTest, ReferenceVarDecl) { 187 std::string Code = R"( 188 struct A {}; 189 190 A &getA(); 191 192 void target() { 193 A &Foo = getA(); 194 // [[p]] 195 } 196 )"; 197 runDataflow( 198 Code, [](llvm::ArrayRef< 199 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 200 Results, 201 ASTContext &ASTCtx) { 202 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 203 const Environment &Env = Results[0].second.Env; 204 205 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 206 ASSERT_THAT(FooDecl, NotNull()); 207 208 const StorageLocation *FooLoc = 209 Env.getStorageLocation(*FooDecl, SkipPast::None); 210 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 211 212 const ReferenceValue *FooVal = 213 cast<ReferenceValue>(Env.getValue(*FooLoc)); 214 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc(); 215 EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc)); 216 217 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc); 218 EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal)); 219 }); 220 } 221 222 TEST_F(TransferTest, SelfReferentialReferenceVarDecl) { 223 std::string Code = R"( 224 struct A; 225 226 struct B {}; 227 228 struct C { 229 A &FooRef; 230 A *FooPtr; 231 B &BazRef; 232 B *BazPtr; 233 }; 234 235 struct A { 236 C &Bar; 237 }; 238 239 A &getA(); 240 241 void target() { 242 A &Foo = getA(); 243 // [[p]] 244 } 245 )"; 246 runDataflow(Code, [](llvm::ArrayRef<std::pair< 247 std::string, DataflowAnalysisState<NoopLattice>>> 248 Results, 249 ASTContext &ASTCtx) { 250 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 251 const Environment &Env = Results[0].second.Env; 252 253 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 254 ASSERT_THAT(FooDecl, NotNull()); 255 256 ASSERT_TRUE(FooDecl->getType()->isReferenceType()); 257 ASSERT_TRUE(FooDecl->getType().getNonReferenceType()->isStructureType()); 258 const auto FooFields = 259 FooDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields(); 260 261 FieldDecl *BarDecl = nullptr; 262 for (FieldDecl *Field : FooFields) { 263 if (Field->getNameAsString() == "Bar") { 264 BarDecl = Field; 265 } else { 266 FAIL() << "Unexpected field: " << Field->getNameAsString(); 267 } 268 } 269 ASSERT_THAT(BarDecl, NotNull()); 270 271 ASSERT_TRUE(BarDecl->getType()->isReferenceType()); 272 ASSERT_TRUE(BarDecl->getType().getNonReferenceType()->isStructureType()); 273 const auto BarFields = 274 BarDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields(); 275 276 FieldDecl *FooRefDecl = nullptr; 277 FieldDecl *FooPtrDecl = nullptr; 278 FieldDecl *BazRefDecl = nullptr; 279 FieldDecl *BazPtrDecl = nullptr; 280 for (FieldDecl *Field : BarFields) { 281 if (Field->getNameAsString() == "FooRef") { 282 FooRefDecl = Field; 283 } else if (Field->getNameAsString() == "FooPtr") { 284 FooPtrDecl = Field; 285 } else if (Field->getNameAsString() == "BazRef") { 286 BazRefDecl = Field; 287 } else if (Field->getNameAsString() == "BazPtr") { 288 BazPtrDecl = Field; 289 } else { 290 FAIL() << "Unexpected field: " << Field->getNameAsString(); 291 } 292 } 293 ASSERT_THAT(FooRefDecl, NotNull()); 294 ASSERT_THAT(FooPtrDecl, NotNull()); 295 ASSERT_THAT(BazRefDecl, NotNull()); 296 ASSERT_THAT(BazPtrDecl, NotNull()); 297 298 const auto *FooLoc = cast<ScalarStorageLocation>( 299 Env.getStorageLocation(*FooDecl, SkipPast::None)); 300 const auto *FooVal = cast<ReferenceValue>(Env.getValue(*FooLoc)); 301 const auto *FooPointeeVal = 302 cast<StructValue>(Env.getValue(FooVal->getPointeeLoc())); 303 304 const auto *BarVal = 305 cast<ReferenceValue>(&FooPointeeVal->getChild(*BarDecl)); 306 const auto *BarPointeeVal = 307 cast<StructValue>(Env.getValue(BarVal->getPointeeLoc())); 308 309 const auto *FooRefVal = 310 cast<ReferenceValue>(&BarPointeeVal->getChild(*FooRefDecl)); 311 const StorageLocation &FooRefPointeeLoc = FooRefVal->getPointeeLoc(); 312 EXPECT_THAT(Env.getValue(FooRefPointeeLoc), IsNull()); 313 314 const auto *FooPtrVal = 315 cast<PointerValue>(&BarPointeeVal->getChild(*FooPtrDecl)); 316 const StorageLocation &FooPtrPointeeLoc = FooPtrVal->getPointeeLoc(); 317 EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull()); 318 319 const auto *BazRefVal = 320 cast<ReferenceValue>(&BarPointeeVal->getChild(*BazRefDecl)); 321 const StorageLocation &BazRefPointeeLoc = BazRefVal->getPointeeLoc(); 322 EXPECT_THAT(Env.getValue(BazRefPointeeLoc), NotNull()); 323 324 const auto *BazPtrVal = 325 cast<PointerValue>(&BarPointeeVal->getChild(*BazPtrDecl)); 326 const StorageLocation &BazPtrPointeeLoc = BazPtrVal->getPointeeLoc(); 327 EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull()); 328 }); 329 } 330 331 TEST_F(TransferTest, PointerVarDecl) { 332 std::string Code = R"( 333 struct A {}; 334 335 A *getA(); 336 337 void target() { 338 A *Foo = getA(); 339 // [[p]] 340 } 341 )"; 342 runDataflow( 343 Code, [](llvm::ArrayRef< 344 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 345 Results, 346 ASTContext &ASTCtx) { 347 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 348 const Environment &Env = Results[0].second.Env; 349 350 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 351 ASSERT_THAT(FooDecl, NotNull()); 352 353 const StorageLocation *FooLoc = 354 Env.getStorageLocation(*FooDecl, SkipPast::None); 355 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 356 357 const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc)); 358 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc(); 359 EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc)); 360 361 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc); 362 EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal)); 363 }); 364 } 365 366 TEST_F(TransferTest, SelfReferentialPointerVarDecl) { 367 std::string Code = R"( 368 struct A; 369 370 struct B {}; 371 372 struct C { 373 A &FooRef; 374 A *FooPtr; 375 B &BazRef; 376 B *BazPtr; 377 }; 378 379 struct A { 380 C *Bar; 381 }; 382 383 A *getA(); 384 385 void target() { 386 A *Foo = getA(); 387 // [[p]] 388 } 389 )"; 390 runDataflow( 391 Code, [](llvm::ArrayRef< 392 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 393 Results, 394 ASTContext &ASTCtx) { 395 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 396 const Environment &Env = Results[0].second.Env; 397 398 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 399 ASSERT_THAT(FooDecl, NotNull()); 400 401 ASSERT_TRUE(FooDecl->getType()->isPointerType()); 402 ASSERT_TRUE(FooDecl->getType() 403 ->getAs<PointerType>() 404 ->getPointeeType() 405 ->isStructureType()); 406 const auto FooFields = FooDecl->getType() 407 ->getAs<PointerType>() 408 ->getPointeeType() 409 ->getAsRecordDecl() 410 ->fields(); 411 412 FieldDecl *BarDecl = nullptr; 413 for (FieldDecl *Field : FooFields) { 414 if (Field->getNameAsString() == "Bar") { 415 BarDecl = Field; 416 } else { 417 FAIL() << "Unexpected field: " << Field->getNameAsString(); 418 } 419 } 420 ASSERT_THAT(BarDecl, NotNull()); 421 422 ASSERT_TRUE(BarDecl->getType()->isPointerType()); 423 ASSERT_TRUE(BarDecl->getType() 424 ->getAs<PointerType>() 425 ->getPointeeType() 426 ->isStructureType()); 427 const auto BarFields = BarDecl->getType() 428 ->getAs<PointerType>() 429 ->getPointeeType() 430 ->getAsRecordDecl() 431 ->fields(); 432 433 FieldDecl *FooRefDecl = nullptr; 434 FieldDecl *FooPtrDecl = nullptr; 435 FieldDecl *BazRefDecl = nullptr; 436 FieldDecl *BazPtrDecl = nullptr; 437 for (FieldDecl *Field : BarFields) { 438 if (Field->getNameAsString() == "FooRef") { 439 FooRefDecl = Field; 440 } else if (Field->getNameAsString() == "FooPtr") { 441 FooPtrDecl = Field; 442 } else if (Field->getNameAsString() == "BazRef") { 443 BazRefDecl = Field; 444 } else if (Field->getNameAsString() == "BazPtr") { 445 BazPtrDecl = Field; 446 } else { 447 FAIL() << "Unexpected field: " << Field->getNameAsString(); 448 } 449 } 450 ASSERT_THAT(FooRefDecl, NotNull()); 451 ASSERT_THAT(FooPtrDecl, NotNull()); 452 ASSERT_THAT(BazRefDecl, NotNull()); 453 ASSERT_THAT(BazPtrDecl, NotNull()); 454 455 const auto *FooLoc = cast<ScalarStorageLocation>( 456 Env.getStorageLocation(*FooDecl, SkipPast::None)); 457 const auto *FooVal = cast<PointerValue>(Env.getValue(*FooLoc)); 458 const auto *FooPointeeVal = 459 cast<StructValue>(Env.getValue(FooVal->getPointeeLoc())); 460 461 const auto *BarVal = 462 cast<PointerValue>(&FooPointeeVal->getChild(*BarDecl)); 463 const auto *BarPointeeVal = 464 cast<StructValue>(Env.getValue(BarVal->getPointeeLoc())); 465 466 const auto *FooRefVal = 467 cast<ReferenceValue>(&BarPointeeVal->getChild(*FooRefDecl)); 468 const StorageLocation &FooRefPointeeLoc = FooRefVal->getPointeeLoc(); 469 EXPECT_THAT(Env.getValue(FooRefPointeeLoc), IsNull()); 470 471 const auto *FooPtrVal = 472 cast<PointerValue>(&BarPointeeVal->getChild(*FooPtrDecl)); 473 const StorageLocation &FooPtrPointeeLoc = FooPtrVal->getPointeeLoc(); 474 EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull()); 475 476 const auto *BazRefVal = 477 cast<ReferenceValue>(&BarPointeeVal->getChild(*BazRefDecl)); 478 const StorageLocation &BazRefPointeeLoc = BazRefVal->getPointeeLoc(); 479 EXPECT_THAT(Env.getValue(BazRefPointeeLoc), NotNull()); 480 481 const auto *BazPtrVal = 482 cast<PointerValue>(&BarPointeeVal->getChild(*BazPtrDecl)); 483 const StorageLocation &BazPtrPointeeLoc = BazPtrVal->getPointeeLoc(); 484 EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull()); 485 }); 486 } 487 488 TEST_F(TransferTest, JoinVarDecl) { 489 std::string Code = R"( 490 void target(bool B) { 491 int Foo; 492 // [[p1]] 493 if (B) { 494 int Bar; 495 // [[p2]] 496 } else { 497 int Baz; 498 // [[p3]] 499 } 500 (void)0; 501 // [[p4]] 502 } 503 )"; 504 runDataflow(Code, [](llvm::ArrayRef<std::pair< 505 std::string, DataflowAnalysisState<NoopLattice>>> 506 Results, 507 ASTContext &ASTCtx) { 508 ASSERT_THAT(Results, ElementsAre(Pair("p4", _), Pair("p3", _), 509 Pair("p2", _), Pair("p1", _))); 510 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 511 ASSERT_THAT(FooDecl, NotNull()); 512 513 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 514 ASSERT_THAT(BarDecl, NotNull()); 515 516 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 517 ASSERT_THAT(BazDecl, NotNull()); 518 519 const Environment &Env1 = Results[3].second.Env; 520 const StorageLocation *FooLoc = 521 Env1.getStorageLocation(*FooDecl, SkipPast::None); 522 EXPECT_THAT(FooLoc, NotNull()); 523 EXPECT_THAT(Env1.getStorageLocation(*BarDecl, SkipPast::None), IsNull()); 524 EXPECT_THAT(Env1.getStorageLocation(*BazDecl, SkipPast::None), IsNull()); 525 526 const Environment &Env2 = Results[2].second.Env; 527 EXPECT_EQ(Env2.getStorageLocation(*FooDecl, SkipPast::None), FooLoc); 528 EXPECT_THAT(Env2.getStorageLocation(*BarDecl, SkipPast::None), NotNull()); 529 EXPECT_THAT(Env2.getStorageLocation(*BazDecl, SkipPast::None), IsNull()); 530 531 const Environment &Env3 = Results[1].second.Env; 532 EXPECT_EQ(Env3.getStorageLocation(*FooDecl, SkipPast::None), FooLoc); 533 EXPECT_THAT(Env3.getStorageLocation(*BarDecl, SkipPast::None), IsNull()); 534 EXPECT_THAT(Env3.getStorageLocation(*BazDecl, SkipPast::None), NotNull()); 535 536 const Environment &Env4 = Results[0].second.Env; 537 EXPECT_EQ(Env4.getStorageLocation(*FooDecl, SkipPast::None), FooLoc); 538 EXPECT_THAT(Env4.getStorageLocation(*BarDecl, SkipPast::None), IsNull()); 539 EXPECT_THAT(Env4.getStorageLocation(*BazDecl, SkipPast::None), IsNull()); 540 }); 541 } 542 543 TEST_F(TransferTest, BinaryOperatorAssign) { 544 std::string Code = R"( 545 void target() { 546 int Foo; 547 int Bar; 548 (Bar) = (Foo); 549 // [[p]] 550 } 551 )"; 552 runDataflow(Code, 553 [](llvm::ArrayRef< 554 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 555 Results, 556 ASTContext &ASTCtx) { 557 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 558 const Environment &Env = Results[0].second.Env; 559 560 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 561 ASSERT_THAT(FooDecl, NotNull()); 562 563 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None); 564 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 565 566 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 567 ASSERT_THAT(BarDecl, NotNull()); 568 569 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal); 570 }); 571 } 572 573 TEST_F(TransferTest, VarDeclInitAssign) { 574 std::string Code = R"( 575 void target() { 576 int Foo; 577 int Bar = Foo; 578 // [[p]] 579 } 580 )"; 581 runDataflow(Code, 582 [](llvm::ArrayRef< 583 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 584 Results, 585 ASTContext &ASTCtx) { 586 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 587 const Environment &Env = Results[0].second.Env; 588 589 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 590 ASSERT_THAT(FooDecl, NotNull()); 591 592 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None); 593 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 594 595 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 596 ASSERT_THAT(BarDecl, NotNull()); 597 598 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal); 599 }); 600 } 601 602 TEST_F(TransferTest, VarDeclInitAssignChained) { 603 std::string Code = R"( 604 void target() { 605 int Foo; 606 int Bar; 607 int Baz = (Bar = Foo); 608 // [[p]] 609 } 610 )"; 611 runDataflow(Code, 612 [](llvm::ArrayRef< 613 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 614 Results, 615 ASTContext &ASTCtx) { 616 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 617 const Environment &Env = Results[0].second.Env; 618 619 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 620 ASSERT_THAT(FooDecl, NotNull()); 621 622 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None); 623 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 624 625 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 626 ASSERT_THAT(BarDecl, NotNull()); 627 628 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 629 ASSERT_THAT(BazDecl, NotNull()); 630 631 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal); 632 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), FooVal); 633 }); 634 } 635 636 TEST_F(TransferTest, VarDeclInitAssignPtrDeref) { 637 std::string Code = R"( 638 void target() { 639 int Foo; 640 int *Bar; 641 *(Bar) = Foo; 642 int Baz = *(Bar); 643 // [[p]] 644 } 645 )"; 646 runDataflow(Code, 647 [](llvm::ArrayRef< 648 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 649 Results, 650 ASTContext &ASTCtx) { 651 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 652 const Environment &Env = Results[0].second.Env; 653 654 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 655 ASSERT_THAT(FooDecl, NotNull()); 656 657 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None); 658 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 659 660 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 661 ASSERT_THAT(BarDecl, NotNull()); 662 663 const auto *BarVal = 664 cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None)); 665 EXPECT_EQ(Env.getValue(BarVal->getPointeeLoc()), FooVal); 666 667 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 668 ASSERT_THAT(BazDecl, NotNull()); 669 670 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), FooVal); 671 }); 672 } 673 674 TEST_F(TransferTest, AssignToAndFromReference) { 675 std::string Code = R"( 676 void target() { 677 int Foo; 678 int Bar; 679 int &Baz = Foo; 680 // [[p1]] 681 Baz = Bar; 682 int Qux = Baz; 683 int &Quux = Baz; 684 // [[p2]] 685 } 686 )"; 687 runDataflow( 688 Code, [](llvm::ArrayRef< 689 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 690 Results, 691 ASTContext &ASTCtx) { 692 ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _))); 693 const Environment &Env1 = Results[0].second.Env; 694 const Environment &Env2 = Results[1].second.Env; 695 696 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 697 ASSERT_THAT(FooDecl, NotNull()); 698 699 const Value *FooVal = Env1.getValue(*FooDecl, SkipPast::None); 700 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 701 702 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 703 ASSERT_THAT(BarDecl, NotNull()); 704 705 const Value *BarVal = Env1.getValue(*BarDecl, SkipPast::None); 706 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 707 708 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 709 ASSERT_THAT(BazDecl, NotNull()); 710 711 EXPECT_EQ(Env1.getValue(*BazDecl, SkipPast::Reference), FooVal); 712 713 EXPECT_EQ(Env2.getValue(*BazDecl, SkipPast::Reference), BarVal); 714 EXPECT_EQ(Env2.getValue(*FooDecl, SkipPast::None), BarVal); 715 716 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 717 ASSERT_THAT(QuxDecl, NotNull()); 718 EXPECT_EQ(Env2.getValue(*QuxDecl, SkipPast::None), BarVal); 719 720 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 721 ASSERT_THAT(QuuxDecl, NotNull()); 722 EXPECT_EQ(Env2.getValue(*QuuxDecl, SkipPast::Reference), BarVal); 723 }); 724 } 725 726 TEST_F(TransferTest, MultipleParamDecls) { 727 std::string Code = R"( 728 void target(int Foo, int Bar) { 729 (void)0; 730 // [[p]] 731 } 732 )"; 733 runDataflow(Code, 734 [](llvm::ArrayRef< 735 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 736 Results, 737 ASTContext &ASTCtx) { 738 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 739 const Environment &Env = Results[0].second.Env; 740 741 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 742 ASSERT_THAT(FooDecl, NotNull()); 743 744 const StorageLocation *FooLoc = 745 Env.getStorageLocation(*FooDecl, SkipPast::None); 746 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 747 748 const Value *FooVal = Env.getValue(*FooLoc); 749 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 750 751 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 752 ASSERT_THAT(BarDecl, NotNull()); 753 754 const StorageLocation *BarLoc = 755 Env.getStorageLocation(*BarDecl, SkipPast::None); 756 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 757 758 const Value *BarVal = Env.getValue(*BarLoc); 759 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 760 }); 761 } 762 763 TEST_F(TransferTest, StructParamDecl) { 764 std::string Code = R"( 765 struct A { 766 int Bar; 767 }; 768 769 void target(A Foo) { 770 (void)0; 771 // [[p]] 772 } 773 )"; 774 runDataflow( 775 Code, [](llvm::ArrayRef< 776 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 777 Results, 778 ASTContext &ASTCtx) { 779 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 780 const Environment &Env = Results[0].second.Env; 781 782 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 783 ASSERT_THAT(FooDecl, NotNull()); 784 785 ASSERT_TRUE(FooDecl->getType()->isStructureType()); 786 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 787 788 FieldDecl *BarDecl = nullptr; 789 for (FieldDecl *Field : FooFields) { 790 if (Field->getNameAsString() == "Bar") { 791 BarDecl = Field; 792 } else { 793 FAIL() << "Unexpected field: " << Field->getNameAsString(); 794 } 795 } 796 ASSERT_THAT(BarDecl, NotNull()); 797 798 const auto *FooLoc = cast<AggregateStorageLocation>( 799 Env.getStorageLocation(*FooDecl, SkipPast::None)); 800 const auto *BarLoc = 801 cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl)); 802 803 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 804 const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl)); 805 EXPECT_EQ(Env.getValue(*BarLoc), BarVal); 806 }); 807 } 808 809 TEST_F(TransferTest, ReferenceParamDecl) { 810 std::string Code = R"( 811 struct A {}; 812 813 void target(A &Foo) { 814 (void)0; 815 // [[p]] 816 } 817 )"; 818 runDataflow(Code, 819 [](llvm::ArrayRef< 820 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 821 Results, 822 ASTContext &ASTCtx) { 823 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 824 const Environment &Env = Results[0].second.Env; 825 826 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 827 ASSERT_THAT(FooDecl, NotNull()); 828 829 const StorageLocation *FooLoc = 830 Env.getStorageLocation(*FooDecl, SkipPast::None); 831 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 832 833 const ReferenceValue *FooVal = 834 dyn_cast<ReferenceValue>(Env.getValue(*FooLoc)); 835 ASSERT_THAT(FooVal, NotNull()); 836 837 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc(); 838 EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc)); 839 840 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc); 841 EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal)); 842 }); 843 } 844 845 TEST_F(TransferTest, PointerParamDecl) { 846 std::string Code = R"( 847 struct A {}; 848 849 void target(A *Foo) { 850 (void)0; 851 // [[p]] 852 } 853 )"; 854 runDataflow( 855 Code, [](llvm::ArrayRef< 856 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 857 Results, 858 ASTContext &ASTCtx) { 859 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 860 const Environment &Env = Results[0].second.Env; 861 862 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 863 ASSERT_THAT(FooDecl, NotNull()); 864 865 const StorageLocation *FooLoc = 866 Env.getStorageLocation(*FooDecl, SkipPast::None); 867 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 868 869 const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc)); 870 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc(); 871 EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc)); 872 873 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc); 874 EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal)); 875 }); 876 } 877 878 TEST_F(TransferTest, StructMember) { 879 std::string Code = R"( 880 struct A { 881 int Bar; 882 }; 883 884 void target(A Foo) { 885 int Baz = Foo.Bar; 886 // [[p]] 887 } 888 )"; 889 runDataflow( 890 Code, [](llvm::ArrayRef< 891 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 892 Results, 893 ASTContext &ASTCtx) { 894 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 895 const Environment &Env = Results[0].second.Env; 896 897 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 898 ASSERT_THAT(FooDecl, NotNull()); 899 900 ASSERT_TRUE(FooDecl->getType()->isStructureType()); 901 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 902 903 FieldDecl *BarDecl = nullptr; 904 for (FieldDecl *Field : FooFields) { 905 if (Field->getNameAsString() == "Bar") { 906 BarDecl = Field; 907 } else { 908 FAIL() << "Unexpected field: " << Field->getNameAsString(); 909 } 910 } 911 ASSERT_THAT(BarDecl, NotNull()); 912 913 const auto *FooLoc = cast<AggregateStorageLocation>( 914 Env.getStorageLocation(*FooDecl, SkipPast::None)); 915 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 916 const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl)); 917 918 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 919 ASSERT_THAT(BazDecl, NotNull()); 920 921 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarVal); 922 }); 923 } 924 925 TEST_F(TransferTest, ClassMember) { 926 std::string Code = R"( 927 class A { 928 public: 929 int Bar; 930 }; 931 932 void target(A Foo) { 933 int Baz = Foo.Bar; 934 // [[p]] 935 } 936 )"; 937 runDataflow( 938 Code, [](llvm::ArrayRef< 939 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 940 Results, 941 ASTContext &ASTCtx) { 942 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 943 const Environment &Env = Results[0].second.Env; 944 945 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 946 ASSERT_THAT(FooDecl, NotNull()); 947 948 ASSERT_TRUE(FooDecl->getType()->isClassType()); 949 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 950 951 FieldDecl *BarDecl = nullptr; 952 for (FieldDecl *Field : FooFields) { 953 if (Field->getNameAsString() == "Bar") { 954 BarDecl = Field; 955 } else { 956 FAIL() << "Unexpected field: " << Field->getNameAsString(); 957 } 958 } 959 ASSERT_THAT(BarDecl, NotNull()); 960 961 const auto *FooLoc = cast<AggregateStorageLocation>( 962 Env.getStorageLocation(*FooDecl, SkipPast::None)); 963 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 964 const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl)); 965 966 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 967 ASSERT_THAT(BazDecl, NotNull()); 968 969 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarVal); 970 }); 971 } 972 973 TEST_F(TransferTest, ReferenceMember) { 974 std::string Code = R"( 975 struct A { 976 int &Bar; 977 }; 978 979 void target(A Foo) { 980 int Baz = Foo.Bar; 981 // [[p]] 982 } 983 )"; 984 runDataflow( 985 Code, [](llvm::ArrayRef< 986 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 987 Results, 988 ASTContext &ASTCtx) { 989 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 990 const Environment &Env = Results[0].second.Env; 991 992 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 993 ASSERT_THAT(FooDecl, NotNull()); 994 995 ASSERT_TRUE(FooDecl->getType()->isStructureType()); 996 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 997 998 FieldDecl *BarDecl = nullptr; 999 for (FieldDecl *Field : FooFields) { 1000 if (Field->getNameAsString() == "Bar") { 1001 BarDecl = Field; 1002 } else { 1003 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1004 } 1005 } 1006 ASSERT_THAT(BarDecl, NotNull()); 1007 1008 const auto *FooLoc = cast<AggregateStorageLocation>( 1009 Env.getStorageLocation(*FooDecl, SkipPast::None)); 1010 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 1011 const auto *BarVal = cast<ReferenceValue>(&FooVal->getChild(*BarDecl)); 1012 const auto *BarPointeeVal = 1013 cast<IntegerValue>(Env.getValue(BarVal->getPointeeLoc())); 1014 1015 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 1016 ASSERT_THAT(BazDecl, NotNull()); 1017 1018 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarPointeeVal); 1019 }); 1020 } 1021 1022 TEST_F(TransferTest, StructThisMember) { 1023 std::string Code = R"( 1024 struct A { 1025 int Bar; 1026 1027 struct B { 1028 int Baz; 1029 }; 1030 1031 B Qux; 1032 1033 void target() { 1034 int Foo = Bar; 1035 int Quux = Qux.Baz; 1036 // [[p]] 1037 } 1038 }; 1039 )"; 1040 runDataflow( 1041 Code, [](llvm::ArrayRef< 1042 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 1043 Results, 1044 ASTContext &ASTCtx) { 1045 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 1046 const Environment &Env = Results[0].second.Env; 1047 1048 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>( 1049 Env.getThisPointeeStorageLocation()); 1050 ASSERT_THAT(ThisLoc, NotNull()); 1051 1052 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1053 ASSERT_THAT(BarDecl, NotNull()); 1054 1055 const auto *BarLoc = 1056 cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl)); 1057 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 1058 1059 const Value *BarVal = Env.getValue(*BarLoc); 1060 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 1061 1062 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1063 ASSERT_THAT(FooDecl, NotNull()); 1064 EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal); 1065 1066 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 1067 ASSERT_THAT(QuxDecl, NotNull()); 1068 1069 ASSERT_TRUE(QuxDecl->getType()->isStructureType()); 1070 auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields(); 1071 1072 FieldDecl *BazDecl = nullptr; 1073 for (FieldDecl *Field : QuxFields) { 1074 if (Field->getNameAsString() == "Baz") { 1075 BazDecl = Field; 1076 } else { 1077 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1078 } 1079 } 1080 ASSERT_THAT(BazDecl, NotNull()); 1081 1082 const auto *QuxLoc = 1083 cast<AggregateStorageLocation>(&ThisLoc->getChild(*QuxDecl)); 1084 const auto *QuxVal = dyn_cast<StructValue>(Env.getValue(*QuxLoc)); 1085 ASSERT_THAT(QuxVal, NotNull()); 1086 1087 const auto *BazLoc = 1088 cast<ScalarStorageLocation>(&QuxLoc->getChild(*BazDecl)); 1089 const auto *BazVal = cast<IntegerValue>(&QuxVal->getChild(*BazDecl)); 1090 EXPECT_EQ(Env.getValue(*BazLoc), BazVal); 1091 1092 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 1093 ASSERT_THAT(QuuxDecl, NotNull()); 1094 EXPECT_EQ(Env.getValue(*QuuxDecl, SkipPast::None), BazVal); 1095 }); 1096 } 1097 1098 TEST_F(TransferTest, ClassThisMember) { 1099 std::string Code = R"( 1100 class A { 1101 int Bar; 1102 1103 class B { 1104 public: 1105 int Baz; 1106 }; 1107 1108 B Qux; 1109 1110 void target() { 1111 int Foo = Bar; 1112 int Quux = Qux.Baz; 1113 // [[p]] 1114 } 1115 }; 1116 )"; 1117 runDataflow( 1118 Code, [](llvm::ArrayRef< 1119 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 1120 Results, 1121 ASTContext &ASTCtx) { 1122 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 1123 const Environment &Env = Results[0].second.Env; 1124 1125 const auto *ThisLoc = 1126 cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation()); 1127 1128 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1129 ASSERT_THAT(BarDecl, NotNull()); 1130 1131 const auto *BarLoc = 1132 cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl)); 1133 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 1134 1135 const Value *BarVal = Env.getValue(*BarLoc); 1136 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 1137 1138 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1139 ASSERT_THAT(FooDecl, NotNull()); 1140 EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal); 1141 1142 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 1143 ASSERT_THAT(QuxDecl, NotNull()); 1144 1145 ASSERT_TRUE(QuxDecl->getType()->isClassType()); 1146 auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields(); 1147 1148 FieldDecl *BazDecl = nullptr; 1149 for (FieldDecl *Field : QuxFields) { 1150 if (Field->getNameAsString() == "Baz") { 1151 BazDecl = Field; 1152 } else { 1153 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1154 } 1155 } 1156 ASSERT_THAT(BazDecl, NotNull()); 1157 1158 const auto *QuxLoc = 1159 cast<AggregateStorageLocation>(&ThisLoc->getChild(*QuxDecl)); 1160 const auto *QuxVal = dyn_cast<StructValue>(Env.getValue(*QuxLoc)); 1161 ASSERT_THAT(QuxVal, NotNull()); 1162 1163 const auto *BazLoc = 1164 cast<ScalarStorageLocation>(&QuxLoc->getChild(*BazDecl)); 1165 const auto *BazVal = cast<IntegerValue>(&QuxVal->getChild(*BazDecl)); 1166 EXPECT_EQ(Env.getValue(*BazLoc), BazVal); 1167 1168 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 1169 ASSERT_THAT(QuuxDecl, NotNull()); 1170 EXPECT_EQ(Env.getValue(*QuuxDecl, SkipPast::None), BazVal); 1171 }); 1172 } 1173 1174 TEST_F(TransferTest, ConstructorInitializer) { 1175 std::string Code = R"( 1176 struct target { 1177 int Bar; 1178 1179 target(int Foo) : Bar(Foo) { 1180 int Qux = Bar; 1181 // [[p]] 1182 } 1183 }; 1184 )"; 1185 runDataflow(Code, 1186 [](llvm::ArrayRef< 1187 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 1188 Results, 1189 ASTContext &ASTCtx) { 1190 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 1191 const Environment &Env = Results[0].second.Env; 1192 1193 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>( 1194 Env.getThisPointeeStorageLocation()); 1195 ASSERT_THAT(ThisLoc, NotNull()); 1196 1197 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1198 ASSERT_THAT(FooDecl, NotNull()); 1199 1200 const auto *FooVal = 1201 cast<IntegerValue>(Env.getValue(*FooDecl, SkipPast::None)); 1202 1203 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 1204 ASSERT_THAT(QuxDecl, NotNull()); 1205 EXPECT_EQ(Env.getValue(*QuxDecl, SkipPast::None), FooVal); 1206 }); 1207 } 1208 1209 TEST_F(TransferTest, DefaultInitializer) { 1210 std::string Code = R"( 1211 struct target { 1212 int Bar; 1213 int Baz = Bar; 1214 1215 target(int Foo) : Bar(Foo) { 1216 int Qux = Baz; 1217 // [[p]] 1218 } 1219 }; 1220 )"; 1221 runDataflow(Code, 1222 [](llvm::ArrayRef< 1223 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 1224 Results, 1225 ASTContext &ASTCtx) { 1226 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 1227 const Environment &Env = Results[0].second.Env; 1228 1229 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>( 1230 Env.getThisPointeeStorageLocation()); 1231 ASSERT_THAT(ThisLoc, NotNull()); 1232 1233 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1234 ASSERT_THAT(FooDecl, NotNull()); 1235 1236 const auto *FooVal = 1237 cast<IntegerValue>(Env.getValue(*FooDecl, SkipPast::None)); 1238 1239 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 1240 ASSERT_THAT(QuxDecl, NotNull()); 1241 EXPECT_EQ(Env.getValue(*QuxDecl, SkipPast::None), FooVal); 1242 }); 1243 } 1244 1245 TEST_F(TransferTest, DefaultInitializerReference) { 1246 std::string Code = R"( 1247 struct target { 1248 int &Bar; 1249 int &Baz = Bar; 1250 1251 target(int &Foo) : Bar(Foo) { 1252 int &Qux = Baz; 1253 // [[p]] 1254 } 1255 }; 1256 )"; 1257 runDataflow( 1258 Code, [](llvm::ArrayRef< 1259 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 1260 Results, 1261 ASTContext &ASTCtx) { 1262 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 1263 const Environment &Env = Results[0].second.Env; 1264 1265 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>( 1266 Env.getThisPointeeStorageLocation()); 1267 ASSERT_THAT(ThisLoc, NotNull()); 1268 1269 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1270 ASSERT_THAT(FooDecl, NotNull()); 1271 1272 const auto *FooVal = 1273 cast<ReferenceValue>(Env.getValue(*FooDecl, SkipPast::None)); 1274 1275 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 1276 ASSERT_THAT(QuxDecl, NotNull()); 1277 1278 const auto *QuxVal = 1279 cast<ReferenceValue>(Env.getValue(*QuxDecl, SkipPast::None)); 1280 EXPECT_EQ(&QuxVal->getPointeeLoc(), &FooVal->getPointeeLoc()); 1281 }); 1282 } 1283 1284 } // namespace 1285