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