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