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