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