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