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 "TestingSupport.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/AST/Decl.h" 12 #include "clang/ASTMatchers/ASTMatchers.h" 13 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" 14 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" 15 #include "clang/Analysis/FlowSensitive/RecordOps.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/SmallVector.h" 21 #include "llvm/ADT/StringRef.h" 22 #include "llvm/Support/Casting.h" 23 #include "llvm/Testing/Support/Error.h" 24 #include "gmock/gmock.h" 25 #include "gtest/gtest.h" 26 #include <optional> 27 #include <string> 28 #include <utility> 29 30 namespace { 31 32 using namespace clang; 33 using namespace dataflow; 34 using namespace test; 35 using ::testing::Eq; 36 using ::testing::IsNull; 37 using ::testing::Ne; 38 using ::testing::NotNull; 39 using ::testing::UnorderedElementsAre; 40 41 void runDataflow( 42 llvm::StringRef Code, 43 std::function< 44 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &, 45 ASTContext &)> 46 VerifyResults, 47 DataflowAnalysisOptions Options, 48 LangStandard::Kind Std = LangStandard::lang_cxx17, 49 llvm::StringRef TargetFun = "target") { 50 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code, VerifyResults, Options, 51 Std, TargetFun), 52 llvm::Succeeded()); 53 } 54 55 void runDataflow( 56 llvm::StringRef Code, 57 std::function< 58 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &, 59 ASTContext &)> 60 VerifyResults, 61 LangStandard::Kind Std = LangStandard::lang_cxx17, 62 bool ApplyBuiltinTransfer = true, llvm::StringRef TargetFun = "target") { 63 runDataflow(Code, std::move(VerifyResults), 64 {ApplyBuiltinTransfer ? BuiltinOptions{} 65 : std::optional<BuiltinOptions>()}, 66 Std, TargetFun); 67 } 68 69 void runDataflowOnLambda( 70 llvm::StringRef Code, 71 std::function< 72 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &, 73 ASTContext &)> 74 VerifyResults, 75 DataflowAnalysisOptions Options, 76 LangStandard::Kind Std = LangStandard::lang_cxx17) { 77 ASSERT_THAT_ERROR( 78 checkDataflowWithNoopAnalysis( 79 Code, 80 ast_matchers::hasDeclContext( 81 ast_matchers::cxxRecordDecl(ast_matchers::isLambda())), 82 VerifyResults, Options, Std), 83 llvm::Succeeded()); 84 } 85 86 void runDataflowOnLambda( 87 llvm::StringRef Code, 88 std::function< 89 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &, 90 ASTContext &)> 91 VerifyResults, 92 LangStandard::Kind Std = LangStandard::lang_cxx17, 93 bool ApplyBuiltinTransfer = true) { 94 runDataflowOnLambda(Code, std::move(VerifyResults), 95 {ApplyBuiltinTransfer ? BuiltinOptions{} 96 : std::optional<BuiltinOptions>()}, 97 Std); 98 } 99 100 const Formula &getFormula(const ValueDecl &D, const Environment &Env) { 101 return cast<BoolValue>(Env.getValue(D))->formula(); 102 } 103 104 TEST(TransferTest, CNotSupported) { 105 std::string Code = R"( 106 void target() {} 107 )"; 108 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis( 109 Code, [](const auto &, auto &) {}, {BuiltinOptions{}}, 110 LangStandard::lang_c89), 111 llvm::FailedWithMessage("Can only analyze C++")); 112 } 113 114 TEST(TransferTest, IntVarDeclNotTrackedWhenTransferDisabled) { 115 std::string Code = R"( 116 void target() { 117 int Foo; 118 // [[p]] 119 } 120 )"; 121 runDataflow( 122 Code, 123 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 124 ASTContext &ASTCtx) { 125 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 126 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 127 128 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 129 ASSERT_THAT(FooDecl, NotNull()); 130 131 EXPECT_EQ(Env.getStorageLocation(*FooDecl), nullptr); 132 }, 133 LangStandard::lang_cxx17, 134 /*ApplyBuiltinTransfer=*/false); 135 } 136 137 TEST(TransferTest, BoolVarDecl) { 138 std::string Code = R"( 139 void target() { 140 bool Foo; 141 // [[p]] 142 } 143 )"; 144 runDataflow( 145 Code, 146 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 147 ASTContext &ASTCtx) { 148 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 149 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 150 151 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 152 ASSERT_THAT(FooDecl, NotNull()); 153 154 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 155 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 156 157 const Value *FooVal = Env.getValue(*FooLoc); 158 EXPECT_TRUE(isa_and_nonnull<BoolValue>(FooVal)); 159 }); 160 } 161 162 TEST(TransferTest, IntVarDecl) { 163 std::string Code = R"( 164 void target() { 165 int Foo; 166 // [[p]] 167 } 168 )"; 169 runDataflow( 170 Code, 171 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 172 ASTContext &ASTCtx) { 173 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 174 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 175 176 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 177 ASSERT_THAT(FooDecl, NotNull()); 178 179 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 180 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 181 182 const Value *FooVal = Env.getValue(*FooLoc); 183 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 184 }); 185 } 186 187 TEST(TransferTest, StructIncomplete) { 188 std::string Code = R"( 189 struct A; 190 191 void target() { 192 A* Foo; 193 // [[p]] 194 } 195 )"; 196 runDataflow( 197 Code, 198 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 199 ASTContext &ASTCtx) { 200 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 201 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 202 203 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 204 ASSERT_THAT(FooDecl, NotNull()); 205 auto *FooValue = dyn_cast_or_null<PointerValue>(Env.getValue(*FooDecl)); 206 ASSERT_THAT(FooValue, NotNull()); 207 208 EXPECT_TRUE(isa<RecordStorageLocation>(FooValue->getPointeeLoc())); 209 auto *FooPointeeValue = Env.getValue(FooValue->getPointeeLoc()); 210 ASSERT_THAT(FooPointeeValue, NotNull()); 211 EXPECT_TRUE(isa<RecordValue>(FooPointeeValue)); 212 }); 213 } 214 215 // As a memory optimization, we prevent modeling fields nested below a certain 216 // level (currently, depth 3). This test verifies this lack of modeling. We also 217 // include a regression test for the case that the unmodeled field is a 218 // reference to a struct; previously, we crashed when accessing such a field. 219 TEST(TransferTest, StructFieldUnmodeled) { 220 std::string Code = R"( 221 struct S { int X; }; 222 S GlobalS; 223 struct A { S &Unmodeled = GlobalS; }; 224 struct B { A F3; }; 225 struct C { B F2; }; 226 struct D { C F1; }; 227 228 void target() { 229 D Bar; 230 A &Foo = Bar.F1.F2.F3; 231 int Zab = Foo.Unmodeled.X; 232 // [[p]] 233 } 234 )"; 235 runDataflow( 236 Code, 237 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 238 ASTContext &ASTCtx) { 239 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 240 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 241 242 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 243 ASSERT_THAT(FooDecl, NotNull()); 244 QualType FooReferentType = FooDecl->getType()->getPointeeType(); 245 ASSERT_TRUE(FooReferentType->isStructureType()); 246 auto FooFields = FooReferentType->getAsRecordDecl()->fields(); 247 248 FieldDecl *UnmodeledDecl = nullptr; 249 for (FieldDecl *Field : FooFields) { 250 if (Field->getNameAsString() == "Unmodeled") { 251 UnmodeledDecl = Field; 252 } else { 253 FAIL() << "Unexpected field: " << Field->getNameAsString(); 254 } 255 } 256 ASSERT_THAT(UnmodeledDecl, NotNull()); 257 258 const auto *FooLoc = 259 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 260 const auto *UnmodeledLoc = FooLoc->getChild(*UnmodeledDecl); 261 ASSERT_TRUE(isa<RecordStorageLocation>(UnmodeledLoc)); 262 EXPECT_THAT(Env.getValue(*UnmodeledLoc), IsNull()); 263 264 const ValueDecl *ZabDecl = findValueDecl(ASTCtx, "Zab"); 265 ASSERT_THAT(ZabDecl, NotNull()); 266 EXPECT_THAT(Env.getValue(*ZabDecl), NotNull()); 267 }); 268 } 269 270 TEST(TransferTest, StructVarDecl) { 271 std::string Code = R"( 272 struct A { 273 int Bar; 274 }; 275 276 void target() { 277 A Foo; 278 (void)Foo.Bar; 279 // [[p]] 280 } 281 )"; 282 runDataflow( 283 Code, 284 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 285 ASTContext &ASTCtx) { 286 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 287 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 288 289 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 290 ASSERT_THAT(FooDecl, NotNull()); 291 292 ASSERT_TRUE(FooDecl->getType()->isStructureType()); 293 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 294 295 FieldDecl *BarDecl = nullptr; 296 for (FieldDecl *Field : FooFields) { 297 if (Field->getNameAsString() == "Bar") { 298 BarDecl = Field; 299 } else { 300 FAIL() << "Unexpected field: " << Field->getNameAsString(); 301 } 302 } 303 ASSERT_THAT(BarDecl, NotNull()); 304 305 const auto *FooLoc = 306 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 307 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env))); 308 }); 309 } 310 311 TEST(TransferTest, StructVarDeclWithInit) { 312 std::string Code = R"( 313 struct A { 314 int Bar; 315 }; 316 317 A Gen(); 318 319 void target() { 320 A Foo = Gen(); 321 (void)Foo.Bar; 322 // [[p]] 323 } 324 )"; 325 runDataflow( 326 Code, 327 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 328 ASTContext &ASTCtx) { 329 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 330 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 331 332 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 333 ASSERT_THAT(FooDecl, NotNull()); 334 335 ASSERT_TRUE(FooDecl->getType()->isStructureType()); 336 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 337 338 FieldDecl *BarDecl = nullptr; 339 for (FieldDecl *Field : FooFields) { 340 if (Field->getNameAsString() == "Bar") { 341 BarDecl = Field; 342 } else { 343 FAIL() << "Unexpected field: " << Field->getNameAsString(); 344 } 345 } 346 ASSERT_THAT(BarDecl, NotNull()); 347 348 const auto *FooLoc = 349 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 350 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env))); 351 }); 352 } 353 354 TEST(TransferTest, StructArrayVarDecl) { 355 std::string Code = R"( 356 struct A {}; 357 358 void target() { 359 A Array[2]; 360 // [[p]] 361 } 362 )"; 363 runDataflow( 364 Code, 365 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 366 ASTContext &ASTCtx) { 367 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 368 369 const ValueDecl *ArrayDecl = findValueDecl(ASTCtx, "Array"); 370 371 // We currently don't create values for arrays. 372 ASSERT_THAT(Env.getValue(*ArrayDecl), IsNull()); 373 }); 374 } 375 376 TEST(TransferTest, ClassVarDecl) { 377 std::string Code = R"( 378 class A { 379 public: 380 int Bar; 381 }; 382 383 void target() { 384 A Foo; 385 (void)Foo.Bar; 386 // [[p]] 387 } 388 )"; 389 runDataflow( 390 Code, 391 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 392 ASTContext &ASTCtx) { 393 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 394 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 395 396 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 397 ASSERT_THAT(FooDecl, NotNull()); 398 399 ASSERT_TRUE(FooDecl->getType()->isClassType()); 400 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 401 402 FieldDecl *BarDecl = nullptr; 403 for (FieldDecl *Field : FooFields) { 404 if (Field->getNameAsString() == "Bar") { 405 BarDecl = Field; 406 } else { 407 FAIL() << "Unexpected field: " << Field->getNameAsString(); 408 } 409 } 410 ASSERT_THAT(BarDecl, NotNull()); 411 412 const auto *FooLoc = 413 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 414 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env))); 415 }); 416 } 417 418 TEST(TransferTest, ReferenceVarDecl) { 419 std::string Code = R"( 420 struct A {}; 421 422 A &getA(); 423 424 void target() { 425 A &Foo = getA(); 426 // [[p]] 427 } 428 )"; 429 runDataflow( 430 Code, 431 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 432 ASTContext &ASTCtx) { 433 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 434 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 435 436 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 437 ASSERT_THAT(FooDecl, NotNull()); 438 439 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 440 ASSERT_TRUE(isa_and_nonnull<RecordStorageLocation>(FooLoc)); 441 442 const Value *FooReferentVal = Env.getValue(*FooLoc); 443 EXPECT_TRUE(isa_and_nonnull<RecordValue>(FooReferentVal)); 444 }); 445 } 446 447 TEST(TransferTest, SelfReferentialReferenceVarDecl) { 448 std::string Code = R"( 449 struct A; 450 451 struct B {}; 452 453 struct C { 454 A &FooRef; 455 A *FooPtr; 456 B &BazRef; 457 B *BazPtr; 458 }; 459 460 struct A { 461 C &Bar; 462 }; 463 464 A &getA(); 465 466 void target() { 467 A &Foo = getA(); 468 (void)Foo.Bar.FooRef; 469 (void)Foo.Bar.FooPtr; 470 (void)Foo.Bar.BazRef; 471 (void)Foo.Bar.BazPtr; 472 // [[p]] 473 } 474 )"; 475 runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> 476 &Results, 477 ASTContext &ASTCtx) { 478 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 479 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 480 481 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 482 ASSERT_THAT(FooDecl, NotNull()); 483 484 ASSERT_TRUE(FooDecl->getType()->isReferenceType()); 485 ASSERT_TRUE(FooDecl->getType().getNonReferenceType()->isStructureType()); 486 const auto FooFields = 487 FooDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields(); 488 489 FieldDecl *BarDecl = nullptr; 490 for (FieldDecl *Field : FooFields) { 491 if (Field->getNameAsString() == "Bar") { 492 BarDecl = Field; 493 } else { 494 FAIL() << "Unexpected field: " << Field->getNameAsString(); 495 } 496 } 497 ASSERT_THAT(BarDecl, NotNull()); 498 499 ASSERT_TRUE(BarDecl->getType()->isReferenceType()); 500 ASSERT_TRUE(BarDecl->getType().getNonReferenceType()->isStructureType()); 501 const auto BarFields = 502 BarDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields(); 503 504 FieldDecl *FooRefDecl = nullptr; 505 FieldDecl *FooPtrDecl = nullptr; 506 FieldDecl *BazRefDecl = nullptr; 507 FieldDecl *BazPtrDecl = nullptr; 508 for (FieldDecl *Field : BarFields) { 509 if (Field->getNameAsString() == "FooRef") { 510 FooRefDecl = Field; 511 } else if (Field->getNameAsString() == "FooPtr") { 512 FooPtrDecl = Field; 513 } else if (Field->getNameAsString() == "BazRef") { 514 BazRefDecl = Field; 515 } else if (Field->getNameAsString() == "BazPtr") { 516 BazPtrDecl = Field; 517 } else { 518 FAIL() << "Unexpected field: " << Field->getNameAsString(); 519 } 520 } 521 ASSERT_THAT(FooRefDecl, NotNull()); 522 ASSERT_THAT(FooPtrDecl, NotNull()); 523 ASSERT_THAT(BazRefDecl, NotNull()); 524 ASSERT_THAT(BazPtrDecl, NotNull()); 525 526 const auto &FooLoc = 527 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 528 529 const auto &BarLoc = 530 *cast<RecordStorageLocation>(FooLoc.getChild(*BarDecl)); 531 532 const auto &FooReferentLoc = 533 *cast<RecordStorageLocation>(BarLoc.getChild(*FooRefDecl)); 534 EXPECT_THAT(Env.getValue(FooReferentLoc), NotNull()); 535 EXPECT_THAT(getFieldValue(&FooReferentLoc, *BarDecl, Env), IsNull()); 536 537 const auto &FooPtrVal = 538 *cast<PointerValue>(getFieldValue(&BarLoc, *FooPtrDecl, Env)); 539 const auto &FooPtrPointeeLoc = 540 cast<RecordStorageLocation>(FooPtrVal.getPointeeLoc()); 541 EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), NotNull()); 542 EXPECT_THAT(getFieldValue(&FooPtrPointeeLoc, *BarDecl, Env), IsNull()); 543 544 EXPECT_THAT(getFieldValue(&BarLoc, *BazRefDecl, Env), NotNull()); 545 546 const auto &BazPtrVal = 547 *cast<PointerValue>(getFieldValue(&BarLoc, *BazPtrDecl, Env)); 548 const StorageLocation &BazPtrPointeeLoc = BazPtrVal.getPointeeLoc(); 549 EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull()); 550 }); 551 } 552 553 TEST(TransferTest, PointerVarDecl) { 554 std::string Code = R"( 555 struct A {}; 556 557 A *getA(); 558 559 void target() { 560 A *Foo = getA(); 561 // [[p]] 562 } 563 )"; 564 runDataflow( 565 Code, 566 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 567 ASTContext &ASTCtx) { 568 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 569 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 570 571 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 572 ASSERT_THAT(FooDecl, NotNull()); 573 574 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 575 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 576 577 const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc)); 578 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc(); 579 EXPECT_TRUE(isa<RecordStorageLocation>(&FooPointeeLoc)); 580 581 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc); 582 EXPECT_TRUE(isa_and_nonnull<RecordValue>(FooPointeeVal)); 583 }); 584 } 585 586 TEST(TransferTest, SelfReferentialPointerVarDecl) { 587 std::string Code = R"( 588 struct A; 589 590 struct B {}; 591 592 struct C { 593 A &FooRef; 594 A *FooPtr; 595 B &BazRef; 596 B *BazPtr; 597 }; 598 599 struct A { 600 C *Bar; 601 }; 602 603 A *getA(); 604 605 void target() { 606 A *Foo = getA(); 607 (void)Foo->Bar->FooRef; 608 (void)Foo->Bar->FooPtr; 609 (void)Foo->Bar->BazRef; 610 (void)Foo->Bar->BazPtr; 611 // [[p]] 612 } 613 )"; 614 runDataflow( 615 Code, 616 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 617 ASTContext &ASTCtx) { 618 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 619 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 620 621 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 622 ASSERT_THAT(FooDecl, NotNull()); 623 624 ASSERT_TRUE(FooDecl->getType()->isPointerType()); 625 ASSERT_TRUE(FooDecl->getType() 626 ->getAs<PointerType>() 627 ->getPointeeType() 628 ->isStructureType()); 629 const auto FooFields = FooDecl->getType() 630 ->getAs<PointerType>() 631 ->getPointeeType() 632 ->getAsRecordDecl() 633 ->fields(); 634 635 FieldDecl *BarDecl = nullptr; 636 for (FieldDecl *Field : FooFields) { 637 if (Field->getNameAsString() == "Bar") { 638 BarDecl = Field; 639 } else { 640 FAIL() << "Unexpected field: " << Field->getNameAsString(); 641 } 642 } 643 ASSERT_THAT(BarDecl, NotNull()); 644 645 ASSERT_TRUE(BarDecl->getType()->isPointerType()); 646 ASSERT_TRUE(BarDecl->getType() 647 ->getAs<PointerType>() 648 ->getPointeeType() 649 ->isStructureType()); 650 const auto BarFields = BarDecl->getType() 651 ->getAs<PointerType>() 652 ->getPointeeType() 653 ->getAsRecordDecl() 654 ->fields(); 655 656 FieldDecl *FooRefDecl = nullptr; 657 FieldDecl *FooPtrDecl = nullptr; 658 FieldDecl *BazRefDecl = nullptr; 659 FieldDecl *BazPtrDecl = nullptr; 660 for (FieldDecl *Field : BarFields) { 661 if (Field->getNameAsString() == "FooRef") { 662 FooRefDecl = Field; 663 } else if (Field->getNameAsString() == "FooPtr") { 664 FooPtrDecl = Field; 665 } else if (Field->getNameAsString() == "BazRef") { 666 BazRefDecl = Field; 667 } else if (Field->getNameAsString() == "BazPtr") { 668 BazPtrDecl = Field; 669 } else { 670 FAIL() << "Unexpected field: " << Field->getNameAsString(); 671 } 672 } 673 ASSERT_THAT(FooRefDecl, NotNull()); 674 ASSERT_THAT(FooPtrDecl, NotNull()); 675 ASSERT_THAT(BazRefDecl, NotNull()); 676 ASSERT_THAT(BazPtrDecl, NotNull()); 677 678 const auto &FooLoc = 679 *cast<ScalarStorageLocation>(Env.getStorageLocation(*FooDecl)); 680 const auto &FooVal = *cast<PointerValue>(Env.getValue(FooLoc)); 681 const auto &FooPointeeLoc = 682 cast<RecordStorageLocation>(FooVal.getPointeeLoc()); 683 684 const auto &BarVal = 685 *cast<PointerValue>(getFieldValue(&FooPointeeLoc, *BarDecl, Env)); 686 const auto &BarPointeeLoc = 687 cast<RecordStorageLocation>(BarVal.getPointeeLoc()); 688 689 EXPECT_THAT(getFieldValue(&BarPointeeLoc, *FooRefDecl, Env), NotNull()); 690 691 const auto &FooPtrVal = *cast<PointerValue>( 692 getFieldValue(&BarPointeeLoc, *FooPtrDecl, Env)); 693 const auto &FooPtrPointeeLoc = 694 cast<RecordStorageLocation>(FooPtrVal.getPointeeLoc()); 695 EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull()); 696 697 EXPECT_THAT(getFieldValue(&BarPointeeLoc, *BazRefDecl, Env), NotNull()); 698 699 const auto &BazPtrVal = *cast<PointerValue>( 700 getFieldValue(&BarPointeeLoc, *BazPtrDecl, Env)); 701 const StorageLocation &BazPtrPointeeLoc = BazPtrVal.getPointeeLoc(); 702 EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull()); 703 }); 704 } 705 706 TEST(TransferTest, DirectlySelfReferentialReference) { 707 std::string Code = R"( 708 struct target { 709 target() { 710 (void)0; 711 // [[p]] 712 } 713 target &self = *this; 714 }; 715 )"; 716 runDataflow( 717 Code, 718 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 719 ASTContext &ASTCtx) { 720 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 721 const ValueDecl *SelfDecl = findValueDecl(ASTCtx, "self"); 722 723 auto *ThisLoc = Env.getThisPointeeStorageLocation(); 724 ASSERT_EQ(ThisLoc->getChild(*SelfDecl), ThisLoc); 725 }); 726 } 727 728 TEST(TransferTest, MultipleVarsDecl) { 729 std::string Code = R"( 730 void target() { 731 int Foo, Bar; 732 (void)0; 733 // [[p]] 734 } 735 )"; 736 runDataflow( 737 Code, 738 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 739 ASTContext &ASTCtx) { 740 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 741 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 742 743 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 744 ASSERT_THAT(FooDecl, NotNull()); 745 746 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 747 ASSERT_THAT(BarDecl, NotNull()); 748 749 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 750 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 751 752 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 753 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 754 755 const Value *FooVal = Env.getValue(*FooLoc); 756 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 757 758 const Value *BarVal = Env.getValue(*BarLoc); 759 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 760 }); 761 } 762 763 TEST(TransferTest, JoinVarDecl) { 764 std::string Code = R"( 765 void target(bool B) { 766 int Foo; 767 // [[p1]] 768 if (B) { 769 int Bar; 770 // [[p2]] 771 } else { 772 int Baz; 773 // [[p3]] 774 } 775 (void)0; 776 // [[p4]] 777 } 778 )"; 779 runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> 780 &Results, 781 ASTContext &ASTCtx) { 782 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2", "p3", "p4")); 783 784 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 785 ASSERT_THAT(FooDecl, NotNull()); 786 787 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 788 ASSERT_THAT(BarDecl, NotNull()); 789 790 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 791 ASSERT_THAT(BazDecl, NotNull()); 792 793 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 794 795 const StorageLocation *FooLoc = Env1.getStorageLocation(*FooDecl); 796 EXPECT_THAT(FooLoc, NotNull()); 797 EXPECT_THAT(Env1.getStorageLocation(*BarDecl), IsNull()); 798 EXPECT_THAT(Env1.getStorageLocation(*BazDecl), IsNull()); 799 800 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 801 EXPECT_EQ(Env2.getStorageLocation(*FooDecl), FooLoc); 802 EXPECT_THAT(Env2.getStorageLocation(*BarDecl), NotNull()); 803 EXPECT_THAT(Env2.getStorageLocation(*BazDecl), IsNull()); 804 805 const Environment &Env3 = getEnvironmentAtAnnotation(Results, "p3"); 806 EXPECT_EQ(Env3.getStorageLocation(*FooDecl), FooLoc); 807 EXPECT_THAT(Env3.getStorageLocation(*BarDecl), IsNull()); 808 EXPECT_THAT(Env3.getStorageLocation(*BazDecl), NotNull()); 809 810 const Environment &Env4 = getEnvironmentAtAnnotation(Results, "p4"); 811 EXPECT_EQ(Env4.getStorageLocation(*FooDecl), FooLoc); 812 EXPECT_THAT(Env4.getStorageLocation(*BarDecl), IsNull()); 813 EXPECT_THAT(Env4.getStorageLocation(*BazDecl), IsNull()); 814 }); 815 } 816 817 TEST(TransferTest, BinaryOperatorAssign) { 818 std::string Code = R"( 819 void target() { 820 int Foo; 821 int Bar; 822 (Bar) = (Foo); 823 // [[p]] 824 } 825 )"; 826 runDataflow( 827 Code, 828 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 829 ASTContext &ASTCtx) { 830 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 831 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 832 833 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 834 ASSERT_THAT(FooDecl, NotNull()); 835 836 const Value *FooVal = Env.getValue(*FooDecl); 837 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 838 839 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 840 ASSERT_THAT(BarDecl, NotNull()); 841 842 EXPECT_EQ(Env.getValue(*BarDecl), FooVal); 843 }); 844 } 845 846 TEST(TransferTest, BinaryOperatorAssignIntegerLiteral) { 847 std::string Code = R"( 848 void target() { 849 int Foo = 1; 850 // [[before]] 851 Foo = 2; 852 // [[after]] 853 } 854 )"; 855 runDataflow( 856 Code, 857 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 858 ASTContext &ASTCtx) { 859 const Environment &Before = 860 getEnvironmentAtAnnotation(Results, "before"); 861 const Environment &After = getEnvironmentAtAnnotation(Results, "after"); 862 863 const auto &ValBefore = 864 getValueForDecl<IntegerValue>(ASTCtx, Before, "Foo"); 865 const auto &ValAfter = 866 getValueForDecl<IntegerValue>(ASTCtx, After, "Foo"); 867 EXPECT_NE(&ValBefore, &ValAfter); 868 }); 869 } 870 871 TEST(TransferTest, VarDeclInitAssign) { 872 std::string Code = R"( 873 void target() { 874 int Foo; 875 int Bar = Foo; 876 // [[p]] 877 } 878 )"; 879 runDataflow( 880 Code, 881 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 882 ASTContext &ASTCtx) { 883 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 884 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 885 886 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 887 ASSERT_THAT(FooDecl, NotNull()); 888 889 const Value *FooVal = Env.getValue(*FooDecl); 890 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 891 892 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 893 ASSERT_THAT(BarDecl, NotNull()); 894 895 EXPECT_EQ(Env.getValue(*BarDecl), FooVal); 896 }); 897 } 898 899 TEST(TransferTest, VarDeclInitAssignChained) { 900 std::string Code = R"( 901 void target() { 902 int Foo; 903 int Bar; 904 int Baz = (Bar = Foo); 905 // [[p]] 906 } 907 )"; 908 runDataflow( 909 Code, 910 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 911 ASTContext &ASTCtx) { 912 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 913 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 914 915 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 916 ASSERT_THAT(FooDecl, NotNull()); 917 918 const Value *FooVal = Env.getValue(*FooDecl); 919 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 920 921 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 922 ASSERT_THAT(BarDecl, NotNull()); 923 924 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 925 ASSERT_THAT(BazDecl, NotNull()); 926 927 EXPECT_EQ(Env.getValue(*BarDecl), FooVal); 928 EXPECT_EQ(Env.getValue(*BazDecl), FooVal); 929 }); 930 } 931 932 TEST(TransferTest, VarDeclInitAssignPtrDeref) { 933 std::string Code = R"( 934 void target() { 935 int Foo; 936 int *Bar; 937 *(Bar) = Foo; 938 int Baz = *(Bar); 939 // [[p]] 940 } 941 )"; 942 runDataflow( 943 Code, 944 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 945 ASTContext &ASTCtx) { 946 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 947 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 948 949 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 950 ASSERT_THAT(FooDecl, NotNull()); 951 952 const Value *FooVal = Env.getValue(*FooDecl); 953 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 954 955 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 956 ASSERT_THAT(BarDecl, NotNull()); 957 958 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 959 EXPECT_EQ(Env.getValue(BarVal->getPointeeLoc()), FooVal); 960 961 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 962 ASSERT_THAT(BazDecl, NotNull()); 963 964 EXPECT_EQ(Env.getValue(*BazDecl), FooVal); 965 }); 966 } 967 968 TEST(TransferTest, AssignToAndFromReference) { 969 std::string Code = R"( 970 void target() { 971 int Foo; 972 int Bar; 973 int &Baz = Foo; 974 // [[p1]] 975 Baz = Bar; 976 int Qux = Baz; 977 int &Quux = Baz; 978 // [[p2]] 979 } 980 )"; 981 runDataflow( 982 Code, 983 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 984 ASTContext &ASTCtx) { 985 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 986 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 987 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 988 989 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 990 ASSERT_THAT(FooDecl, NotNull()); 991 992 const Value *FooVal = Env1.getValue(*FooDecl); 993 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 994 995 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 996 ASSERT_THAT(BarDecl, NotNull()); 997 998 const Value *BarVal = Env1.getValue(*BarDecl); 999 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 1000 1001 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 1002 ASSERT_THAT(BazDecl, NotNull()); 1003 1004 EXPECT_EQ(Env1.getValue(*BazDecl), FooVal); 1005 1006 EXPECT_EQ(Env2.getValue(*BazDecl), BarVal); 1007 EXPECT_EQ(Env2.getValue(*FooDecl), BarVal); 1008 1009 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 1010 ASSERT_THAT(QuxDecl, NotNull()); 1011 EXPECT_EQ(Env2.getValue(*QuxDecl), BarVal); 1012 1013 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 1014 ASSERT_THAT(QuuxDecl, NotNull()); 1015 EXPECT_EQ(Env2.getValue(*QuuxDecl), BarVal); 1016 }); 1017 } 1018 1019 TEST(TransferTest, MultipleParamDecls) { 1020 std::string Code = R"( 1021 void target(int Foo, int Bar) { 1022 (void)0; 1023 // [[p]] 1024 } 1025 )"; 1026 runDataflow( 1027 Code, 1028 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1029 ASTContext &ASTCtx) { 1030 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1031 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1032 1033 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1034 ASSERT_THAT(FooDecl, NotNull()); 1035 1036 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 1037 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 1038 1039 const Value *FooVal = Env.getValue(*FooLoc); 1040 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 1041 1042 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1043 ASSERT_THAT(BarDecl, NotNull()); 1044 1045 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 1046 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 1047 1048 const Value *BarVal = Env.getValue(*BarLoc); 1049 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 1050 }); 1051 } 1052 1053 TEST(TransferTest, StructParamDecl) { 1054 std::string Code = R"( 1055 struct A { 1056 int Bar; 1057 }; 1058 1059 void target(A Foo) { 1060 (void)Foo.Bar; 1061 // [[p]] 1062 } 1063 )"; 1064 runDataflow( 1065 Code, 1066 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1067 ASTContext &ASTCtx) { 1068 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1069 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1070 1071 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1072 ASSERT_THAT(FooDecl, NotNull()); 1073 1074 ASSERT_TRUE(FooDecl->getType()->isStructureType()); 1075 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 1076 1077 FieldDecl *BarDecl = nullptr; 1078 for (FieldDecl *Field : FooFields) { 1079 if (Field->getNameAsString() == "Bar") { 1080 BarDecl = Field; 1081 } else { 1082 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1083 } 1084 } 1085 ASSERT_THAT(BarDecl, NotNull()); 1086 1087 const auto *FooLoc = 1088 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 1089 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env))); 1090 }); 1091 } 1092 1093 TEST(TransferTest, ReferenceParamDecl) { 1094 std::string Code = R"( 1095 struct A {}; 1096 1097 void target(A &Foo) { 1098 (void)0; 1099 // [[p]] 1100 } 1101 )"; 1102 runDataflow( 1103 Code, 1104 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1105 ASTContext &ASTCtx) { 1106 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1107 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1108 1109 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1110 ASSERT_THAT(FooDecl, NotNull()); 1111 1112 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 1113 ASSERT_TRUE(isa_and_nonnull<RecordStorageLocation>(FooLoc)); 1114 1115 const Value *FooReferentVal = Env.getValue(*FooLoc); 1116 EXPECT_TRUE(isa_and_nonnull<RecordValue>(FooReferentVal)); 1117 }); 1118 } 1119 1120 TEST(TransferTest, PointerParamDecl) { 1121 std::string Code = R"( 1122 struct A {}; 1123 1124 void target(A *Foo) { 1125 (void)0; 1126 // [[p]] 1127 } 1128 )"; 1129 runDataflow( 1130 Code, 1131 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1132 ASTContext &ASTCtx) { 1133 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1134 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1135 1136 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1137 ASSERT_THAT(FooDecl, NotNull()); 1138 1139 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 1140 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 1141 1142 const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc)); 1143 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc(); 1144 EXPECT_TRUE(isa<RecordStorageLocation>(&FooPointeeLoc)); 1145 1146 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc); 1147 EXPECT_TRUE(isa_and_nonnull<RecordValue>(FooPointeeVal)); 1148 }); 1149 } 1150 1151 TEST(TransferTest, StructMember) { 1152 std::string Code = R"( 1153 struct A { 1154 int Bar; 1155 }; 1156 1157 void target(A Foo) { 1158 int Baz = Foo.Bar; 1159 // [[p]] 1160 } 1161 )"; 1162 runDataflow( 1163 Code, 1164 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1165 ASTContext &ASTCtx) { 1166 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1167 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1168 1169 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1170 ASSERT_THAT(FooDecl, NotNull()); 1171 1172 ASSERT_TRUE(FooDecl->getType()->isStructureType()); 1173 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 1174 1175 FieldDecl *BarDecl = nullptr; 1176 for (FieldDecl *Field : FooFields) { 1177 if (Field->getNameAsString() == "Bar") { 1178 BarDecl = Field; 1179 } else { 1180 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1181 } 1182 } 1183 ASSERT_THAT(BarDecl, NotNull()); 1184 1185 const auto *FooLoc = 1186 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 1187 const auto *BarVal = 1188 cast<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)); 1189 1190 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 1191 ASSERT_THAT(BazDecl, NotNull()); 1192 1193 EXPECT_EQ(Env.getValue(*BazDecl), BarVal); 1194 }); 1195 } 1196 1197 TEST(TransferTest, StructMemberEnum) { 1198 std::string Code = R"( 1199 struct A { 1200 int Bar; 1201 enum E { ONE, TWO }; 1202 }; 1203 1204 void target(A Foo) { 1205 A::E Baz = Foo.ONE; 1206 // [[p]] 1207 } 1208 )"; 1209 // Minimal expectations -- we're just testing that it doesn't crash, since 1210 // enums aren't interpreted. 1211 runDataflow( 1212 Code, 1213 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1214 ASTContext &ASTCtx) { 1215 EXPECT_THAT(Results.keys(), UnorderedElementsAre("p")); 1216 }); 1217 } 1218 1219 TEST(TransferTest, DerivedBaseMemberClass) { 1220 std::string Code = R"( 1221 class A { 1222 int ADefault; 1223 protected: 1224 int AProtected; 1225 private: 1226 int APrivate; 1227 public: 1228 int APublic; 1229 1230 private: 1231 friend void target(); 1232 }; 1233 1234 class B : public A { 1235 int BDefault; 1236 protected: 1237 int BProtected; 1238 private: 1239 int BPrivate; 1240 1241 private: 1242 friend void target(); 1243 }; 1244 1245 void target() { 1246 B Foo; 1247 (void)Foo.ADefault; 1248 (void)Foo.AProtected; 1249 (void)Foo.APrivate; 1250 (void)Foo.APublic; 1251 (void)Foo.BDefault; 1252 (void)Foo.BProtected; 1253 (void)Foo.BPrivate; 1254 // [[p]] 1255 } 1256 )"; 1257 runDataflow( 1258 Code, 1259 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1260 ASTContext &ASTCtx) { 1261 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1262 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1263 1264 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1265 ASSERT_THAT(FooDecl, NotNull()); 1266 ASSERT_TRUE(FooDecl->getType()->isRecordType()); 1267 1268 // Derived-class fields. 1269 const FieldDecl *BDefaultDecl = nullptr; 1270 const FieldDecl *BProtectedDecl = nullptr; 1271 const FieldDecl *BPrivateDecl = nullptr; 1272 for (const FieldDecl *Field : 1273 FooDecl->getType()->getAsRecordDecl()->fields()) { 1274 if (Field->getNameAsString() == "BDefault") { 1275 BDefaultDecl = Field; 1276 } else if (Field->getNameAsString() == "BProtected") { 1277 BProtectedDecl = Field; 1278 } else if (Field->getNameAsString() == "BPrivate") { 1279 BPrivateDecl = Field; 1280 } else { 1281 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1282 } 1283 } 1284 ASSERT_THAT(BDefaultDecl, NotNull()); 1285 ASSERT_THAT(BProtectedDecl, NotNull()); 1286 ASSERT_THAT(BPrivateDecl, NotNull()); 1287 1288 // Base-class fields. 1289 const FieldDecl *ADefaultDecl = nullptr; 1290 const FieldDecl *APrivateDecl = nullptr; 1291 const FieldDecl *AProtectedDecl = nullptr; 1292 const FieldDecl *APublicDecl = nullptr; 1293 for (const clang::CXXBaseSpecifier &Base : 1294 FooDecl->getType()->getAsCXXRecordDecl()->bases()) { 1295 QualType BaseType = Base.getType(); 1296 ASSERT_TRUE(BaseType->isRecordType()); 1297 for (const FieldDecl *Field : BaseType->getAsRecordDecl()->fields()) { 1298 if (Field->getNameAsString() == "ADefault") { 1299 ADefaultDecl = Field; 1300 } else if (Field->getNameAsString() == "AProtected") { 1301 AProtectedDecl = Field; 1302 } else if (Field->getNameAsString() == "APrivate") { 1303 APrivateDecl = Field; 1304 } else if (Field->getNameAsString() == "APublic") { 1305 APublicDecl = Field; 1306 } else { 1307 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1308 } 1309 } 1310 } 1311 ASSERT_THAT(ADefaultDecl, NotNull()); 1312 ASSERT_THAT(AProtectedDecl, NotNull()); 1313 ASSERT_THAT(APrivateDecl, NotNull()); 1314 ASSERT_THAT(APublicDecl, NotNull()); 1315 1316 ASSERT_TRUE( 1317 isa<RecordStorageLocation>(Env.getStorageLocation(*FooDecl))); 1318 }); 1319 } 1320 1321 static void derivedBaseMemberExpectations( 1322 const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1323 ASTContext &ASTCtx) { 1324 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1325 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1326 1327 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1328 ASSERT_THAT(FooDecl, NotNull()); 1329 1330 ASSERT_TRUE(FooDecl->getType()->isRecordType()); 1331 const FieldDecl *BarDecl = nullptr; 1332 for (const clang::CXXBaseSpecifier &Base : 1333 FooDecl->getType()->getAsCXXRecordDecl()->bases()) { 1334 QualType BaseType = Base.getType(); 1335 ASSERT_TRUE(BaseType->isStructureType()); 1336 1337 for (const FieldDecl *Field : BaseType->getAsRecordDecl()->fields()) { 1338 if (Field->getNameAsString() == "Bar") { 1339 BarDecl = Field; 1340 } else { 1341 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1342 } 1343 } 1344 } 1345 ASSERT_THAT(BarDecl, NotNull()); 1346 1347 const auto &FooLoc = 1348 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 1349 const auto &FooVal = *cast<RecordValue>(Env.getValue(FooLoc)); 1350 EXPECT_EQ(&FooVal.getLoc(), &FooLoc); 1351 } 1352 1353 TEST(TransferTest, DerivedBaseMemberStructDefault) { 1354 std::string Code = R"( 1355 struct A { 1356 int Bar; 1357 }; 1358 struct B : public A { 1359 }; 1360 1361 void target() { 1362 B Foo; 1363 (void)Foo.Bar; 1364 // [[p]] 1365 } 1366 )"; 1367 runDataflow(Code, derivedBaseMemberExpectations); 1368 } 1369 1370 TEST(TransferTest, DerivedBaseMemberPrivateFriend) { 1371 // Include an access to `Foo.Bar` to verify the analysis doesn't crash on that 1372 // access. 1373 std::string Code = R"( 1374 struct A { 1375 private: 1376 friend void target(); 1377 int Bar; 1378 }; 1379 struct B : public A { 1380 }; 1381 1382 void target() { 1383 B Foo; 1384 (void)Foo.Bar; 1385 // [[p]] 1386 } 1387 )"; 1388 runDataflow(Code, derivedBaseMemberExpectations); 1389 } 1390 1391 TEST(TransferTest, ClassMember) { 1392 std::string Code = R"( 1393 class A { 1394 public: 1395 int Bar; 1396 }; 1397 1398 void target(A Foo) { 1399 int Baz = Foo.Bar; 1400 // [[p]] 1401 } 1402 )"; 1403 runDataflow( 1404 Code, 1405 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1406 ASTContext &ASTCtx) { 1407 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1408 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1409 1410 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1411 ASSERT_THAT(FooDecl, NotNull()); 1412 1413 ASSERT_TRUE(FooDecl->getType()->isClassType()); 1414 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 1415 1416 FieldDecl *BarDecl = nullptr; 1417 for (FieldDecl *Field : FooFields) { 1418 if (Field->getNameAsString() == "Bar") { 1419 BarDecl = Field; 1420 } else { 1421 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1422 } 1423 } 1424 ASSERT_THAT(BarDecl, NotNull()); 1425 1426 const auto *FooLoc = 1427 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 1428 const auto *BarVal = 1429 cast<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)); 1430 1431 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 1432 ASSERT_THAT(BazDecl, NotNull()); 1433 1434 EXPECT_EQ(Env.getValue(*BazDecl), BarVal); 1435 }); 1436 } 1437 1438 TEST(TransferTest, BaseClassInitializer) { 1439 using ast_matchers::cxxConstructorDecl; 1440 using ast_matchers::hasName; 1441 using ast_matchers::ofClass; 1442 1443 std::string Code = R"( 1444 class A { 1445 public: 1446 A(int I) : Bar(I) {} 1447 int Bar; 1448 }; 1449 1450 class B : public A { 1451 public: 1452 B(int I) : A(I) { 1453 (void)0; 1454 // [[p]] 1455 } 1456 }; 1457 )"; 1458 ASSERT_THAT_ERROR( 1459 checkDataflow<NoopAnalysis>( 1460 AnalysisInputs<NoopAnalysis>( 1461 Code, cxxConstructorDecl(ofClass(hasName("B"))), 1462 [](ASTContext &C, Environment &) { return NoopAnalysis(C); }) 1463 .withASTBuildArgs( 1464 {"-fsyntax-only", "-fno-delayed-template-parsing", 1465 "-std=" + std::string(LangStandard::getLangStandardForKind( 1466 LangStandard::lang_cxx17) 1467 .getName())}), 1468 /*VerifyResults=*/ 1469 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1470 const AnalysisOutputs &) { 1471 // Regression test to verify that base-class initializers do not 1472 // trigger an assertion. If we add support for such initializers in 1473 // the future, we can expand this test to check more specific 1474 // properties. 1475 EXPECT_THAT(Results.keys(), UnorderedElementsAre("p")); 1476 }), 1477 llvm::Succeeded()); 1478 } 1479 1480 TEST(TransferTest, StructModeledFieldsWithAccessor) { 1481 std::string Code = R"( 1482 class S { 1483 int *Ptr; 1484 int *PtrNonConst; 1485 int Int; 1486 int IntWithInc; 1487 int IntNotAccessed; 1488 int IntRef; 1489 public: 1490 int *getPtr() const { return Ptr; } 1491 int *getPtrNonConst() { return PtrNonConst; } 1492 int getInt(int i) const { return Int; } 1493 int getWithInc(int i) { IntWithInc += i; return IntWithInc; } 1494 int getIntNotAccessed() const { return IntNotAccessed; } 1495 int getIntNoDefinition() const; 1496 int &getIntRef() { return IntRef; } 1497 void returnVoid() const { return; } 1498 }; 1499 1500 void target() { 1501 S s; 1502 int *p1 = s.getPtr(); 1503 int *p2 = s.getPtrNonConst(); 1504 int i1 = s.getInt(1); 1505 int i2 = s.getWithInc(1); 1506 int i3 = s.getIntNoDefinition(); 1507 int &iref = s.getIntRef(); 1508 1509 // Regression test: Don't crash on an indirect call (which doesn't have 1510 // an associated `CXXMethodDecl`). 1511 auto ptr_to_member_fn = &S::getPtr; 1512 p1 = (s.*ptr_to_member_fn)(); 1513 1514 // Regression test: Don't crash on a return statement without a value. 1515 s.returnVoid(); 1516 // [[p]] 1517 } 1518 )"; 1519 runDataflow( 1520 Code, 1521 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1522 ASTContext &ASTCtx) { 1523 const Environment &Env = 1524 getEnvironmentAtAnnotation(Results, "p"); 1525 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"); 1526 std::vector<const ValueDecl*> Fields; 1527 for (auto [Field, _] : SLoc.children()) 1528 Fields.push_back(Field); 1529 // Only the fields that have simple accessor methods (that have a 1530 // single statement body that returns the member variable) should be 1531 // modeled. 1532 ASSERT_THAT(Fields, UnorderedElementsAre( 1533 findValueDecl(ASTCtx, "Ptr"), findValueDecl(ASTCtx, "PtrNonConst"), 1534 findValueDecl(ASTCtx, "Int"), findValueDecl(ASTCtx, "IntRef"))); 1535 }); 1536 } 1537 1538 TEST(TransferTest, StructModeledFieldsWithComplicatedInheritance) { 1539 std::string Code = R"( 1540 struct Base1 { 1541 int base1_1; 1542 int base1_2; 1543 }; 1544 struct Intermediate : Base1 { 1545 int intermediate_1; 1546 int intermediate_2; 1547 }; 1548 struct Base2 { 1549 int base2_1; 1550 int base2_2; 1551 }; 1552 struct MostDerived : public Intermediate, Base2 { 1553 int most_derived_1; 1554 int most_derived_2; 1555 }; 1556 1557 void target() { 1558 MostDerived MD; 1559 MD.base1_2 = 1; 1560 MD.intermediate_2 = 1; 1561 MD.base2_2 = 1; 1562 MD.most_derived_2 = 1; 1563 // [[p]] 1564 } 1565 )"; 1566 runDataflow( 1567 Code, 1568 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1569 ASTContext &ASTCtx) { 1570 const Environment &Env = 1571 getEnvironmentAtAnnotation(Results, "p"); 1572 1573 // Only the accessed fields should exist in the model. 1574 auto &MDLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "MD"); 1575 std::vector<const ValueDecl*> Fields; 1576 for (auto [Field, _] : MDLoc.children()) 1577 Fields.push_back(Field); 1578 ASSERT_THAT(Fields, UnorderedElementsAre( 1579 findValueDecl(ASTCtx, "base1_2"), 1580 findValueDecl(ASTCtx, "intermediate_2"), 1581 findValueDecl(ASTCtx, "base2_2"), 1582 findValueDecl(ASTCtx, "most_derived_2"))); 1583 }); 1584 } 1585 1586 TEST(TransferTest, StructInitializerListWithComplicatedInheritance) { 1587 std::string Code = R"( 1588 struct Base1 { 1589 int base1; 1590 }; 1591 struct Intermediate : Base1 { 1592 int intermediate; 1593 }; 1594 struct Base2 { 1595 int base2; 1596 }; 1597 struct MostDerived : public Intermediate, Base2 { 1598 int most_derived; 1599 }; 1600 1601 void target() { 1602 MostDerived MD = {}; 1603 // [[p]] 1604 } 1605 )"; 1606 runDataflow( 1607 Code, 1608 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1609 ASTContext &ASTCtx) { 1610 const Environment &Env = 1611 getEnvironmentAtAnnotation(Results, "p"); 1612 1613 // When a struct is initialized with a initializer list, all the 1614 // fields are considered "accessed", and therefore do exist. 1615 auto &MD = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "MD"); 1616 ASSERT_THAT(cast<IntegerValue>( 1617 getFieldValue(&MD, *findValueDecl(ASTCtx, "base1"), Env)), 1618 NotNull()); 1619 ASSERT_THAT(cast<IntegerValue>( 1620 getFieldValue(&MD, *findValueDecl(ASTCtx, "intermediate"), Env)), 1621 NotNull()); 1622 ASSERT_THAT(cast<IntegerValue>( 1623 getFieldValue(&MD, *findValueDecl(ASTCtx, "base2"), Env)), 1624 NotNull()); 1625 ASSERT_THAT(cast<IntegerValue>( 1626 getFieldValue(&MD, *findValueDecl(ASTCtx, "most_derived"), Env)), 1627 NotNull()); 1628 }); 1629 } 1630 1631 TEST(TransferTest, ReferenceMember) { 1632 std::string Code = R"( 1633 struct A { 1634 int &Bar; 1635 }; 1636 1637 void target(A Foo) { 1638 int Baz = Foo.Bar; 1639 // [[p]] 1640 } 1641 )"; 1642 runDataflow( 1643 Code, 1644 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1645 ASTContext &ASTCtx) { 1646 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1647 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1648 1649 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1650 ASSERT_THAT(FooDecl, NotNull()); 1651 1652 ASSERT_TRUE(FooDecl->getType()->isStructureType()); 1653 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 1654 1655 FieldDecl *BarDecl = nullptr; 1656 for (FieldDecl *Field : FooFields) { 1657 if (Field->getNameAsString() == "Bar") { 1658 BarDecl = Field; 1659 } else { 1660 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1661 } 1662 } 1663 ASSERT_THAT(BarDecl, NotNull()); 1664 1665 const auto *FooLoc = 1666 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 1667 const auto *BarReferentVal = 1668 cast<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)); 1669 1670 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 1671 ASSERT_THAT(BazDecl, NotNull()); 1672 1673 EXPECT_EQ(Env.getValue(*BazDecl), BarReferentVal); 1674 }); 1675 } 1676 1677 TEST(TransferTest, StructThisMember) { 1678 std::string Code = R"( 1679 struct A { 1680 int Bar; 1681 1682 struct B { 1683 int Baz; 1684 }; 1685 1686 B Qux; 1687 1688 void target() { 1689 int Foo = Bar; 1690 int Quux = Qux.Baz; 1691 // [[p]] 1692 } 1693 }; 1694 )"; 1695 runDataflow( 1696 Code, 1697 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1698 ASTContext &ASTCtx) { 1699 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1700 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1701 1702 const auto *ThisLoc = Env.getThisPointeeStorageLocation(); 1703 ASSERT_THAT(ThisLoc, NotNull()); 1704 1705 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1706 ASSERT_THAT(BarDecl, NotNull()); 1707 1708 const auto *BarLoc = 1709 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl)); 1710 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 1711 1712 const Value *BarVal = Env.getValue(*BarLoc); 1713 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 1714 1715 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1716 ASSERT_THAT(FooDecl, NotNull()); 1717 EXPECT_EQ(Env.getValue(*FooDecl), BarVal); 1718 1719 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 1720 ASSERT_THAT(QuxDecl, NotNull()); 1721 1722 ASSERT_TRUE(QuxDecl->getType()->isStructureType()); 1723 auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields(); 1724 1725 FieldDecl *BazDecl = nullptr; 1726 for (FieldDecl *Field : QuxFields) { 1727 if (Field->getNameAsString() == "Baz") { 1728 BazDecl = Field; 1729 } else { 1730 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1731 } 1732 } 1733 ASSERT_THAT(BazDecl, NotNull()); 1734 1735 const auto *QuxLoc = 1736 cast<RecordStorageLocation>(ThisLoc->getChild(*QuxDecl)); 1737 EXPECT_THAT(dyn_cast<RecordValue>(Env.getValue(*QuxLoc)), NotNull()); 1738 1739 const auto *BazVal = 1740 cast<IntegerValue>(getFieldValue(QuxLoc, *BazDecl, Env)); 1741 1742 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 1743 ASSERT_THAT(QuuxDecl, NotNull()); 1744 EXPECT_EQ(Env.getValue(*QuuxDecl), BazVal); 1745 }); 1746 } 1747 1748 TEST(TransferTest, ClassThisMember) { 1749 std::string Code = R"( 1750 class A { 1751 int Bar; 1752 1753 class B { 1754 public: 1755 int Baz; 1756 }; 1757 1758 B Qux; 1759 1760 void target() { 1761 int Foo = Bar; 1762 int Quux = Qux.Baz; 1763 // [[p]] 1764 } 1765 }; 1766 )"; 1767 runDataflow( 1768 Code, 1769 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1770 ASTContext &ASTCtx) { 1771 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1772 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1773 1774 const auto *ThisLoc = Env.getThisPointeeStorageLocation(); 1775 1776 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1777 ASSERT_THAT(BarDecl, NotNull()); 1778 1779 const auto *BarLoc = 1780 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl)); 1781 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 1782 1783 const Value *BarVal = Env.getValue(*BarLoc); 1784 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 1785 1786 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1787 ASSERT_THAT(FooDecl, NotNull()); 1788 EXPECT_EQ(Env.getValue(*FooDecl), BarVal); 1789 1790 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 1791 ASSERT_THAT(QuxDecl, NotNull()); 1792 1793 ASSERT_TRUE(QuxDecl->getType()->isClassType()); 1794 auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields(); 1795 1796 FieldDecl *BazDecl = nullptr; 1797 for (FieldDecl *Field : QuxFields) { 1798 if (Field->getNameAsString() == "Baz") { 1799 BazDecl = Field; 1800 } else { 1801 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1802 } 1803 } 1804 ASSERT_THAT(BazDecl, NotNull()); 1805 1806 const auto *QuxLoc = 1807 cast<RecordStorageLocation>(ThisLoc->getChild(*QuxDecl)); 1808 EXPECT_THAT(dyn_cast<RecordValue>(Env.getValue(*QuxLoc)), NotNull()); 1809 1810 const auto *BazVal = 1811 cast<IntegerValue>(getFieldValue(QuxLoc, *BazDecl, Env)); 1812 1813 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 1814 ASSERT_THAT(QuuxDecl, NotNull()); 1815 EXPECT_EQ(Env.getValue(*QuuxDecl), BazVal); 1816 }); 1817 } 1818 1819 TEST(TransferTest, UnionThisMember) { 1820 std::string Code = R"( 1821 union A { 1822 int Foo; 1823 int Bar; 1824 1825 void target() { 1826 A a; 1827 // Mention the fields to ensure they're included in the analysis. 1828 (void)a.Foo; 1829 (void)a.Bar; 1830 // [[p]] 1831 } 1832 }; 1833 )"; 1834 runDataflow( 1835 Code, 1836 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1837 ASTContext &ASTCtx) { 1838 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1839 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1840 1841 const auto *ThisLoc = Env.getThisPointeeStorageLocation(); 1842 ASSERT_THAT(ThisLoc, NotNull()); 1843 1844 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1845 ASSERT_THAT(FooDecl, NotNull()); 1846 1847 const auto *FooLoc = 1848 cast<ScalarStorageLocation>(ThisLoc->getChild(*FooDecl)); 1849 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 1850 1851 const Value *FooVal = Env.getValue(*FooLoc); 1852 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 1853 1854 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1855 ASSERT_THAT(BarDecl, NotNull()); 1856 1857 const auto *BarLoc = 1858 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl)); 1859 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 1860 1861 const Value *BarVal = Env.getValue(*BarLoc); 1862 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 1863 }); 1864 } 1865 1866 TEST(TransferTest, StructThisInLambda) { 1867 std::string ThisCaptureCode = R"( 1868 struct A { 1869 void frob() { 1870 [this]() { 1871 int Foo = Bar; 1872 // [[p1]] 1873 }(); 1874 } 1875 1876 int Bar; 1877 }; 1878 )"; 1879 runDataflow( 1880 ThisCaptureCode, 1881 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1882 ASTContext &ASTCtx) { 1883 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1")); 1884 const Environment &Env = getEnvironmentAtAnnotation(Results, "p1"); 1885 1886 const auto *ThisLoc = Env.getThisPointeeStorageLocation(); 1887 ASSERT_THAT(ThisLoc, NotNull()); 1888 1889 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1890 ASSERT_THAT(BarDecl, NotNull()); 1891 1892 const auto *BarLoc = 1893 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl)); 1894 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 1895 1896 const Value *BarVal = Env.getValue(*BarLoc); 1897 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 1898 1899 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1900 ASSERT_THAT(FooDecl, NotNull()); 1901 EXPECT_EQ(Env.getValue(*FooDecl), BarVal); 1902 }, 1903 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()"); 1904 1905 std::string RefCaptureDefaultCode = R"( 1906 struct A { 1907 void frob() { 1908 [&]() { 1909 int Foo = Bar; 1910 // [[p2]] 1911 }(); 1912 } 1913 1914 int Bar; 1915 }; 1916 )"; 1917 runDataflow( 1918 RefCaptureDefaultCode, 1919 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1920 ASTContext &ASTCtx) { 1921 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p2")); 1922 const Environment &Env = getEnvironmentAtAnnotation(Results, "p2"); 1923 1924 const auto *ThisLoc = Env.getThisPointeeStorageLocation(); 1925 ASSERT_THAT(ThisLoc, NotNull()); 1926 1927 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1928 ASSERT_THAT(BarDecl, NotNull()); 1929 1930 const auto *BarLoc = 1931 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl)); 1932 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 1933 1934 const Value *BarVal = Env.getValue(*BarLoc); 1935 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 1936 1937 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1938 ASSERT_THAT(FooDecl, NotNull()); 1939 EXPECT_EQ(Env.getValue(*FooDecl), BarVal); 1940 }, 1941 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()"); 1942 1943 std::string FreeFunctionLambdaCode = R"( 1944 void foo() { 1945 int Bar; 1946 [&]() { 1947 int Foo = Bar; 1948 // [[p3]] 1949 }(); 1950 } 1951 )"; 1952 runDataflow( 1953 FreeFunctionLambdaCode, 1954 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1955 ASTContext &ASTCtx) { 1956 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p3")); 1957 const Environment &Env = getEnvironmentAtAnnotation(Results, "p3"); 1958 1959 EXPECT_THAT(Env.getThisPointeeStorageLocation(), IsNull()); 1960 }, 1961 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()"); 1962 } 1963 1964 TEST(TransferTest, ConstructorInitializer) { 1965 std::string Code = R"( 1966 struct target { 1967 int Bar; 1968 1969 target(int Foo) : Bar(Foo) { 1970 int Qux = Bar; 1971 // [[p]] 1972 } 1973 }; 1974 )"; 1975 runDataflow( 1976 Code, 1977 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1978 ASTContext &ASTCtx) { 1979 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1980 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1981 1982 const auto *ThisLoc = Env.getThisPointeeStorageLocation(); 1983 ASSERT_THAT(ThisLoc, NotNull()); 1984 1985 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1986 ASSERT_THAT(FooDecl, NotNull()); 1987 1988 const auto *FooVal = cast<IntegerValue>(Env.getValue(*FooDecl)); 1989 1990 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 1991 ASSERT_THAT(QuxDecl, NotNull()); 1992 EXPECT_EQ(Env.getValue(*QuxDecl), FooVal); 1993 }); 1994 } 1995 1996 TEST(TransferTest, DefaultInitializer) { 1997 std::string Code = R"( 1998 struct target { 1999 int Bar; 2000 int Baz = Bar; 2001 2002 target(int Foo) : Bar(Foo) { 2003 int Qux = Baz; 2004 // [[p]] 2005 } 2006 }; 2007 )"; 2008 runDataflow( 2009 Code, 2010 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2011 ASTContext &ASTCtx) { 2012 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2013 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2014 2015 const auto *ThisLoc = Env.getThisPointeeStorageLocation(); 2016 ASSERT_THAT(ThisLoc, NotNull()); 2017 2018 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2019 ASSERT_THAT(FooDecl, NotNull()); 2020 2021 const auto *FooVal = cast<IntegerValue>(Env.getValue(*FooDecl)); 2022 2023 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 2024 ASSERT_THAT(QuxDecl, NotNull()); 2025 EXPECT_EQ(Env.getValue(*QuxDecl), FooVal); 2026 }); 2027 } 2028 2029 TEST(TransferTest, DefaultInitializerReference) { 2030 std::string Code = R"( 2031 struct target { 2032 int &Bar; 2033 int &Baz = Bar; 2034 2035 target(int &Foo) : Bar(Foo) { 2036 int &Qux = Baz; 2037 // [[p]] 2038 } 2039 }; 2040 )"; 2041 runDataflow( 2042 Code, 2043 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2044 ASTContext &ASTCtx) { 2045 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2046 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2047 2048 const auto *ThisLoc = Env.getThisPointeeStorageLocation(); 2049 ASSERT_THAT(ThisLoc, NotNull()); 2050 2051 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2052 ASSERT_THAT(FooDecl, NotNull()); 2053 2054 const auto *FooLoc = Env.getStorageLocation(*FooDecl); 2055 2056 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 2057 ASSERT_THAT(QuxDecl, NotNull()); 2058 2059 const auto *QuxLoc = Env.getStorageLocation(*QuxDecl); 2060 EXPECT_EQ(QuxLoc, FooLoc); 2061 }); 2062 } 2063 2064 TEST(TransferTest, TemporaryObject) { 2065 std::string Code = R"( 2066 struct A { 2067 int Bar; 2068 }; 2069 2070 void target() { 2071 A Foo = A(); 2072 (void)Foo.Bar; 2073 // [[p]] 2074 } 2075 )"; 2076 runDataflow( 2077 Code, 2078 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2079 ASTContext &ASTCtx) { 2080 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2081 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2082 2083 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2084 ASSERT_THAT(FooDecl, NotNull()); 2085 2086 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2087 ASSERT_THAT(BarDecl, NotNull()); 2088 2089 const auto *FooLoc = 2090 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2091 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env))); 2092 }); 2093 } 2094 2095 TEST(TransferTest, ElidableConstructor) { 2096 // This test is effectively the same as TransferTest.TemporaryObject, but 2097 // the code is compiled as C++ 14. 2098 std::string Code = R"( 2099 struct A { 2100 int Bar; 2101 }; 2102 2103 void target() { 2104 A Foo = A(); 2105 (void)Foo.Bar; 2106 // [[p]] 2107 } 2108 )"; 2109 runDataflow( 2110 Code, 2111 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2112 ASTContext &ASTCtx) { 2113 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2114 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2115 2116 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2117 ASSERT_THAT(FooDecl, NotNull()); 2118 2119 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2120 ASSERT_THAT(BarDecl, NotNull()); 2121 2122 const auto *FooLoc = 2123 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2124 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env))); 2125 }, 2126 LangStandard::lang_cxx14); 2127 } 2128 2129 TEST(TransferTest, AssignmentOperator) { 2130 std::string Code = R"( 2131 struct A { 2132 int Baz; 2133 }; 2134 2135 void target() { 2136 A Foo = { 1 }; 2137 A Bar = { 2 }; 2138 // [[p1]] 2139 Foo = Bar; 2140 // [[p2]] 2141 Foo.Baz = 3; 2142 // [[p3]] 2143 } 2144 )"; 2145 runDataflow( 2146 Code, 2147 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2148 ASTContext &ASTCtx) { 2149 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2150 ASSERT_THAT(FooDecl, NotNull()); 2151 2152 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2153 ASSERT_THAT(BarDecl, NotNull()); 2154 2155 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2156 ASSERT_THAT(BazDecl, NotNull()); 2157 2158 // Before copy assignment. 2159 { 2160 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 2161 2162 const auto *FooLoc1 = 2163 cast<RecordStorageLocation>(Env1.getStorageLocation(*FooDecl)); 2164 const auto *BarLoc1 = 2165 cast<RecordStorageLocation>(Env1.getStorageLocation(*BarDecl)); 2166 EXPECT_FALSE(recordsEqual(*FooLoc1, *BarLoc1, Env1)); 2167 2168 const auto *FooBazVal1 = 2169 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env1)); 2170 const auto *BarBazVal1 = 2171 cast<IntegerValue>(getFieldValue(BarLoc1, *BazDecl, Env1)); 2172 EXPECT_NE(FooBazVal1, BarBazVal1); 2173 } 2174 2175 // After copy assignment. 2176 { 2177 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 2178 2179 const auto *FooLoc2 = 2180 cast<RecordStorageLocation>(Env2.getStorageLocation(*FooDecl)); 2181 const auto *BarLoc2 = 2182 cast<RecordStorageLocation>(Env2.getStorageLocation(*BarDecl)); 2183 2184 const auto *FooVal2 = cast<RecordValue>(Env2.getValue(*FooLoc2)); 2185 const auto *BarVal2 = cast<RecordValue>(Env2.getValue(*BarLoc2)); 2186 EXPECT_NE(FooVal2, BarVal2); 2187 2188 EXPECT_TRUE(recordsEqual(*FooLoc2, *BarLoc2, Env2)); 2189 2190 const auto *FooBazVal2 = 2191 cast<IntegerValue>(getFieldValue(FooLoc2, *BazDecl, Env2)); 2192 const auto *BarBazVal2 = 2193 cast<IntegerValue>(getFieldValue(BarLoc2, *BazDecl, Env2)); 2194 EXPECT_EQ(FooBazVal2, BarBazVal2); 2195 } 2196 2197 // After value update. 2198 { 2199 const Environment &Env3 = getEnvironmentAtAnnotation(Results, "p3"); 2200 2201 const auto *FooLoc3 = 2202 cast<RecordStorageLocation>(Env3.getStorageLocation(*FooDecl)); 2203 const auto *BarLoc3 = 2204 cast<RecordStorageLocation>(Env3.getStorageLocation(*BarDecl)); 2205 EXPECT_FALSE(recordsEqual(*FooLoc3, *BarLoc3, Env3)); 2206 2207 const auto *FooBazVal3 = 2208 cast<IntegerValue>(getFieldValue(FooLoc3, *BazDecl, Env3)); 2209 const auto *BarBazVal3 = 2210 cast<IntegerValue>(getFieldValue(BarLoc3, *BazDecl, Env3)); 2211 EXPECT_NE(FooBazVal3, BarBazVal3); 2212 } 2213 }); 2214 } 2215 2216 TEST(TransferTest, AssignmentOperatorFromBase) { 2217 // This is a crash repro. We don't model the copy this case, so no 2218 // expectations on the copied field of the base class are checked. 2219 std::string Code = R"( 2220 struct Base { 2221 int base; 2222 }; 2223 struct Derived : public Base { 2224 using Base::operator=; 2225 int derived; 2226 }; 2227 void target(Base B, Derived D) { 2228 D.base = 1; 2229 D.derived = 1; 2230 D = B; 2231 // [[p]] 2232 } 2233 )"; 2234 runDataflow( 2235 Code, 2236 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2237 ASTContext &ASTCtx) {}); 2238 } 2239 2240 TEST(TransferTest, AssignmentOperatorFromCallResult) { 2241 std::string Code = R"( 2242 struct A {}; 2243 A ReturnA(); 2244 2245 void target() { 2246 A MyA; 2247 MyA = ReturnA(); 2248 } 2249 )"; 2250 runDataflow( 2251 Code, 2252 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2253 ASTContext &ASTCtx) { 2254 // As of this writing, we don't produce a `Value` for the call 2255 // `ReturnA()`. The only condition we're testing for is that the 2256 // analysis should not crash in this case. 2257 }); 2258 } 2259 2260 TEST(TransferTest, AssignmentOperatorWithInitAndInheritance) { 2261 // This is a crash repro. 2262 std::string Code = R"( 2263 struct B { int Foo; }; 2264 struct S : public B {}; 2265 void target() { 2266 S S1 = { 1 }; 2267 S S2; 2268 S S3; 2269 S1 = S2; // Only Dst has InitListExpr. 2270 S3 = S1; // Only Src has InitListExpr. 2271 // [[p]] 2272 } 2273 )"; 2274 runDataflow( 2275 Code, 2276 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2277 ASTContext &ASTCtx) {}); 2278 } 2279 2280 TEST(TransferTest, CopyConstructor) { 2281 std::string Code = R"( 2282 struct A { 2283 int Baz; 2284 }; 2285 2286 void target() { 2287 A Foo = { 1 }; 2288 A Bar = Foo; 2289 // [[after_copy]] 2290 Foo.Baz = 2; 2291 // [[after_update]] 2292 } 2293 )"; 2294 runDataflow( 2295 Code, 2296 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2297 ASTContext &ASTCtx) { 2298 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2299 ASSERT_THAT(FooDecl, NotNull()); 2300 2301 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2302 ASSERT_THAT(BarDecl, NotNull()); 2303 2304 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2305 ASSERT_THAT(BazDecl, NotNull()); 2306 2307 // after_copy 2308 { 2309 const Environment &Env = 2310 getEnvironmentAtAnnotation(Results, "after_copy"); 2311 2312 const auto *FooLoc = 2313 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2314 const auto *BarLoc = 2315 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2316 2317 // `Foo` and `Bar` have different `RecordValue`s associated with them. 2318 const auto *FooVal = cast<RecordValue>(Env.getValue(*FooLoc)); 2319 const auto *BarVal = cast<RecordValue>(Env.getValue(*BarLoc)); 2320 EXPECT_NE(FooVal, BarVal); 2321 2322 // But the records compare equal. 2323 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env)); 2324 2325 // In particular, the value of `Baz` in both records is the same. 2326 const auto *FooBazVal = 2327 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2328 const auto *BarBazVal = 2329 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2330 EXPECT_EQ(FooBazVal, BarBazVal); 2331 } 2332 2333 // after_update 2334 { 2335 const Environment &Env = 2336 getEnvironmentAtAnnotation(Results, "after_update"); 2337 2338 const auto *FooLoc = 2339 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2340 const auto *BarLoc = 2341 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2342 2343 EXPECT_FALSE(recordsEqual(*FooLoc, *BarLoc, Env)); 2344 2345 const auto *FooBazVal = 2346 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2347 const auto *BarBazVal = 2348 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2349 EXPECT_NE(FooBazVal, BarBazVal); 2350 } 2351 }); 2352 } 2353 2354 TEST(TransferTest, CopyConstructorWithDefaultArgument) { 2355 std::string Code = R"( 2356 struct A { 2357 int Baz; 2358 A() = default; 2359 A(const A& a, bool def = true) { Baz = a.Baz; } 2360 }; 2361 2362 void target() { 2363 A Foo; 2364 (void)Foo.Baz; 2365 A Bar = Foo; 2366 // [[p]] 2367 } 2368 )"; 2369 runDataflow( 2370 Code, 2371 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2372 ASTContext &ASTCtx) { 2373 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2374 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2375 2376 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2377 ASSERT_THAT(FooDecl, NotNull()); 2378 2379 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2380 ASSERT_THAT(BarDecl, NotNull()); 2381 2382 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2383 ASSERT_THAT(BazDecl, NotNull()); 2384 2385 const auto *FooLoc = 2386 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2387 const auto *BarLoc = 2388 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2389 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env)); 2390 2391 const auto *FooBazVal = 2392 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2393 const auto *BarBazVal = 2394 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2395 EXPECT_EQ(FooBazVal, BarBazVal); 2396 }); 2397 } 2398 2399 TEST(TransferTest, CopyConstructorWithParens) { 2400 std::string Code = R"( 2401 struct A { 2402 int Baz; 2403 }; 2404 2405 void target() { 2406 A Foo; 2407 (void)Foo.Baz; 2408 A Bar((A(Foo))); 2409 // [[p]] 2410 } 2411 )"; 2412 runDataflow( 2413 Code, 2414 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2415 ASTContext &ASTCtx) { 2416 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2417 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 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 *FooLoc = 2429 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2430 const auto *BarLoc = 2431 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2432 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env)); 2433 2434 const auto *FooBazVal = 2435 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2436 const auto *BarBazVal = 2437 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2438 EXPECT_EQ(FooBazVal, BarBazVal); 2439 }); 2440 } 2441 2442 TEST(TransferTest, CopyConstructorWithInitializerListAsSyntacticSugar) { 2443 std::string Code = R"( 2444 struct A { 2445 int Baz; 2446 }; 2447 void target() { 2448 A Foo = {3}; 2449 (void)Foo.Baz; 2450 A Bar = {A(Foo)}; 2451 // [[p]] 2452 } 2453 )"; 2454 runDataflow( 2455 Code, 2456 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2457 ASTContext &ASTCtx) { 2458 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2459 2460 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2461 2462 const auto &FooLoc = 2463 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo"); 2464 const auto &BarLoc = 2465 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar"); 2466 2467 const auto *FooBazVal = 2468 cast<IntegerValue>(getFieldValue(&FooLoc, *BazDecl, Env)); 2469 const auto *BarBazVal = 2470 cast<IntegerValue>(getFieldValue(&BarLoc, *BazDecl, Env)); 2471 EXPECT_EQ(FooBazVal, BarBazVal); 2472 }); 2473 } 2474 2475 TEST(TransferTest, CopyConstructorArgIsRefReturnedByFunction) { 2476 // This is a crash repro. 2477 std::string Code = R"( 2478 struct S {}; 2479 const S &returnsSRef(); 2480 void target() { 2481 S s(returnsSRef()); 2482 } 2483 )"; 2484 runDataflow( 2485 Code, 2486 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2487 ASTContext &ASTCtx) {}); 2488 } 2489 2490 TEST(TransferTest, MoveConstructor) { 2491 std::string Code = R"( 2492 namespace std { 2493 2494 template <typename T> struct remove_reference { using type = T; }; 2495 template <typename T> struct remove_reference<T&> { using type = T; }; 2496 template <typename T> struct remove_reference<T&&> { using type = T; }; 2497 2498 template <typename T> 2499 using remove_reference_t = typename remove_reference<T>::type; 2500 2501 template <typename T> 2502 std::remove_reference_t<T>&& move(T&& x); 2503 2504 } // namespace std 2505 2506 struct A { 2507 int Baz; 2508 }; 2509 2510 void target() { 2511 A Foo; 2512 A Bar; 2513 (void)Foo.Baz; 2514 // [[p1]] 2515 Foo = std::move(Bar); 2516 // [[p2]] 2517 } 2518 )"; 2519 runDataflow( 2520 Code, 2521 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2522 ASTContext &ASTCtx) { 2523 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 2524 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 2525 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 2526 2527 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2528 ASSERT_THAT(FooDecl, NotNull()); 2529 2530 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2531 ASSERT_THAT(BarDecl, NotNull()); 2532 2533 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2534 ASSERT_THAT(BazDecl, NotNull()); 2535 2536 const auto *FooLoc1 = 2537 cast<RecordStorageLocation>(Env1.getStorageLocation(*FooDecl)); 2538 const auto *BarLoc1 = 2539 cast<RecordStorageLocation>(Env1.getStorageLocation(*BarDecl)); 2540 2541 EXPECT_FALSE(recordsEqual(*FooLoc1, *BarLoc1, Env1)); 2542 2543 const auto *FooVal1 = cast<RecordValue>(Env1.getValue(*FooLoc1)); 2544 const auto *BarVal1 = cast<RecordValue>(Env1.getValue(*BarLoc1)); 2545 EXPECT_NE(FooVal1, BarVal1); 2546 2547 const auto *FooBazVal1 = 2548 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env1)); 2549 const auto *BarBazVal1 = 2550 cast<IntegerValue>(getFieldValue(BarLoc1, *BazDecl, Env1)); 2551 EXPECT_NE(FooBazVal1, BarBazVal1); 2552 2553 const auto *FooLoc2 = 2554 cast<RecordStorageLocation>(Env2.getStorageLocation(*FooDecl)); 2555 const auto *FooVal2 = cast<RecordValue>(Env2.getValue(*FooLoc2)); 2556 EXPECT_NE(FooVal2, BarVal1); 2557 EXPECT_TRUE(recordsEqual(*FooLoc2, Env2, *BarLoc1, Env1)); 2558 2559 const auto *FooBazVal2 = 2560 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env2)); 2561 EXPECT_EQ(FooBazVal2, BarBazVal1); 2562 }); 2563 } 2564 2565 TEST(TransferTest, BindTemporary) { 2566 std::string Code = R"( 2567 struct A { 2568 virtual ~A() = default; 2569 2570 int Baz; 2571 }; 2572 2573 void target(A Foo) { 2574 int Bar = A(Foo).Baz; 2575 // [[p]] 2576 } 2577 )"; 2578 runDataflow( 2579 Code, 2580 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2581 ASTContext &ASTCtx) { 2582 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2583 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2584 2585 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2586 ASSERT_THAT(FooDecl, NotNull()); 2587 2588 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2589 ASSERT_THAT(BarDecl, NotNull()); 2590 2591 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2592 ASSERT_THAT(BazDecl, NotNull()); 2593 2594 const auto &FooLoc = 2595 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2596 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 2597 EXPECT_EQ(BarVal, getFieldValue(&FooLoc, *BazDecl, Env)); 2598 }); 2599 } 2600 2601 TEST(TransferTest, StaticCast) { 2602 std::string Code = R"( 2603 void target(int Foo) { 2604 int Bar = static_cast<int>(Foo); 2605 // [[p]] 2606 } 2607 )"; 2608 runDataflow( 2609 Code, 2610 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2611 ASTContext &ASTCtx) { 2612 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2613 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2614 2615 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2616 ASSERT_THAT(FooDecl, NotNull()); 2617 2618 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2619 ASSERT_THAT(BarDecl, NotNull()); 2620 2621 const auto *FooVal = Env.getValue(*FooDecl); 2622 const auto *BarVal = Env.getValue(*BarDecl); 2623 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 2624 EXPECT_TRUE(isa<IntegerValue>(BarVal)); 2625 EXPECT_EQ(FooVal, BarVal); 2626 }); 2627 } 2628 2629 TEST(TransferTest, IntegralCast) { 2630 std::string Code = R"( 2631 void target(int Foo) { 2632 long Bar = Foo; 2633 // [[p]] 2634 } 2635 )"; 2636 runDataflow( 2637 Code, 2638 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2639 ASTContext &ASTCtx) { 2640 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2641 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2642 2643 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2644 ASSERT_THAT(FooDecl, NotNull()); 2645 2646 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2647 ASSERT_THAT(BarDecl, NotNull()); 2648 2649 const auto *FooVal = Env.getValue(*FooDecl); 2650 const auto *BarVal = Env.getValue(*BarDecl); 2651 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 2652 EXPECT_TRUE(isa<IntegerValue>(BarVal)); 2653 EXPECT_EQ(FooVal, BarVal); 2654 }); 2655 } 2656 2657 TEST(TransferTest, IntegraltoBooleanCast) { 2658 std::string Code = R"( 2659 void target(int Foo) { 2660 bool Bar = Foo; 2661 // [[p]] 2662 } 2663 )"; 2664 runDataflow( 2665 Code, 2666 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2667 ASTContext &ASTCtx) { 2668 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2669 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2670 2671 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2672 ASSERT_THAT(FooDecl, NotNull()); 2673 2674 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2675 ASSERT_THAT(BarDecl, NotNull()); 2676 2677 const auto *FooVal = Env.getValue(*FooDecl); 2678 const auto *BarVal = Env.getValue(*BarDecl); 2679 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 2680 EXPECT_TRUE(isa<BoolValue>(BarVal)); 2681 }); 2682 } 2683 2684 TEST(TransferTest, IntegralToBooleanCastFromBool) { 2685 std::string Code = R"( 2686 void target(bool Foo) { 2687 int Zab = Foo; 2688 bool Bar = Zab; 2689 // [[p]] 2690 } 2691 )"; 2692 runDataflow( 2693 Code, 2694 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2695 ASTContext &ASTCtx) { 2696 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2697 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2698 2699 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2700 ASSERT_THAT(FooDecl, NotNull()); 2701 2702 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2703 ASSERT_THAT(BarDecl, NotNull()); 2704 2705 const auto *FooVal = Env.getValue(*FooDecl); 2706 const auto *BarVal = Env.getValue(*BarDecl); 2707 EXPECT_TRUE(isa<BoolValue>(FooVal)); 2708 EXPECT_TRUE(isa<BoolValue>(BarVal)); 2709 EXPECT_EQ(FooVal, BarVal); 2710 }); 2711 } 2712 2713 TEST(TransferTest, NullToPointerCast) { 2714 std::string Code = R"( 2715 using my_nullptr_t = decltype(nullptr); 2716 struct Baz {}; 2717 void target() { 2718 int *FooX = nullptr; 2719 int *FooY = nullptr; 2720 bool **Bar = nullptr; 2721 Baz *Baz = nullptr; 2722 my_nullptr_t Null = 0; 2723 // [[p]] 2724 } 2725 )"; 2726 runDataflow( 2727 Code, 2728 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2729 ASTContext &ASTCtx) { 2730 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2731 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2732 2733 const ValueDecl *FooXDecl = findValueDecl(ASTCtx, "FooX"); 2734 ASSERT_THAT(FooXDecl, NotNull()); 2735 2736 const ValueDecl *FooYDecl = findValueDecl(ASTCtx, "FooY"); 2737 ASSERT_THAT(FooYDecl, NotNull()); 2738 2739 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2740 ASSERT_THAT(BarDecl, NotNull()); 2741 2742 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2743 ASSERT_THAT(BazDecl, NotNull()); 2744 2745 const ValueDecl *NullDecl = findValueDecl(ASTCtx, "Null"); 2746 ASSERT_THAT(NullDecl, NotNull()); 2747 2748 const auto *FooXVal = cast<PointerValue>(Env.getValue(*FooXDecl)); 2749 const auto *FooYVal = cast<PointerValue>(Env.getValue(*FooYDecl)); 2750 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 2751 const auto *BazVal = cast<PointerValue>(Env.getValue(*BazDecl)); 2752 const auto *NullVal = cast<PointerValue>(Env.getValue(*NullDecl)); 2753 2754 EXPECT_EQ(FooXVal, FooYVal); 2755 EXPECT_NE(FooXVal, BarVal); 2756 EXPECT_NE(FooXVal, BazVal); 2757 EXPECT_NE(BarVal, BazVal); 2758 2759 const StorageLocation &FooPointeeLoc = FooXVal->getPointeeLoc(); 2760 EXPECT_TRUE(isa<ScalarStorageLocation>(FooPointeeLoc)); 2761 EXPECT_THAT(Env.getValue(FooPointeeLoc), IsNull()); 2762 2763 const StorageLocation &BarPointeeLoc = BarVal->getPointeeLoc(); 2764 EXPECT_TRUE(isa<ScalarStorageLocation>(BarPointeeLoc)); 2765 EXPECT_THAT(Env.getValue(BarPointeeLoc), IsNull()); 2766 2767 const StorageLocation &BazPointeeLoc = BazVal->getPointeeLoc(); 2768 EXPECT_TRUE(isa<RecordStorageLocation>(BazPointeeLoc)); 2769 EXPECT_THAT(Env.getValue(BazPointeeLoc), IsNull()); 2770 2771 const StorageLocation &NullPointeeLoc = NullVal->getPointeeLoc(); 2772 EXPECT_TRUE(isa<ScalarStorageLocation>(NullPointeeLoc)); 2773 EXPECT_THAT(Env.getValue(NullPointeeLoc), IsNull()); 2774 }); 2775 } 2776 2777 TEST(TransferTest, PointerToMemberVariable) { 2778 std::string Code = R"( 2779 struct S { 2780 int i; 2781 }; 2782 void target() { 2783 int S::*MemberPointer = &S::i; 2784 // [[p]] 2785 } 2786 )"; 2787 runDataflow( 2788 Code, 2789 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2790 ASTContext &ASTCtx) { 2791 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2792 2793 const ValueDecl *MemberPointerDecl = 2794 findValueDecl(ASTCtx, "MemberPointer"); 2795 ASSERT_THAT(MemberPointerDecl, NotNull()); 2796 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 2797 }); 2798 } 2799 2800 TEST(TransferTest, PointerToMemberFunction) { 2801 std::string Code = R"( 2802 struct S { 2803 void Method(); 2804 }; 2805 void target() { 2806 void (S::*MemberPointer)() = &S::Method; 2807 // [[p]] 2808 } 2809 )"; 2810 runDataflow( 2811 Code, 2812 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2813 ASTContext &ASTCtx) { 2814 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2815 2816 const ValueDecl *MemberPointerDecl = 2817 findValueDecl(ASTCtx, "MemberPointer"); 2818 ASSERT_THAT(MemberPointerDecl, NotNull()); 2819 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 2820 }); 2821 } 2822 2823 TEST(TransferTest, NullToMemberPointerCast) { 2824 std::string Code = R"( 2825 struct Foo {}; 2826 void target() { 2827 int Foo::*MemberPointer = nullptr; 2828 // [[p]] 2829 } 2830 )"; 2831 runDataflow( 2832 Code, 2833 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2834 ASTContext &ASTCtx) { 2835 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2836 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2837 2838 const ValueDecl *MemberPointerDecl = 2839 findValueDecl(ASTCtx, "MemberPointer"); 2840 ASSERT_THAT(MemberPointerDecl, NotNull()); 2841 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 2842 }); 2843 } 2844 2845 TEST(TransferTest, AddrOfValue) { 2846 std::string Code = R"( 2847 void target() { 2848 int Foo; 2849 int *Bar = &Foo; 2850 // [[p]] 2851 } 2852 )"; 2853 runDataflow( 2854 Code, 2855 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2856 ASTContext &ASTCtx) { 2857 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2858 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2859 2860 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2861 ASSERT_THAT(FooDecl, NotNull()); 2862 2863 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2864 ASSERT_THAT(BarDecl, NotNull()); 2865 2866 const auto *FooLoc = 2867 cast<ScalarStorageLocation>(Env.getStorageLocation(*FooDecl)); 2868 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 2869 EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc); 2870 }); 2871 } 2872 2873 TEST(TransferTest, AddrOfReference) { 2874 std::string Code = R"( 2875 void target(int *Foo) { 2876 int *Bar = &(*Foo); 2877 // [[p]] 2878 } 2879 )"; 2880 runDataflow( 2881 Code, 2882 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2883 ASTContext &ASTCtx) { 2884 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2885 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2886 2887 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2888 ASSERT_THAT(FooDecl, NotNull()); 2889 2890 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2891 ASSERT_THAT(BarDecl, NotNull()); 2892 2893 const auto *FooVal = cast<PointerValue>(Env.getValue(*FooDecl)); 2894 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 2895 EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc()); 2896 }); 2897 } 2898 2899 TEST(TransferTest, CannotAnalyzeFunctionTemplate) { 2900 std::string Code = R"( 2901 template <typename T> 2902 void target() {} 2903 )"; 2904 ASSERT_THAT_ERROR( 2905 checkDataflowWithNoopAnalysis(Code), 2906 llvm::FailedWithMessage("Cannot analyze templated declarations")); 2907 } 2908 2909 TEST(TransferTest, CannotAnalyzeMethodOfClassTemplate) { 2910 std::string Code = R"( 2911 template <typename T> 2912 struct A { 2913 void target() {} 2914 }; 2915 )"; 2916 ASSERT_THAT_ERROR( 2917 checkDataflowWithNoopAnalysis(Code), 2918 llvm::FailedWithMessage("Cannot analyze templated declarations")); 2919 } 2920 2921 TEST(TransferTest, VarDeclInitAssignConditionalOperator) { 2922 std::string Code = R"( 2923 struct A {}; 2924 2925 void target(A Foo, A Bar, bool Cond) { 2926 A Baz = Cond ? Foo : Bar; 2927 /*[[p]]*/ 2928 } 2929 )"; 2930 runDataflow( 2931 Code, 2932 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2933 ASTContext &ASTCtx) { 2934 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2935 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2936 2937 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2938 ASSERT_THAT(FooDecl, NotNull()); 2939 2940 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2941 ASSERT_THAT(BarDecl, NotNull()); 2942 2943 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2944 ASSERT_THAT(BazDecl, NotNull()); 2945 2946 const auto *FooVal = cast<RecordValue>(Env.getValue(*FooDecl)); 2947 const auto *BarVal = cast<RecordValue>(Env.getValue(*BarDecl)); 2948 2949 const auto *BazVal = dyn_cast<RecordValue>(Env.getValue(*BazDecl)); 2950 ASSERT_THAT(BazVal, NotNull()); 2951 2952 EXPECT_NE(BazVal, FooVal); 2953 EXPECT_NE(BazVal, BarVal); 2954 }); 2955 } 2956 2957 TEST(TransferTest, VarDeclInDoWhile) { 2958 std::string Code = R"( 2959 void target(int *Foo) { 2960 do { 2961 int Bar = *Foo; 2962 // [[in_loop]] 2963 } while (false); 2964 (void)0; 2965 // [[after_loop]] 2966 } 2967 )"; 2968 runDataflow( 2969 Code, 2970 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2971 ASTContext &ASTCtx) { 2972 const Environment &EnvInLoop = 2973 getEnvironmentAtAnnotation(Results, "in_loop"); 2974 const Environment &EnvAfterLoop = 2975 getEnvironmentAtAnnotation(Results, "after_loop"); 2976 2977 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2978 ASSERT_THAT(FooDecl, NotNull()); 2979 2980 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2981 ASSERT_THAT(BarDecl, NotNull()); 2982 2983 const auto *FooVal = 2984 cast<PointerValue>(EnvAfterLoop.getValue(*FooDecl)); 2985 const auto *FooPointeeVal = 2986 cast<IntegerValue>(EnvAfterLoop.getValue(FooVal->getPointeeLoc())); 2987 2988 const auto *BarVal = cast<IntegerValue>(EnvInLoop.getValue(*BarDecl)); 2989 EXPECT_EQ(BarVal, FooPointeeVal); 2990 2991 ASSERT_THAT(EnvAfterLoop.getValue(*BarDecl), IsNull()); 2992 }); 2993 } 2994 2995 TEST(TransferTest, UnreachableAfterWhileTrue) { 2996 std::string Code = R"( 2997 void target() { 2998 while (true) {} 2999 (void)0; 3000 /*[[p]]*/ 3001 } 3002 )"; 3003 runDataflow( 3004 Code, 3005 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3006 ASTContext &ASTCtx) { 3007 // The node after the while-true is pruned because it is trivially 3008 // known to be unreachable. 3009 ASSERT_TRUE(Results.empty()); 3010 }); 3011 } 3012 3013 TEST(TransferTest, AggregateInitialization) { 3014 std::string BracesCode = R"( 3015 struct A { 3016 int Foo; 3017 }; 3018 3019 struct B { 3020 int Bar; 3021 A Baz; 3022 int Qux; 3023 }; 3024 3025 void target(int BarArg, int FooArg, int QuxArg) { 3026 B Quux{BarArg, {FooArg}, QuxArg}; 3027 B OtherB; 3028 /*[[p]]*/ 3029 } 3030 )"; 3031 std::string BraceElisionCode = R"( 3032 struct A { 3033 int Foo; 3034 }; 3035 3036 struct B { 3037 int Bar; 3038 A Baz; 3039 int Qux; 3040 }; 3041 3042 void target(int BarArg, int FooArg, int QuxArg) { 3043 B Quux = {BarArg, FooArg, QuxArg}; 3044 B OtherB; 3045 /*[[p]]*/ 3046 } 3047 )"; 3048 for (const std::string &Code : {BracesCode, BraceElisionCode}) { 3049 runDataflow( 3050 Code, 3051 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3052 ASTContext &ASTCtx) { 3053 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3054 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3055 3056 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3057 ASSERT_THAT(FooDecl, NotNull()); 3058 3059 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3060 ASSERT_THAT(BarDecl, NotNull()); 3061 3062 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3063 ASSERT_THAT(BazDecl, NotNull()); 3064 3065 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 3066 ASSERT_THAT(QuxDecl, NotNull()); 3067 3068 const ValueDecl *FooArgDecl = findValueDecl(ASTCtx, "FooArg"); 3069 ASSERT_THAT(FooArgDecl, NotNull()); 3070 3071 const ValueDecl *BarArgDecl = findValueDecl(ASTCtx, "BarArg"); 3072 ASSERT_THAT(BarArgDecl, NotNull()); 3073 3074 const ValueDecl *QuxArgDecl = findValueDecl(ASTCtx, "QuxArg"); 3075 ASSERT_THAT(QuxArgDecl, NotNull()); 3076 3077 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 3078 ASSERT_THAT(QuuxDecl, NotNull()); 3079 3080 const auto *FooArgVal = cast<IntegerValue>(Env.getValue(*FooArgDecl)); 3081 const auto *BarArgVal = cast<IntegerValue>(Env.getValue(*BarArgDecl)); 3082 const auto *QuxArgVal = cast<IntegerValue>(Env.getValue(*QuxArgDecl)); 3083 3084 const auto &QuuxLoc = 3085 *cast<RecordStorageLocation>(Env.getStorageLocation(*QuuxDecl)); 3086 const auto &BazLoc = 3087 *cast<RecordStorageLocation>(QuuxLoc.getChild(*BazDecl)); 3088 3089 EXPECT_EQ(getFieldValue(&QuuxLoc, *BarDecl, Env), BarArgVal); 3090 EXPECT_EQ(getFieldValue(&BazLoc, *FooDecl, Env), FooArgVal); 3091 EXPECT_EQ(getFieldValue(&QuuxLoc, *QuxDecl, Env), QuxArgVal); 3092 3093 // Check that fields initialized in an initializer list are always 3094 // modeled in other instances of the same type. 3095 const auto &OtherBLoc = 3096 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "OtherB"); 3097 EXPECT_THAT(OtherBLoc.getChild(*BarDecl), NotNull()); 3098 EXPECT_THAT(OtherBLoc.getChild(*BazDecl), NotNull()); 3099 EXPECT_THAT(OtherBLoc.getChild(*QuxDecl), NotNull()); 3100 }); 3101 } 3102 } 3103 3104 TEST(TransferTest, AggregateInitializationReferenceField) { 3105 std::string Code = R"( 3106 struct S { 3107 int &RefField; 3108 }; 3109 3110 void target(int i) { 3111 S s = { i }; 3112 /*[[p]]*/ 3113 } 3114 )"; 3115 runDataflow( 3116 Code, 3117 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3118 ASTContext &ASTCtx) { 3119 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3120 3121 const ValueDecl *RefFieldDecl = findValueDecl(ASTCtx, "RefField"); 3122 3123 auto &ILoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "i"); 3124 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"); 3125 3126 EXPECT_EQ(SLoc.getChild(*RefFieldDecl), &ILoc); 3127 }); 3128 } 3129 3130 TEST(TransferTest, AggregateInitialization_NotExplicitlyInitializedField) { 3131 std::string Code = R"( 3132 struct S { 3133 int i1; 3134 int i2; 3135 }; 3136 3137 void target(int i) { 3138 S s = { i }; 3139 /*[[p]]*/ 3140 } 3141 )"; 3142 runDataflow( 3143 Code, 3144 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3145 ASTContext &ASTCtx) { 3146 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3147 3148 const ValueDecl *I1FieldDecl = findValueDecl(ASTCtx, "i1"); 3149 const ValueDecl *I2FieldDecl = findValueDecl(ASTCtx, "i2"); 3150 3151 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"); 3152 3153 auto &IValue = getValueForDecl<IntegerValue>(ASTCtx, Env, "i"); 3154 auto &I1Value = 3155 *cast<IntegerValue>(getFieldValue(&SLoc, *I1FieldDecl, Env)); 3156 EXPECT_EQ(&I1Value, &IValue); 3157 auto &I2Value = 3158 *cast<IntegerValue>(getFieldValue(&SLoc, *I2FieldDecl, Env)); 3159 EXPECT_NE(&I2Value, &IValue); 3160 }); 3161 } 3162 3163 TEST(TransferTest, AssignToUnionMember) { 3164 std::string Code = R"( 3165 union A { 3166 int Foo; 3167 }; 3168 3169 void target(int Bar) { 3170 A Baz; 3171 Baz.Foo = Bar; 3172 // [[p]] 3173 } 3174 )"; 3175 runDataflow( 3176 Code, 3177 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3178 ASTContext &ASTCtx) { 3179 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3180 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3181 3182 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3183 ASSERT_THAT(BazDecl, NotNull()); 3184 ASSERT_TRUE(BazDecl->getType()->isUnionType()); 3185 3186 auto BazFields = BazDecl->getType()->getAsRecordDecl()->fields(); 3187 FieldDecl *FooDecl = nullptr; 3188 for (FieldDecl *Field : BazFields) { 3189 if (Field->getNameAsString() == "Foo") { 3190 FooDecl = Field; 3191 } else { 3192 FAIL() << "Unexpected field: " << Field->getNameAsString(); 3193 } 3194 } 3195 ASSERT_THAT(FooDecl, NotNull()); 3196 3197 const auto *BazLoc = dyn_cast_or_null<RecordStorageLocation>( 3198 Env.getStorageLocation(*BazDecl)); 3199 ASSERT_THAT(BazLoc, NotNull()); 3200 ASSERT_THAT(Env.getValue(*BazLoc), NotNull()); 3201 3202 const auto *FooVal = 3203 cast<IntegerValue>(getFieldValue(BazLoc, *FooDecl, Env)); 3204 3205 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3206 ASSERT_THAT(BarDecl, NotNull()); 3207 const auto *BarLoc = Env.getStorageLocation(*BarDecl); 3208 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 3209 3210 EXPECT_EQ(Env.getValue(*BarLoc), FooVal); 3211 }); 3212 } 3213 3214 TEST(TransferTest, AssignFromBoolLiteral) { 3215 std::string Code = R"( 3216 void target() { 3217 bool Foo = true; 3218 bool Bar = false; 3219 // [[p]] 3220 } 3221 )"; 3222 runDataflow( 3223 Code, 3224 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3225 ASTContext &ASTCtx) { 3226 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3227 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3228 3229 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3230 ASSERT_THAT(FooDecl, NotNull()); 3231 3232 const auto *FooVal = 3233 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3234 ASSERT_THAT(FooVal, NotNull()); 3235 3236 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3237 ASSERT_THAT(BarDecl, NotNull()); 3238 3239 const auto *BarVal = 3240 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 3241 ASSERT_THAT(BarVal, NotNull()); 3242 3243 EXPECT_EQ(FooVal, &Env.getBoolLiteralValue(true)); 3244 EXPECT_EQ(BarVal, &Env.getBoolLiteralValue(false)); 3245 }); 3246 } 3247 3248 TEST(TransferTest, AssignFromCompositeBoolExpression) { 3249 { 3250 std::string Code = R"( 3251 void target(bool Foo, bool Bar, bool Qux) { 3252 bool Baz = (Foo) && (Bar || Qux); 3253 // [[p]] 3254 } 3255 )"; 3256 runDataflow( 3257 Code, 3258 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3259 ASTContext &ASTCtx) { 3260 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3261 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3262 3263 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3264 ASSERT_THAT(FooDecl, NotNull()); 3265 3266 const auto *FooVal = 3267 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3268 ASSERT_THAT(FooVal, NotNull()); 3269 3270 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3271 ASSERT_THAT(BarDecl, NotNull()); 3272 3273 const auto *BarVal = 3274 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 3275 ASSERT_THAT(BarVal, NotNull()); 3276 3277 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 3278 ASSERT_THAT(QuxDecl, NotNull()); 3279 3280 const auto *QuxVal = 3281 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl)); 3282 ASSERT_THAT(QuxVal, NotNull()); 3283 3284 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3285 ASSERT_THAT(BazDecl, NotNull()); 3286 3287 const auto *BazVal = 3288 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl)); 3289 ASSERT_THAT(BazVal, NotNull()); 3290 auto &A = Env.arena(); 3291 EXPECT_EQ(&BazVal->formula(), 3292 &A.makeAnd(FooVal->formula(), 3293 A.makeOr(BarVal->formula(), QuxVal->formula()))); 3294 }); 3295 } 3296 3297 { 3298 std::string Code = R"( 3299 void target(bool Foo, bool Bar, bool Qux) { 3300 bool Baz = (Foo && Qux) || (Bar); 3301 // [[p]] 3302 } 3303 )"; 3304 runDataflow( 3305 Code, 3306 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3307 ASTContext &ASTCtx) { 3308 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3309 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3310 3311 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3312 ASSERT_THAT(FooDecl, NotNull()); 3313 3314 const auto *FooVal = 3315 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3316 ASSERT_THAT(FooVal, NotNull()); 3317 3318 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3319 ASSERT_THAT(BarDecl, NotNull()); 3320 3321 const auto *BarVal = 3322 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 3323 ASSERT_THAT(BarVal, NotNull()); 3324 3325 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 3326 ASSERT_THAT(QuxDecl, NotNull()); 3327 3328 const auto *QuxVal = 3329 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl)); 3330 ASSERT_THAT(QuxVal, NotNull()); 3331 3332 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3333 ASSERT_THAT(BazDecl, NotNull()); 3334 3335 const auto *BazVal = 3336 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl)); 3337 ASSERT_THAT(BazVal, NotNull()); 3338 auto &A = Env.arena(); 3339 EXPECT_EQ(&BazVal->formula(), 3340 &A.makeOr(A.makeAnd(FooVal->formula(), QuxVal->formula()), 3341 BarVal->formula())); 3342 }); 3343 } 3344 3345 { 3346 std::string Code = R"( 3347 void target(bool A, bool B, bool C, bool D) { 3348 bool Foo = ((A && B) && C) && D; 3349 // [[p]] 3350 } 3351 )"; 3352 runDataflow( 3353 Code, 3354 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3355 ASTContext &ASTCtx) { 3356 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3357 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3358 3359 const ValueDecl *ADecl = findValueDecl(ASTCtx, "A"); 3360 ASSERT_THAT(ADecl, NotNull()); 3361 3362 const auto *AVal = dyn_cast_or_null<BoolValue>(Env.getValue(*ADecl)); 3363 ASSERT_THAT(AVal, NotNull()); 3364 3365 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B"); 3366 ASSERT_THAT(BDecl, NotNull()); 3367 3368 const auto *BVal = dyn_cast_or_null<BoolValue>(Env.getValue(*BDecl)); 3369 ASSERT_THAT(BVal, NotNull()); 3370 3371 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C"); 3372 ASSERT_THAT(CDecl, NotNull()); 3373 3374 const auto *CVal = dyn_cast_or_null<BoolValue>(Env.getValue(*CDecl)); 3375 ASSERT_THAT(CVal, NotNull()); 3376 3377 const ValueDecl *DDecl = findValueDecl(ASTCtx, "D"); 3378 ASSERT_THAT(DDecl, NotNull()); 3379 3380 const auto *DVal = dyn_cast_or_null<BoolValue>(Env.getValue(*DDecl)); 3381 ASSERT_THAT(DVal, NotNull()); 3382 3383 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3384 ASSERT_THAT(FooDecl, NotNull()); 3385 3386 const auto *FooVal = 3387 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3388 ASSERT_THAT(FooVal, NotNull()); 3389 auto &A = Env.arena(); 3390 EXPECT_EQ( 3391 &FooVal->formula(), 3392 &A.makeAnd(A.makeAnd(A.makeAnd(AVal->formula(), BVal->formula()), 3393 CVal->formula()), 3394 DVal->formula())); 3395 }); 3396 } 3397 } 3398 3399 TEST(TransferTest, AssignFromBoolNegation) { 3400 std::string Code = R"( 3401 void target() { 3402 bool Foo = true; 3403 bool Bar = !(Foo); 3404 // [[p]] 3405 } 3406 )"; 3407 runDataflow( 3408 Code, 3409 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3410 ASTContext &ASTCtx) { 3411 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3412 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3413 3414 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3415 ASSERT_THAT(FooDecl, NotNull()); 3416 3417 const auto *FooVal = 3418 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3419 ASSERT_THAT(FooVal, NotNull()); 3420 3421 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3422 ASSERT_THAT(BarDecl, NotNull()); 3423 3424 const auto *BarVal = 3425 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 3426 ASSERT_THAT(BarVal, NotNull()); 3427 auto &A = Env.arena(); 3428 EXPECT_EQ(&BarVal->formula(), &A.makeNot(FooVal->formula())); 3429 }); 3430 } 3431 3432 TEST(TransferTest, BuiltinExpect) { 3433 std::string Code = R"( 3434 void target(long Foo) { 3435 long Bar = __builtin_expect(Foo, true); 3436 /*[[p]]*/ 3437 } 3438 )"; 3439 runDataflow( 3440 Code, 3441 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3442 ASTContext &ASTCtx) { 3443 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3444 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3445 3446 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3447 ASSERT_THAT(FooDecl, NotNull()); 3448 3449 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3450 ASSERT_THAT(BarDecl, NotNull()); 3451 3452 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3453 }); 3454 } 3455 3456 // `__builtin_expect` takes and returns a `long` argument, so other types 3457 // involve casts. This verifies that we identify the input and output in that 3458 // case. 3459 TEST(TransferTest, BuiltinExpectBoolArg) { 3460 std::string Code = R"( 3461 void target(bool Foo) { 3462 bool Bar = __builtin_expect(Foo, true); 3463 /*[[p]]*/ 3464 } 3465 )"; 3466 runDataflow( 3467 Code, 3468 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3469 ASTContext &ASTCtx) { 3470 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3471 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3472 3473 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3474 ASSERT_THAT(FooDecl, NotNull()); 3475 3476 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3477 ASSERT_THAT(BarDecl, NotNull()); 3478 3479 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3480 }); 3481 } 3482 3483 TEST(TransferTest, BuiltinUnreachable) { 3484 std::string Code = R"( 3485 void target(bool Foo) { 3486 bool Bar = false; 3487 if (Foo) 3488 Bar = Foo; 3489 else 3490 __builtin_unreachable(); 3491 (void)0; 3492 /*[[p]]*/ 3493 } 3494 )"; 3495 runDataflow( 3496 Code, 3497 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3498 ASTContext &ASTCtx) { 3499 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3500 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3501 3502 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3503 ASSERT_THAT(FooDecl, NotNull()); 3504 3505 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3506 ASSERT_THAT(BarDecl, NotNull()); 3507 3508 // `__builtin_unreachable` promises that the code is 3509 // unreachable, so the compiler treats the "then" branch as the 3510 // only possible predecessor of this statement. 3511 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3512 }); 3513 } 3514 3515 TEST(TransferTest, BuiltinTrap) { 3516 std::string Code = R"( 3517 void target(bool Foo) { 3518 bool Bar = false; 3519 if (Foo) 3520 Bar = Foo; 3521 else 3522 __builtin_trap(); 3523 (void)0; 3524 /*[[p]]*/ 3525 } 3526 )"; 3527 runDataflow( 3528 Code, 3529 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3530 ASTContext &ASTCtx) { 3531 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3532 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3533 3534 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3535 ASSERT_THAT(FooDecl, NotNull()); 3536 3537 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3538 ASSERT_THAT(BarDecl, NotNull()); 3539 3540 // `__builtin_trap` ensures program termination, so only the 3541 // "then" branch is a predecessor of this statement. 3542 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3543 }); 3544 } 3545 3546 TEST(TransferTest, BuiltinDebugTrap) { 3547 std::string Code = R"( 3548 void target(bool Foo) { 3549 bool Bar = false; 3550 if (Foo) 3551 Bar = Foo; 3552 else 3553 __builtin_debugtrap(); 3554 (void)0; 3555 /*[[p]]*/ 3556 } 3557 )"; 3558 runDataflow( 3559 Code, 3560 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3561 ASTContext &ASTCtx) { 3562 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3563 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3564 3565 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3566 ASSERT_THAT(FooDecl, NotNull()); 3567 3568 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3569 ASSERT_THAT(BarDecl, NotNull()); 3570 3571 // `__builtin_debugtrap` doesn't ensure program termination. 3572 EXPECT_NE(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3573 }); 3574 } 3575 3576 TEST(TransferTest, StaticIntSingleVarDecl) { 3577 std::string Code = R"( 3578 void target() { 3579 static int Foo; 3580 // [[p]] 3581 } 3582 )"; 3583 runDataflow( 3584 Code, 3585 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3586 ASTContext &ASTCtx) { 3587 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3588 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3589 3590 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3591 ASSERT_THAT(FooDecl, NotNull()); 3592 3593 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 3594 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 3595 3596 const Value *FooVal = Env.getValue(*FooLoc); 3597 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 3598 }); 3599 } 3600 3601 TEST(TransferTest, StaticIntGroupVarDecl) { 3602 std::string Code = R"( 3603 void target() { 3604 static int Foo, Bar; 3605 (void)0; 3606 // [[p]] 3607 } 3608 )"; 3609 runDataflow( 3610 Code, 3611 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3612 ASTContext &ASTCtx) { 3613 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3614 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3615 3616 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3617 ASSERT_THAT(FooDecl, NotNull()); 3618 3619 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3620 ASSERT_THAT(BarDecl, NotNull()); 3621 3622 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 3623 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 3624 3625 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 3626 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 3627 3628 const Value *FooVal = Env.getValue(*FooLoc); 3629 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 3630 3631 const Value *BarVal = Env.getValue(*BarLoc); 3632 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 3633 3634 EXPECT_NE(FooVal, BarVal); 3635 }); 3636 } 3637 3638 TEST(TransferTest, GlobalIntVarDecl) { 3639 std::string Code = R"( 3640 static int Foo; 3641 3642 void target() { 3643 int Bar = Foo; 3644 int Baz = Foo; 3645 // [[p]] 3646 } 3647 )"; 3648 runDataflow( 3649 Code, 3650 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3651 ASTContext &ASTCtx) { 3652 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3653 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3654 3655 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3656 ASSERT_THAT(BarDecl, NotNull()); 3657 3658 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3659 ASSERT_THAT(BazDecl, NotNull()); 3660 3661 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 3662 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 3663 EXPECT_EQ(BarVal, BazVal); 3664 }); 3665 } 3666 3667 TEST(TransferTest, StaticMemberIntVarDecl) { 3668 std::string Code = R"( 3669 struct A { 3670 static int Foo; 3671 }; 3672 3673 void target(A a) { 3674 int Bar = a.Foo; 3675 int Baz = a.Foo; 3676 // [[p]] 3677 } 3678 )"; 3679 runDataflow( 3680 Code, 3681 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3682 ASTContext &ASTCtx) { 3683 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3684 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3685 3686 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3687 ASSERT_THAT(BarDecl, NotNull()); 3688 3689 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3690 ASSERT_THAT(BazDecl, NotNull()); 3691 3692 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 3693 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 3694 EXPECT_EQ(BarVal, BazVal); 3695 }); 3696 } 3697 3698 TEST(TransferTest, StaticMemberRefVarDecl) { 3699 std::string Code = R"( 3700 struct A { 3701 static int &Foo; 3702 }; 3703 3704 void target(A a) { 3705 int Bar = a.Foo; 3706 int Baz = a.Foo; 3707 // [[p]] 3708 } 3709 )"; 3710 runDataflow( 3711 Code, 3712 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3713 ASTContext &ASTCtx) { 3714 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3715 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3716 3717 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3718 ASSERT_THAT(BarDecl, NotNull()); 3719 3720 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3721 ASSERT_THAT(BazDecl, NotNull()); 3722 3723 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 3724 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 3725 EXPECT_EQ(BarVal, BazVal); 3726 }); 3727 } 3728 3729 TEST(TransferTest, AssignMemberBeforeCopy) { 3730 std::string Code = R"( 3731 struct A { 3732 int Foo; 3733 }; 3734 3735 void target() { 3736 A A1; 3737 A A2; 3738 int Bar; 3739 A1.Foo = Bar; 3740 A2 = A1; 3741 // [[p]] 3742 } 3743 )"; 3744 runDataflow( 3745 Code, 3746 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3747 ASTContext &ASTCtx) { 3748 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3749 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3750 3751 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3752 ASSERT_THAT(FooDecl, NotNull()); 3753 3754 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3755 ASSERT_THAT(BarDecl, NotNull()); 3756 3757 const ValueDecl *A1Decl = findValueDecl(ASTCtx, "A1"); 3758 ASSERT_THAT(A1Decl, NotNull()); 3759 3760 const ValueDecl *A2Decl = findValueDecl(ASTCtx, "A2"); 3761 ASSERT_THAT(A2Decl, NotNull()); 3762 3763 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 3764 3765 const auto &A2Loc = 3766 *cast<RecordStorageLocation>(Env.getStorageLocation(*A2Decl)); 3767 EXPECT_EQ(getFieldValue(&A2Loc, *FooDecl, Env), BarVal); 3768 }); 3769 } 3770 3771 TEST(TransferTest, BooleanEquality) { 3772 std::string Code = R"( 3773 void target(bool Bar) { 3774 bool Foo = true; 3775 if (Bar == Foo) { 3776 (void)0; 3777 /*[[p-then]]*/ 3778 } else { 3779 (void)0; 3780 /*[[p-else]]*/ 3781 } 3782 } 3783 )"; 3784 runDataflow( 3785 Code, 3786 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3787 ASTContext &ASTCtx) { 3788 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else")); 3789 const Environment &EnvThen = 3790 getEnvironmentAtAnnotation(Results, "p-then"); 3791 const Environment &EnvElse = 3792 getEnvironmentAtAnnotation(Results, "p-else"); 3793 3794 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3795 ASSERT_THAT(BarDecl, NotNull()); 3796 3797 auto &BarValThen = getFormula(*BarDecl, EnvThen); 3798 EXPECT_TRUE(EnvThen.flowConditionImplies(BarValThen)); 3799 3800 auto &BarValElse = getFormula(*BarDecl, EnvElse); 3801 EXPECT_TRUE( 3802 EnvElse.flowConditionImplies(EnvElse.arena().makeNot(BarValElse))); 3803 }); 3804 } 3805 3806 TEST(TransferTest, BooleanInequality) { 3807 std::string Code = R"( 3808 void target(bool Bar) { 3809 bool Foo = true; 3810 if (Bar != Foo) { 3811 (void)0; 3812 /*[[p-then]]*/ 3813 } else { 3814 (void)0; 3815 /*[[p-else]]*/ 3816 } 3817 } 3818 )"; 3819 runDataflow( 3820 Code, 3821 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3822 ASTContext &ASTCtx) { 3823 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else")); 3824 const Environment &EnvThen = 3825 getEnvironmentAtAnnotation(Results, "p-then"); 3826 const Environment &EnvElse = 3827 getEnvironmentAtAnnotation(Results, "p-else"); 3828 3829 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3830 ASSERT_THAT(BarDecl, NotNull()); 3831 3832 auto &BarValThen = getFormula(*BarDecl, EnvThen); 3833 EXPECT_TRUE( 3834 EnvThen.flowConditionImplies(EnvThen.arena().makeNot(BarValThen))); 3835 3836 auto &BarValElse = getFormula(*BarDecl, EnvElse); 3837 EXPECT_TRUE(EnvElse.flowConditionImplies(BarValElse)); 3838 }); 3839 } 3840 3841 TEST(TransferTest, IntegerLiteralEquality) { 3842 std::string Code = R"( 3843 void target() { 3844 bool equal = (42 == 42); 3845 // [[p]] 3846 } 3847 )"; 3848 runDataflow( 3849 Code, 3850 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3851 ASTContext &ASTCtx) { 3852 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3853 3854 auto &Equal = 3855 getValueForDecl<BoolValue>(ASTCtx, Env, "equal").formula(); 3856 EXPECT_TRUE(Env.flowConditionImplies(Equal)); 3857 }); 3858 } 3859 3860 TEST(TransferTest, CorrelatedBranches) { 3861 std::string Code = R"( 3862 void target(bool B, bool C) { 3863 if (B) { 3864 return; 3865 } 3866 (void)0; 3867 /*[[p0]]*/ 3868 if (C) { 3869 B = true; 3870 /*[[p1]]*/ 3871 } 3872 if (B) { 3873 (void)0; 3874 /*[[p2]]*/ 3875 } 3876 } 3877 )"; 3878 runDataflow( 3879 Code, 3880 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3881 ASTContext &ASTCtx) { 3882 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p0", "p1", "p2")); 3883 3884 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C"); 3885 ASSERT_THAT(CDecl, NotNull()); 3886 3887 { 3888 const Environment &Env = getEnvironmentAtAnnotation(Results, "p0"); 3889 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B"); 3890 ASSERT_THAT(BDecl, NotNull()); 3891 auto &BVal = getFormula(*BDecl, Env); 3892 3893 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(BVal))); 3894 } 3895 3896 { 3897 const Environment &Env = getEnvironmentAtAnnotation(Results, "p1"); 3898 auto &CVal = getFormula(*CDecl, Env); 3899 EXPECT_TRUE(Env.flowConditionImplies(CVal)); 3900 } 3901 3902 { 3903 const Environment &Env = getEnvironmentAtAnnotation(Results, "p2"); 3904 auto &CVal = getFormula(*CDecl, Env); 3905 EXPECT_TRUE(Env.flowConditionImplies(CVal)); 3906 } 3907 }); 3908 } 3909 3910 TEST(TransferTest, LoopWithAssignmentConverges) { 3911 std::string Code = R"( 3912 bool foo(); 3913 3914 void target() { 3915 do { 3916 bool Bar = foo(); 3917 if (Bar) break; 3918 (void)Bar; 3919 /*[[p]]*/ 3920 } while (true); 3921 } 3922 )"; 3923 // The key property that we are verifying is implicit in `runDataflow` -- 3924 // namely, that the analysis succeeds, rather than hitting the maximum number 3925 // of iterations. 3926 runDataflow( 3927 Code, 3928 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3929 ASTContext &ASTCtx) { 3930 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3931 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3932 3933 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3934 ASSERT_THAT(BarDecl, NotNull()); 3935 3936 auto &BarVal = getFormula(*BarDecl, Env); 3937 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(BarVal))); 3938 }); 3939 } 3940 3941 TEST(TransferTest, LoopWithStagedAssignments) { 3942 std::string Code = R"( 3943 bool foo(); 3944 3945 void target() { 3946 bool Bar = false; 3947 bool Err = false; 3948 while (foo()) { 3949 if (Bar) 3950 Err = true; 3951 Bar = true; 3952 /*[[p]]*/ 3953 } 3954 } 3955 )"; 3956 runDataflow( 3957 Code, 3958 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3959 ASTContext &ASTCtx) { 3960 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3961 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3962 3963 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3964 ASSERT_THAT(BarDecl, NotNull()); 3965 const ValueDecl *ErrDecl = findValueDecl(ASTCtx, "Err"); 3966 ASSERT_THAT(ErrDecl, NotNull()); 3967 3968 auto &BarVal = getFormula(*BarDecl, Env); 3969 auto &ErrVal = getFormula(*ErrDecl, Env); 3970 EXPECT_TRUE(Env.flowConditionImplies(BarVal)); 3971 // An unsound analysis, for example only evaluating the loop once, can 3972 // conclude that `Err` is false. So, we test that this conclusion is not 3973 // reached. 3974 EXPECT_FALSE( 3975 Env.flowConditionImplies(Env.arena().makeNot(ErrVal))); 3976 }); 3977 } 3978 3979 TEST(TransferTest, LoopWithReferenceAssignmentConverges) { 3980 std::string Code = R"( 3981 bool &foo(); 3982 3983 void target() { 3984 do { 3985 bool& Bar = foo(); 3986 if (Bar) break; 3987 (void)Bar; 3988 /*[[p]]*/ 3989 } while (true); 3990 } 3991 )"; 3992 // The key property that we are verifying is that the analysis succeeds, 3993 // rather than hitting the maximum number of iterations. 3994 runDataflow( 3995 Code, 3996 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3997 ASTContext &ASTCtx) { 3998 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3999 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4000 4001 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4002 ASSERT_THAT(BarDecl, NotNull()); 4003 4004 auto &BarVal = getFormula(*BarDecl, Env); 4005 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(BarVal))); 4006 }); 4007 } 4008 4009 TEST(TransferTest, LoopWithStructReferenceAssignmentConverges) { 4010 std::string Code = R"( 4011 struct Lookup { 4012 int x; 4013 }; 4014 4015 void target(Lookup val, bool b) { 4016 const Lookup* l = nullptr; 4017 while (b) { 4018 l = &val; 4019 /*[[p-inner]]*/ 4020 } 4021 (void)0; 4022 /*[[p-outer]]*/ 4023 } 4024 )"; 4025 // The key property that we are verifying is implicit in `runDataflow` -- 4026 // namely, that the analysis succeeds, rather than hitting the maximum number 4027 // of iterations. 4028 runDataflow( 4029 Code, 4030 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4031 ASTContext &ASTCtx) { 4032 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-inner", "p-outer")); 4033 const Environment &InnerEnv = 4034 getEnvironmentAtAnnotation(Results, "p-inner"); 4035 const Environment &OuterEnv = 4036 getEnvironmentAtAnnotation(Results, "p-outer"); 4037 4038 const ValueDecl *ValDecl = findValueDecl(ASTCtx, "val"); 4039 ASSERT_THAT(ValDecl, NotNull()); 4040 4041 const ValueDecl *LDecl = findValueDecl(ASTCtx, "l"); 4042 ASSERT_THAT(LDecl, NotNull()); 4043 4044 // Inner. 4045 auto *LVal = dyn_cast<PointerValue>(InnerEnv.getValue(*LDecl)); 4046 ASSERT_THAT(LVal, NotNull()); 4047 4048 EXPECT_EQ(&LVal->getPointeeLoc(), 4049 InnerEnv.getStorageLocation(*ValDecl)); 4050 4051 // Outer. 4052 LVal = dyn_cast<PointerValue>(OuterEnv.getValue(*LDecl)); 4053 ASSERT_THAT(LVal, NotNull()); 4054 4055 // The loop body may not have been executed, so we should not conclude 4056 // that `l` points to `val`. 4057 EXPECT_NE(&LVal->getPointeeLoc(), 4058 OuterEnv.getStorageLocation(*ValDecl)); 4059 }); 4060 } 4061 4062 TEST(TransferTest, LoopDereferencingChangingPointerConverges) { 4063 std::string Code = R"cc( 4064 bool some_condition(); 4065 4066 void target(int i1, int i2) { 4067 int *p = &i1; 4068 while (true) { 4069 (void)*p; 4070 if (some_condition()) 4071 p = &i1; 4072 else 4073 p = &i2; 4074 } 4075 } 4076 )cc"; 4077 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 4078 } 4079 4080 TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) { 4081 std::string Code = R"cc( 4082 struct Lookup { 4083 int x; 4084 }; 4085 4086 bool some_condition(); 4087 4088 void target(Lookup l1, Lookup l2) { 4089 Lookup *l = &l1; 4090 while (true) { 4091 (void)l->x; 4092 if (some_condition()) 4093 l = &l1; 4094 else 4095 l = &l2; 4096 } 4097 } 4098 )cc"; 4099 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 4100 } 4101 4102 TEST(TransferTest, LoopWithShortCircuitedConditionConverges) { 4103 std::string Code = R"cc( 4104 bool foo(); 4105 4106 void target() { 4107 bool c = false; 4108 while (foo() || foo()) { 4109 c = true; 4110 } 4111 } 4112 )cc"; 4113 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 4114 } 4115 4116 TEST(TransferTest, DoesNotCrashOnUnionThisExpr) { 4117 std::string Code = R"( 4118 union Union { 4119 int A; 4120 float B; 4121 }; 4122 4123 void foo() { 4124 Union A; 4125 Union B; 4126 A = B; 4127 } 4128 )"; 4129 // This is a crash regression test when calling the transfer function on a 4130 // `CXXThisExpr` that refers to a union. 4131 runDataflow( 4132 Code, 4133 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &, 4134 ASTContext &) {}, 4135 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator="); 4136 } 4137 4138 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToRefs) { 4139 std::string Code = R"( 4140 struct A { 4141 int Foo; 4142 int Bar; 4143 }; 4144 4145 void target() { 4146 int Qux; 4147 A Baz; 4148 Baz.Foo = Qux; 4149 auto &FooRef = Baz.Foo; 4150 auto &BarRef = Baz.Bar; 4151 auto &[BoundFooRef, BoundBarRef] = Baz; 4152 // [[p]] 4153 } 4154 )"; 4155 runDataflow( 4156 Code, 4157 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4158 ASTContext &ASTCtx) { 4159 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4160 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4161 4162 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 4163 ASSERT_THAT(FooRefDecl, NotNull()); 4164 4165 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 4166 ASSERT_THAT(BarRefDecl, NotNull()); 4167 4168 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4169 ASSERT_THAT(QuxDecl, NotNull()); 4170 4171 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef"); 4172 ASSERT_THAT(BoundFooRefDecl, NotNull()); 4173 4174 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef"); 4175 ASSERT_THAT(BoundBarRefDecl, NotNull()); 4176 4177 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 4178 ASSERT_THAT(FooRefLoc, NotNull()); 4179 4180 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 4181 ASSERT_THAT(BarRefLoc, NotNull()); 4182 4183 const Value *QuxVal = Env.getValue(*QuxDecl); 4184 ASSERT_THAT(QuxVal, NotNull()); 4185 4186 const StorageLocation *BoundFooRefLoc = 4187 Env.getStorageLocation(*BoundFooRefDecl); 4188 EXPECT_EQ(BoundFooRefLoc, FooRefLoc); 4189 4190 const StorageLocation *BoundBarRefLoc = 4191 Env.getStorageLocation(*BoundBarRefDecl); 4192 EXPECT_EQ(BoundBarRefLoc, BarRefLoc); 4193 4194 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal); 4195 }); 4196 } 4197 4198 TEST(TransferTest, StructuredBindingAssignFromStructRefMembersToRefs) { 4199 std::string Code = R"( 4200 struct A { 4201 int &Foo; 4202 int &Bar; 4203 }; 4204 4205 void target(A Baz) { 4206 int Qux; 4207 Baz.Foo = Qux; 4208 auto &FooRef = Baz.Foo; 4209 auto &BarRef = Baz.Bar; 4210 auto &[BoundFooRef, BoundBarRef] = Baz; 4211 // [[p]] 4212 } 4213 )"; 4214 runDataflow( 4215 Code, 4216 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4217 ASTContext &ASTCtx) { 4218 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4219 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4220 4221 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 4222 ASSERT_THAT(FooRefDecl, NotNull()); 4223 4224 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 4225 ASSERT_THAT(BarRefDecl, NotNull()); 4226 4227 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4228 ASSERT_THAT(QuxDecl, NotNull()); 4229 4230 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef"); 4231 ASSERT_THAT(BoundFooRefDecl, NotNull()); 4232 4233 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef"); 4234 ASSERT_THAT(BoundBarRefDecl, NotNull()); 4235 4236 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 4237 ASSERT_THAT(FooRefLoc, NotNull()); 4238 4239 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 4240 ASSERT_THAT(BarRefLoc, NotNull()); 4241 4242 const Value *QuxVal = Env.getValue(*QuxDecl); 4243 ASSERT_THAT(QuxVal, NotNull()); 4244 4245 const StorageLocation *BoundFooRefLoc = 4246 Env.getStorageLocation(*BoundFooRefDecl); 4247 EXPECT_EQ(BoundFooRefLoc, FooRefLoc); 4248 4249 const StorageLocation *BoundBarRefLoc = 4250 Env.getStorageLocation(*BoundBarRefDecl); 4251 EXPECT_EQ(BoundBarRefLoc, BarRefLoc); 4252 4253 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal); 4254 }); 4255 } 4256 4257 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToInts) { 4258 std::string Code = R"( 4259 struct A { 4260 int Foo; 4261 int Bar; 4262 }; 4263 4264 void target() { 4265 int Qux; 4266 A Baz; 4267 Baz.Foo = Qux; 4268 auto &FooRef = Baz.Foo; 4269 auto &BarRef = Baz.Bar; 4270 auto [BoundFoo, BoundBar] = Baz; 4271 // [[p]] 4272 } 4273 )"; 4274 runDataflow( 4275 Code, 4276 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4277 ASTContext &ASTCtx) { 4278 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4279 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4280 4281 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 4282 ASSERT_THAT(FooRefDecl, NotNull()); 4283 4284 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 4285 ASSERT_THAT(BarRefDecl, NotNull()); 4286 4287 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 4288 ASSERT_THAT(BoundFooDecl, NotNull()); 4289 4290 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 4291 ASSERT_THAT(BoundBarDecl, NotNull()); 4292 4293 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4294 ASSERT_THAT(QuxDecl, NotNull()); 4295 4296 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 4297 ASSERT_THAT(FooRefLoc, NotNull()); 4298 4299 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 4300 ASSERT_THAT(BarRefLoc, NotNull()); 4301 4302 const Value *QuxVal = Env.getValue(*QuxDecl); 4303 ASSERT_THAT(QuxVal, NotNull()); 4304 4305 const StorageLocation *BoundFooLoc = 4306 Env.getStorageLocation(*BoundFooDecl); 4307 EXPECT_NE(BoundFooLoc, FooRefLoc); 4308 4309 const StorageLocation *BoundBarLoc = 4310 Env.getStorageLocation(*BoundBarDecl); 4311 EXPECT_NE(BoundBarLoc, BarRefLoc); 4312 4313 EXPECT_EQ(Env.getValue(*BoundFooDecl), QuxVal); 4314 }); 4315 } 4316 4317 TEST(TransferTest, StructuredBindingAssignFromTupleLikeType) { 4318 std::string Code = R"( 4319 namespace std { 4320 using size_t = int; 4321 template <class> struct tuple_size; 4322 template <std::size_t, class> struct tuple_element; 4323 template <class...> class tuple; 4324 4325 namespace { 4326 template <class T, T v> 4327 struct size_helper { static const T value = v; }; 4328 } // namespace 4329 4330 template <class... T> 4331 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {}; 4332 4333 template <std::size_t I, class... T> 4334 struct tuple_element<I, tuple<T...>> { 4335 using type = __type_pack_element<I, T...>; 4336 }; 4337 4338 template <class...> class tuple {}; 4339 4340 template <std::size_t I, class... T> 4341 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 4342 } // namespace std 4343 4344 std::tuple<bool, int> makeTuple(); 4345 4346 void target(bool B) { 4347 auto [BoundFoo, BoundBar] = makeTuple(); 4348 bool Baz; 4349 // Include if-then-else to test interaction of `BindingDecl` with join. 4350 if (B) { 4351 Baz = BoundFoo; 4352 (void)BoundBar; 4353 // [[p1]] 4354 } else { 4355 Baz = BoundFoo; 4356 } 4357 (void)0; 4358 // [[p2]] 4359 } 4360 )"; 4361 runDataflow( 4362 Code, 4363 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4364 ASTContext &ASTCtx) { 4365 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 4366 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 4367 4368 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 4369 ASSERT_THAT(BoundFooDecl, NotNull()); 4370 4371 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 4372 ASSERT_THAT(BoundBarDecl, NotNull()); 4373 4374 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4375 ASSERT_THAT(BazDecl, NotNull()); 4376 4377 // BindingDecls always map to references -- either lvalue or rvalue, so 4378 // we still need to skip here. 4379 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl); 4380 ASSERT_THAT(BoundFooValue, NotNull()); 4381 EXPECT_TRUE(isa<BoolValue>(BoundFooValue)); 4382 4383 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl); 4384 ASSERT_THAT(BoundBarValue, NotNull()); 4385 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue)); 4386 4387 // Test that a `DeclRefExpr` to a `BindingDecl` works as expected. 4388 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue); 4389 4390 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 4391 4392 // Test that `BoundFooDecl` retains the value we expect, after the join. 4393 BoundFooValue = Env2.getValue(*BoundFooDecl); 4394 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue); 4395 }); 4396 } 4397 4398 TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) { 4399 std::string Code = R"( 4400 namespace std { 4401 using size_t = int; 4402 template <class> struct tuple_size; 4403 template <std::size_t, class> struct tuple_element; 4404 template <class...> class tuple; 4405 4406 namespace { 4407 template <class T, T v> 4408 struct size_helper { static const T value = v; }; 4409 } // namespace 4410 4411 template <class... T> 4412 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {}; 4413 4414 template <std::size_t I, class... T> 4415 struct tuple_element<I, tuple<T...>> { 4416 using type = __type_pack_element<I, T...>; 4417 }; 4418 4419 template <class...> class tuple {}; 4420 4421 template <std::size_t I, class... T> 4422 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 4423 } // namespace std 4424 4425 std::tuple<bool, int> &getTuple(); 4426 4427 void target(bool B) { 4428 auto &[BoundFoo, BoundBar] = getTuple(); 4429 bool Baz; 4430 // Include if-then-else to test interaction of `BindingDecl` with join. 4431 if (B) { 4432 Baz = BoundFoo; 4433 (void)BoundBar; 4434 // [[p1]] 4435 } else { 4436 Baz = BoundFoo; 4437 } 4438 (void)0; 4439 // [[p2]] 4440 } 4441 )"; 4442 runDataflow( 4443 Code, 4444 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4445 ASTContext &ASTCtx) { 4446 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 4447 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 4448 4449 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 4450 ASSERT_THAT(BoundFooDecl, NotNull()); 4451 4452 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 4453 ASSERT_THAT(BoundBarDecl, NotNull()); 4454 4455 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4456 ASSERT_THAT(BazDecl, NotNull()); 4457 4458 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl); 4459 ASSERT_THAT(BoundFooValue, NotNull()); 4460 EXPECT_TRUE(isa<BoolValue>(BoundFooValue)); 4461 4462 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl); 4463 ASSERT_THAT(BoundBarValue, NotNull()); 4464 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue)); 4465 4466 // Test that a `DeclRefExpr` to a `BindingDecl` (with reference type) 4467 // works as expected. We don't test aliasing properties of the 4468 // reference, because we don't model `std::get` and so have no way to 4469 // equate separate references into the tuple. 4470 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue); 4471 4472 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 4473 4474 // Test that `BoundFooDecl` retains the value we expect, after the join. 4475 BoundFooValue = Env2.getValue(*BoundFooDecl); 4476 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue); 4477 }); 4478 } 4479 4480 TEST(TransferTest, BinaryOperatorComma) { 4481 std::string Code = R"( 4482 void target(int Foo, int Bar) { 4483 int &Baz = (Foo, Bar); 4484 // [[p]] 4485 } 4486 )"; 4487 runDataflow( 4488 Code, 4489 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4490 ASTContext &ASTCtx) { 4491 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4492 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4493 4494 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4495 ASSERT_THAT(BarDecl, NotNull()); 4496 4497 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4498 ASSERT_THAT(BazDecl, NotNull()); 4499 4500 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 4501 ASSERT_THAT(BarLoc, NotNull()); 4502 4503 const StorageLocation *BazLoc = Env.getStorageLocation(*BazDecl); 4504 EXPECT_EQ(BazLoc, BarLoc); 4505 }); 4506 } 4507 4508 TEST(TransferTest, IfStmtBranchExtendsFlowCondition) { 4509 std::string Code = R"( 4510 void target(bool Foo) { 4511 if (Foo) { 4512 (void)0; 4513 // [[if_then]] 4514 } else { 4515 (void)0; 4516 // [[if_else]] 4517 } 4518 } 4519 )"; 4520 runDataflow( 4521 Code, 4522 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4523 ASTContext &ASTCtx) { 4524 ASSERT_THAT(Results.keys(), UnorderedElementsAre("if_then", "if_else")); 4525 const Environment &ThenEnv = 4526 getEnvironmentAtAnnotation(Results, "if_then"); 4527 const Environment &ElseEnv = 4528 getEnvironmentAtAnnotation(Results, "if_else"); 4529 4530 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4531 ASSERT_THAT(FooDecl, NotNull()); 4532 4533 auto &ThenFooVal= getFormula(*FooDecl, ThenEnv); 4534 EXPECT_TRUE(ThenEnv.flowConditionImplies(ThenFooVal)); 4535 4536 auto &ElseFooVal = getFormula(*FooDecl, ElseEnv); 4537 EXPECT_TRUE( 4538 ElseEnv.flowConditionImplies(ElseEnv.arena().makeNot(ElseFooVal))); 4539 }); 4540 } 4541 4542 TEST(TransferTest, WhileStmtBranchExtendsFlowCondition) { 4543 std::string Code = R"( 4544 void target(bool Foo) { 4545 while (Foo) { 4546 (void)0; 4547 // [[loop_body]] 4548 } 4549 (void)0; 4550 // [[after_loop]] 4551 } 4552 )"; 4553 runDataflow( 4554 Code, 4555 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4556 ASTContext &ASTCtx) { 4557 ASSERT_THAT(Results.keys(), 4558 UnorderedElementsAre("loop_body", "after_loop")); 4559 const Environment &LoopBodyEnv = 4560 getEnvironmentAtAnnotation(Results, "loop_body"); 4561 const Environment &AfterLoopEnv = 4562 getEnvironmentAtAnnotation(Results, "after_loop"); 4563 4564 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4565 ASSERT_THAT(FooDecl, NotNull()); 4566 4567 auto &LoopBodyFooVal = getFormula(*FooDecl, LoopBodyEnv); 4568 EXPECT_TRUE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal)); 4569 4570 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 4571 EXPECT_TRUE(AfterLoopEnv.flowConditionImplies( 4572 AfterLoopEnv.arena().makeNot(AfterLoopFooVal))); 4573 }); 4574 } 4575 4576 TEST(TransferTest, DoWhileStmtBranchExtendsFlowCondition) { 4577 std::string Code = R"( 4578 void target(bool Foo) { 4579 bool Bar = true; 4580 do { 4581 (void)0; 4582 // [[loop_body]] 4583 Bar = false; 4584 } while (Foo); 4585 (void)0; 4586 // [[after_loop]] 4587 } 4588 )"; 4589 runDataflow( 4590 Code, 4591 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4592 ASTContext &ASTCtx) { 4593 ASSERT_THAT(Results.keys(), 4594 UnorderedElementsAre("loop_body", "after_loop")); 4595 const Environment &LoopBodyEnv = 4596 getEnvironmentAtAnnotation(Results, "loop_body"); 4597 const Environment &AfterLoopEnv = 4598 getEnvironmentAtAnnotation(Results, "after_loop"); 4599 auto &A = AfterLoopEnv.arena(); 4600 4601 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4602 ASSERT_THAT(FooDecl, NotNull()); 4603 4604 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4605 ASSERT_THAT(BarDecl, NotNull()); 4606 4607 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 4608 auto &LoopBodyBarVal = getFormula(*BarDecl, LoopBodyEnv); 4609 EXPECT_TRUE(LoopBodyEnv.flowConditionImplies( 4610 A.makeOr(LoopBodyBarVal, LoopBodyFooVal))); 4611 4612 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 4613 auto &AfterLoopBarVal = getFormula(*BarDecl, AfterLoopEnv); 4614 EXPECT_TRUE( 4615 AfterLoopEnv.flowConditionImplies(A.makeNot(AfterLoopFooVal))); 4616 EXPECT_TRUE( 4617 AfterLoopEnv.flowConditionImplies(A.makeNot(AfterLoopBarVal))); 4618 }); 4619 } 4620 4621 TEST(TransferTest, ForStmtBranchExtendsFlowCondition) { 4622 std::string Code = R"( 4623 void target(bool Foo) { 4624 for (; Foo;) { 4625 (void)0; 4626 // [[loop_body]] 4627 } 4628 (void)0; 4629 // [[after_loop]] 4630 } 4631 )"; 4632 runDataflow( 4633 Code, 4634 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4635 ASTContext &ASTCtx) { 4636 ASSERT_THAT(Results.keys(), 4637 UnorderedElementsAre("loop_body", "after_loop")); 4638 const Environment &LoopBodyEnv = 4639 getEnvironmentAtAnnotation(Results, "loop_body"); 4640 const Environment &AfterLoopEnv = 4641 getEnvironmentAtAnnotation(Results, "after_loop"); 4642 4643 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4644 ASSERT_THAT(FooDecl, NotNull()); 4645 4646 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 4647 EXPECT_TRUE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal)); 4648 4649 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 4650 EXPECT_TRUE(AfterLoopEnv.flowConditionImplies( 4651 AfterLoopEnv.arena().makeNot(AfterLoopFooVal))); 4652 }); 4653 } 4654 4655 TEST(TransferTest, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition) { 4656 std::string Code = R"( 4657 void target(bool Foo) { 4658 for (;;) { 4659 (void)0; 4660 // [[loop_body]] 4661 } 4662 } 4663 )"; 4664 runDataflow( 4665 Code, 4666 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4667 ASTContext &ASTCtx) { 4668 ASSERT_THAT(Results.keys(), UnorderedElementsAre("loop_body")); 4669 const Environment &LoopBodyEnv = 4670 getEnvironmentAtAnnotation(Results, "loop_body"); 4671 4672 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4673 ASSERT_THAT(FooDecl, NotNull()); 4674 4675 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 4676 EXPECT_FALSE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal)); 4677 }); 4678 } 4679 4680 TEST(TransferTest, ContextSensitiveOptionDisabled) { 4681 std::string Code = R"( 4682 bool GiveBool(); 4683 void SetBool(bool &Var) { Var = true; } 4684 4685 void target() { 4686 bool Foo = GiveBool(); 4687 SetBool(Foo); 4688 // [[p]] 4689 } 4690 )"; 4691 runDataflow( 4692 Code, 4693 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4694 ASTContext &ASTCtx) { 4695 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4696 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4697 4698 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4699 ASSERT_THAT(FooDecl, NotNull()); 4700 4701 auto &FooVal = getFormula(*FooDecl, Env); 4702 EXPECT_FALSE(Env.flowConditionImplies(FooVal)); 4703 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(FooVal))); 4704 }, 4705 {BuiltinOptions{/*.ContextSensitiveOpts=*/std::nullopt}}); 4706 } 4707 4708 TEST(TransferTest, ContextSensitiveReturnReference) { 4709 std::string Code = R"( 4710 class S {}; 4711 S& target(bool b, S &s) { 4712 return s; 4713 // [[p]] 4714 } 4715 )"; 4716 runDataflow( 4717 Code, 4718 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4719 ASTContext &ASTCtx) { 4720 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4721 4722 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 4723 ASSERT_THAT(SDecl, NotNull()); 4724 4725 auto *SLoc = Env.getStorageLocation(*SDecl); 4726 ASSERT_THAT(SLoc, NotNull()); 4727 4728 ASSERT_THAT(Env.getReturnStorageLocation(), Eq(SLoc)); 4729 }, 4730 {BuiltinOptions{ContextSensitiveOptions{}}}); 4731 } 4732 4733 // This test is a regression test, based on a real crash. 4734 TEST(TransferTest, ContextSensitiveReturnReferenceWithConditionalOperator) { 4735 std::string Code = R"( 4736 class S {}; 4737 S& target(bool b, S &s) { 4738 return b ? s : s; 4739 // [[p]] 4740 } 4741 )"; 4742 runDataflow( 4743 Code, 4744 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4745 ASTContext &ASTCtx) { 4746 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4747 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4748 4749 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 4750 ASSERT_THAT(SDecl, NotNull()); 4751 4752 auto *SLoc = Env.getStorageLocation(*SDecl); 4753 ASSERT_THAT(SLoc, NotNull()); 4754 EXPECT_THAT(Env.getValue(*SLoc), NotNull()); 4755 4756 auto *Loc = Env.getReturnStorageLocation(); 4757 ASSERT_THAT(Loc, NotNull()); 4758 EXPECT_THAT(Env.getValue(*Loc), NotNull()); 4759 4760 // TODO: We would really like to make this stronger assertion, but that 4761 // doesn't work because we don't propagate values correctly through 4762 // the conditional operator yet. 4763 // ASSERT_THAT(Loc, Eq(SLoc)); 4764 }, 4765 {BuiltinOptions{ContextSensitiveOptions{}}}); 4766 } 4767 4768 TEST(TransferTest, ContextSensitiveReturnOneOfTwoReferences) { 4769 std::string Code = R"( 4770 class S {}; 4771 S &callee(bool b, S &s1_parm, S &s2_parm) { 4772 if (b) 4773 return s1_parm; 4774 else 4775 return s2_parm; 4776 } 4777 void target(bool b) { 4778 S s1; 4779 S s2; 4780 S &return_s1 = s1; 4781 S &return_s2 = s2; 4782 S &return_dont_know = callee(b, s1, s2); 4783 // [[p]] 4784 } 4785 )"; 4786 runDataflow( 4787 Code, 4788 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4789 ASTContext &ASTCtx) { 4790 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4791 4792 const ValueDecl *S1 = findValueDecl(ASTCtx, "s1"); 4793 ASSERT_THAT(S1, NotNull()); 4794 const ValueDecl *S2 = findValueDecl(ASTCtx, "s2"); 4795 ASSERT_THAT(S2, NotNull()); 4796 const ValueDecl *ReturnS1 = findValueDecl(ASTCtx, "return_s1"); 4797 ASSERT_THAT(ReturnS1, NotNull()); 4798 const ValueDecl *ReturnS2 = findValueDecl(ASTCtx, "return_s2"); 4799 ASSERT_THAT(ReturnS2, NotNull()); 4800 const ValueDecl *ReturnDontKnow = 4801 findValueDecl(ASTCtx, "return_dont_know"); 4802 ASSERT_THAT(ReturnDontKnow, NotNull()); 4803 4804 StorageLocation *S1Loc = Env.getStorageLocation(*S1); 4805 StorageLocation *S2Loc = Env.getStorageLocation(*S2); 4806 4807 EXPECT_THAT(Env.getStorageLocation(*ReturnS1), Eq(S1Loc)); 4808 EXPECT_THAT(Env.getStorageLocation(*ReturnS2), Eq(S2Loc)); 4809 4810 // In the case where we don't have a consistent storage location for 4811 // the return value, the framework creates a new storage location, which 4812 // should be different from the storage locations of `s1` and `s2`. 4813 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S1Loc)); 4814 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S2Loc)); 4815 }, 4816 {BuiltinOptions{ContextSensitiveOptions{}}}); 4817 } 4818 4819 TEST(TransferTest, ContextSensitiveDepthZero) { 4820 std::string Code = R"( 4821 bool GiveBool(); 4822 void SetBool(bool &Var) { Var = true; } 4823 4824 void target() { 4825 bool Foo = GiveBool(); 4826 SetBool(Foo); 4827 // [[p]] 4828 } 4829 )"; 4830 runDataflow( 4831 Code, 4832 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4833 ASTContext &ASTCtx) { 4834 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4835 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4836 4837 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4838 ASSERT_THAT(FooDecl, NotNull()); 4839 4840 auto &FooVal = getFormula(*FooDecl, Env); 4841 EXPECT_FALSE(Env.flowConditionImplies(FooVal)); 4842 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(FooVal))); 4843 }, 4844 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/0}}}); 4845 } 4846 4847 TEST(TransferTest, ContextSensitiveSetTrue) { 4848 std::string Code = R"( 4849 bool GiveBool(); 4850 void SetBool(bool &Var) { Var = true; } 4851 4852 void target() { 4853 bool Foo = GiveBool(); 4854 SetBool(Foo); 4855 // [[p]] 4856 } 4857 )"; 4858 runDataflow( 4859 Code, 4860 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4861 ASTContext &ASTCtx) { 4862 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4863 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4864 4865 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4866 ASSERT_THAT(FooDecl, NotNull()); 4867 4868 auto &FooVal = getFormula(*FooDecl, Env); 4869 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4870 }, 4871 {BuiltinOptions{ContextSensitiveOptions{}}}); 4872 } 4873 4874 TEST(TransferTest, ContextSensitiveSetFalse) { 4875 std::string Code = R"( 4876 bool GiveBool(); 4877 void SetBool(bool &Var) { Var = false; } 4878 4879 void target() { 4880 bool Foo = GiveBool(); 4881 SetBool(Foo); 4882 // [[p]] 4883 } 4884 )"; 4885 runDataflow( 4886 Code, 4887 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4888 ASTContext &ASTCtx) { 4889 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4890 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4891 4892 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4893 ASSERT_THAT(FooDecl, NotNull()); 4894 4895 auto &FooVal = getFormula(*FooDecl, Env); 4896 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(FooVal))); 4897 }, 4898 {BuiltinOptions{ContextSensitiveOptions{}}}); 4899 } 4900 4901 TEST(TransferTest, ContextSensitiveSetBothTrueAndFalse) { 4902 std::string Code = R"( 4903 bool GiveBool(); 4904 void SetBool(bool &Var, bool Val) { Var = Val; } 4905 4906 void target() { 4907 bool Foo = GiveBool(); 4908 bool Bar = GiveBool(); 4909 SetBool(Foo, true); 4910 SetBool(Bar, false); 4911 // [[p]] 4912 } 4913 )"; 4914 runDataflow( 4915 Code, 4916 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4917 ASTContext &ASTCtx) { 4918 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4919 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4920 auto &A = Env.arena(); 4921 4922 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4923 ASSERT_THAT(FooDecl, NotNull()); 4924 4925 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4926 ASSERT_THAT(BarDecl, NotNull()); 4927 4928 auto &FooVal = getFormula(*FooDecl, Env); 4929 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4930 EXPECT_FALSE(Env.flowConditionImplies(A.makeNot(FooVal))); 4931 4932 auto &BarVal = getFormula(*BarDecl, Env); 4933 EXPECT_FALSE(Env.flowConditionImplies(BarVal)); 4934 EXPECT_TRUE(Env.flowConditionImplies(A.makeNot(BarVal))); 4935 }, 4936 {BuiltinOptions{ContextSensitiveOptions{}}}); 4937 } 4938 4939 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthOne) { 4940 std::string Code = R"( 4941 bool GiveBool(); 4942 void SetBool1(bool &Var) { Var = true; } 4943 void SetBool2(bool &Var) { SetBool1(Var); } 4944 4945 void target() { 4946 bool Foo = GiveBool(); 4947 SetBool2(Foo); 4948 // [[p]] 4949 } 4950 )"; 4951 runDataflow( 4952 Code, 4953 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4954 ASTContext &ASTCtx) { 4955 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4956 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4957 4958 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4959 ASSERT_THAT(FooDecl, NotNull()); 4960 4961 auto &FooVal = getFormula(*FooDecl, Env); 4962 EXPECT_FALSE(Env.flowConditionImplies(FooVal)); 4963 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(FooVal))); 4964 }, 4965 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/1}}}); 4966 } 4967 4968 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthTwo) { 4969 std::string Code = R"( 4970 bool GiveBool(); 4971 void SetBool1(bool &Var) { Var = true; } 4972 void SetBool2(bool &Var) { SetBool1(Var); } 4973 4974 void target() { 4975 bool Foo = GiveBool(); 4976 SetBool2(Foo); 4977 // [[p]] 4978 } 4979 )"; 4980 runDataflow( 4981 Code, 4982 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4983 ASTContext &ASTCtx) { 4984 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4985 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4986 4987 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4988 ASSERT_THAT(FooDecl, NotNull()); 4989 4990 auto &FooVal = getFormula(*FooDecl, Env); 4991 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4992 }, 4993 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}}); 4994 } 4995 4996 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthTwo) { 4997 std::string Code = R"( 4998 bool GiveBool(); 4999 void SetBool1(bool &Var) { Var = true; } 5000 void SetBool2(bool &Var) { SetBool1(Var); } 5001 void SetBool3(bool &Var) { SetBool2(Var); } 5002 5003 void target() { 5004 bool Foo = GiveBool(); 5005 SetBool3(Foo); 5006 // [[p]] 5007 } 5008 )"; 5009 runDataflow( 5010 Code, 5011 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5012 ASTContext &ASTCtx) { 5013 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5014 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5015 5016 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5017 ASSERT_THAT(FooDecl, NotNull()); 5018 5019 auto &FooVal = getFormula(*FooDecl, Env); 5020 EXPECT_FALSE(Env.flowConditionImplies(FooVal)); 5021 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(FooVal))); 5022 }, 5023 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}}); 5024 } 5025 5026 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthThree) { 5027 std::string Code = R"( 5028 bool GiveBool(); 5029 void SetBool1(bool &Var) { Var = true; } 5030 void SetBool2(bool &Var) { SetBool1(Var); } 5031 void SetBool3(bool &Var) { SetBool2(Var); } 5032 5033 void target() { 5034 bool Foo = GiveBool(); 5035 SetBool3(Foo); 5036 // [[p]] 5037 } 5038 )"; 5039 runDataflow( 5040 Code, 5041 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5042 ASTContext &ASTCtx) { 5043 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5044 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5045 5046 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5047 ASSERT_THAT(FooDecl, NotNull()); 5048 5049 auto &FooVal = getFormula(*FooDecl, Env); 5050 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5051 }, 5052 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/3}}}); 5053 } 5054 5055 TEST(TransferTest, ContextSensitiveMutualRecursion) { 5056 std::string Code = R"( 5057 bool Pong(bool X, bool Y); 5058 5059 bool Ping(bool X, bool Y) { 5060 if (X) { 5061 return Y; 5062 } else { 5063 return Pong(!X, Y); 5064 } 5065 } 5066 5067 bool Pong(bool X, bool Y) { 5068 if (Y) { 5069 return X; 5070 } else { 5071 return Ping(X, !Y); 5072 } 5073 } 5074 5075 void target() { 5076 bool Foo = Ping(false, false); 5077 // [[p]] 5078 } 5079 )"; 5080 runDataflow( 5081 Code, 5082 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5083 ASTContext &ASTCtx) { 5084 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5085 // The analysis doesn't crash... 5086 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5087 5088 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5089 ASSERT_THAT(FooDecl, NotNull()); 5090 5091 auto &FooVal = getFormula(*FooDecl, Env); 5092 // ... but it also can't prove anything here. 5093 EXPECT_FALSE(Env.flowConditionImplies(FooVal)); 5094 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(FooVal))); 5095 }, 5096 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/4}}}); 5097 } 5098 5099 TEST(TransferTest, ContextSensitiveSetMultipleLines) { 5100 std::string Code = R"( 5101 void SetBools(bool &Var1, bool &Var2) { 5102 Var1 = true; 5103 Var2 = false; 5104 } 5105 5106 void target() { 5107 bool Foo = false; 5108 bool Bar = true; 5109 SetBools(Foo, Bar); 5110 // [[p]] 5111 } 5112 )"; 5113 runDataflow( 5114 Code, 5115 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5116 ASTContext &ASTCtx) { 5117 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5118 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5119 5120 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5121 ASSERT_THAT(FooDecl, NotNull()); 5122 5123 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5124 ASSERT_THAT(BarDecl, NotNull()); 5125 5126 auto &FooVal = getFormula(*FooDecl, Env); 5127 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5128 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(FooVal))); 5129 5130 auto &BarVal = getFormula(*BarDecl, Env); 5131 EXPECT_FALSE(Env.flowConditionImplies(BarVal)); 5132 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(BarVal))); 5133 }, 5134 {BuiltinOptions{ContextSensitiveOptions{}}}); 5135 } 5136 5137 TEST(TransferTest, ContextSensitiveSetMultipleBlocks) { 5138 std::string Code = R"( 5139 void IfCond(bool Cond, bool &Then, bool &Else) { 5140 if (Cond) { 5141 Then = true; 5142 } else { 5143 Else = true; 5144 } 5145 } 5146 5147 void target() { 5148 bool Foo = false; 5149 bool Bar = false; 5150 bool Baz = false; 5151 IfCond(Foo, Bar, Baz); 5152 // [[p]] 5153 } 5154 )"; 5155 runDataflow( 5156 Code, 5157 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5158 ASTContext &ASTCtx) { 5159 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5160 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5161 5162 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5163 ASSERT_THAT(BarDecl, NotNull()); 5164 5165 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5166 ASSERT_THAT(BazDecl, NotNull()); 5167 5168 auto &BarVal = getFormula(*BarDecl, Env); 5169 EXPECT_FALSE(Env.flowConditionImplies(BarVal)); 5170 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(BarVal))); 5171 5172 auto &BazVal = getFormula(*BazDecl, Env); 5173 EXPECT_TRUE(Env.flowConditionImplies(BazVal)); 5174 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(BazVal))); 5175 }, 5176 {BuiltinOptions{ContextSensitiveOptions{}}}); 5177 } 5178 5179 TEST(TransferTest, ContextSensitiveReturnVoid) { 5180 std::string Code = R"( 5181 void Noop() { return; } 5182 5183 void target() { 5184 Noop(); 5185 // [[p]] 5186 } 5187 )"; 5188 runDataflow( 5189 Code, 5190 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5191 ASTContext &ASTCtx) { 5192 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5193 // This just tests that the analysis doesn't crash. 5194 }, 5195 {BuiltinOptions{ContextSensitiveOptions{}}}); 5196 } 5197 5198 TEST(TransferTest, ContextSensitiveReturnTrue) { 5199 std::string Code = R"( 5200 bool GiveBool() { return true; } 5201 5202 void target() { 5203 bool Foo = GiveBool(); 5204 // [[p]] 5205 } 5206 )"; 5207 runDataflow( 5208 Code, 5209 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5210 ASTContext &ASTCtx) { 5211 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5212 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5213 5214 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5215 ASSERT_THAT(FooDecl, NotNull()); 5216 5217 auto &FooVal = getFormula(*FooDecl, Env); 5218 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5219 }, 5220 {BuiltinOptions{ContextSensitiveOptions{}}}); 5221 } 5222 5223 TEST(TransferTest, ContextSensitiveReturnFalse) { 5224 std::string Code = R"( 5225 bool GiveBool() { return false; } 5226 5227 void target() { 5228 bool Foo = GiveBool(); 5229 // [[p]] 5230 } 5231 )"; 5232 runDataflow( 5233 Code, 5234 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5235 ASTContext &ASTCtx) { 5236 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5237 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5238 5239 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5240 ASSERT_THAT(FooDecl, NotNull()); 5241 5242 auto &FooVal = getFormula(*FooDecl, Env); 5243 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(FooVal))); 5244 }, 5245 {BuiltinOptions{ContextSensitiveOptions{}}}); 5246 } 5247 5248 TEST(TransferTest, ContextSensitiveReturnArg) { 5249 std::string Code = R"( 5250 bool GiveBool(); 5251 bool GiveBack(bool Arg) { return Arg; } 5252 5253 void target() { 5254 bool Foo = GiveBool(); 5255 bool Bar = GiveBack(Foo); 5256 bool Baz = Foo == Bar; 5257 // [[p]] 5258 } 5259 )"; 5260 runDataflow( 5261 Code, 5262 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5263 ASTContext &ASTCtx) { 5264 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5265 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5266 5267 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5268 ASSERT_THAT(BazDecl, NotNull()); 5269 5270 auto &BazVal = getFormula(*BazDecl, Env); 5271 EXPECT_TRUE(Env.flowConditionImplies(BazVal)); 5272 }, 5273 {BuiltinOptions{ContextSensitiveOptions{}}}); 5274 } 5275 5276 TEST(TransferTest, ContextSensitiveReturnInt) { 5277 std::string Code = R"( 5278 int identity(int x) { return x; } 5279 5280 void target() { 5281 int y = identity(42); 5282 // [[p]] 5283 } 5284 )"; 5285 runDataflow( 5286 Code, 5287 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5288 ASTContext &ASTCtx) { 5289 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5290 // This just tests that the analysis doesn't crash. 5291 }, 5292 {BuiltinOptions{ContextSensitiveOptions{}}}); 5293 } 5294 5295 TEST(TransferTest, ContextSensitiveMethodLiteral) { 5296 std::string Code = R"( 5297 class MyClass { 5298 public: 5299 bool giveBool() { return true; } 5300 }; 5301 5302 void target() { 5303 MyClass MyObj; 5304 bool Foo = MyObj.giveBool(); 5305 // [[p]] 5306 } 5307 )"; 5308 runDataflow( 5309 Code, 5310 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5311 ASTContext &ASTCtx) { 5312 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5313 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5314 5315 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5316 ASSERT_THAT(FooDecl, NotNull()); 5317 5318 auto &FooVal = getFormula(*FooDecl, Env); 5319 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5320 }, 5321 {BuiltinOptions{ContextSensitiveOptions{}}}); 5322 } 5323 5324 TEST(TransferTest, ContextSensitiveMethodGetter) { 5325 std::string Code = R"( 5326 class MyClass { 5327 public: 5328 bool getField() { return Field; } 5329 5330 bool Field; 5331 }; 5332 5333 void target() { 5334 MyClass MyObj; 5335 MyObj.Field = true; 5336 bool Foo = MyObj.getField(); 5337 // [[p]] 5338 } 5339 )"; 5340 runDataflow( 5341 Code, 5342 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5343 ASTContext &ASTCtx) { 5344 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5345 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5346 5347 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5348 ASSERT_THAT(FooDecl, NotNull()); 5349 5350 auto &FooVal = getFormula(*FooDecl, Env); 5351 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5352 }, 5353 {BuiltinOptions{ContextSensitiveOptions{}}}); 5354 } 5355 5356 TEST(TransferTest, ContextSensitiveMethodSetter) { 5357 std::string Code = R"( 5358 class MyClass { 5359 public: 5360 void setField(bool Val) { Field = Val; } 5361 5362 bool Field; 5363 }; 5364 5365 void target() { 5366 MyClass MyObj; 5367 MyObj.setField(true); 5368 bool Foo = MyObj.Field; 5369 // [[p]] 5370 } 5371 )"; 5372 runDataflow( 5373 Code, 5374 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5375 ASTContext &ASTCtx) { 5376 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5377 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5378 5379 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5380 ASSERT_THAT(FooDecl, NotNull()); 5381 5382 auto &FooVal = getFormula(*FooDecl, Env); 5383 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5384 }, 5385 {BuiltinOptions{ContextSensitiveOptions{}}}); 5386 } 5387 5388 TEST(TransferTest, ContextSensitiveMethodGetterAndSetter) { 5389 std::string Code = R"( 5390 class MyClass { 5391 public: 5392 bool getField() { return Field; } 5393 void setField(bool Val) { Field = Val; } 5394 5395 private: 5396 bool Field; 5397 }; 5398 5399 void target() { 5400 MyClass MyObj; 5401 MyObj.setField(true); 5402 bool Foo = MyObj.getField(); 5403 // [[p]] 5404 } 5405 )"; 5406 runDataflow( 5407 Code, 5408 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5409 ASTContext &ASTCtx) { 5410 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5411 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5412 5413 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5414 ASSERT_THAT(FooDecl, NotNull()); 5415 5416 auto &FooVal = getFormula(*FooDecl, Env); 5417 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5418 }, 5419 {BuiltinOptions{ContextSensitiveOptions{}}}); 5420 } 5421 5422 5423 TEST(TransferTest, ContextSensitiveMethodTwoLayersVoid) { 5424 std::string Code = R"( 5425 class MyClass { 5426 public: 5427 void Inner() { MyField = true; } 5428 void Outer() { Inner(); } 5429 5430 bool MyField; 5431 }; 5432 5433 void target() { 5434 MyClass MyObj; 5435 MyObj.Outer(); 5436 bool Foo = MyObj.MyField; 5437 // [[p]] 5438 } 5439 )"; 5440 runDataflow( 5441 Code, 5442 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5443 ASTContext &ASTCtx) { 5444 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5445 ; 5446 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5447 5448 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5449 ASSERT_THAT(FooDecl, NotNull()); 5450 5451 auto &FooVal = getFormula(*FooDecl, Env); 5452 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5453 }, 5454 {BuiltinOptions{ContextSensitiveOptions{}}}); 5455 } 5456 5457 TEST(TransferTest, ContextSensitiveMethodTwoLayersReturn) { 5458 std::string Code = R"( 5459 class MyClass { 5460 public: 5461 bool Inner() { return MyField; } 5462 bool Outer() { return Inner(); } 5463 5464 bool MyField; 5465 }; 5466 5467 void target() { 5468 MyClass MyObj; 5469 MyObj.MyField = true; 5470 bool Foo = MyObj.Outer(); 5471 // [[p]] 5472 } 5473 )"; 5474 runDataflow( 5475 Code, 5476 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5477 ASTContext &ASTCtx) { 5478 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5479 ; 5480 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5481 5482 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5483 ASSERT_THAT(FooDecl, NotNull()); 5484 5485 auto &FooVal = getFormula(*FooDecl, Env); 5486 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5487 }, 5488 {BuiltinOptions{ContextSensitiveOptions{}}}); 5489 } 5490 5491 TEST(TransferTest, ContextSensitiveConstructorBody) { 5492 std::string Code = R"( 5493 class MyClass { 5494 public: 5495 MyClass() { MyField = true; } 5496 5497 bool MyField; 5498 }; 5499 5500 void target() { 5501 MyClass MyObj; 5502 bool Foo = MyObj.MyField; 5503 // [[p]] 5504 } 5505 )"; 5506 runDataflow( 5507 Code, 5508 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5509 ASTContext &ASTCtx) { 5510 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5511 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5512 5513 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5514 ASSERT_THAT(FooDecl, NotNull()); 5515 5516 auto &FooVal = getFormula(*FooDecl, Env); 5517 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5518 }, 5519 {BuiltinOptions{ContextSensitiveOptions{}}}); 5520 } 5521 5522 TEST(TransferTest, ContextSensitiveConstructorInitializer) { 5523 std::string Code = R"( 5524 class MyClass { 5525 public: 5526 MyClass() : MyField(true) {} 5527 5528 bool MyField; 5529 }; 5530 5531 void target() { 5532 MyClass MyObj; 5533 bool Foo = MyObj.MyField; 5534 // [[p]] 5535 } 5536 )"; 5537 runDataflow( 5538 Code, 5539 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5540 ASTContext &ASTCtx) { 5541 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5542 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5543 5544 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5545 ASSERT_THAT(FooDecl, NotNull()); 5546 5547 auto &FooVal = getFormula(*FooDecl, Env); 5548 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5549 }, 5550 {BuiltinOptions{ContextSensitiveOptions{}}}); 5551 } 5552 5553 TEST(TransferTest, ContextSensitiveConstructorDefault) { 5554 std::string Code = R"( 5555 class MyClass { 5556 public: 5557 MyClass() = default; 5558 5559 bool MyField = true; 5560 }; 5561 5562 void target() { 5563 MyClass MyObj; 5564 bool Foo = MyObj.MyField; 5565 // [[p]] 5566 } 5567 )"; 5568 runDataflow( 5569 Code, 5570 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5571 ASTContext &ASTCtx) { 5572 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5573 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5574 5575 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5576 ASSERT_THAT(FooDecl, NotNull()); 5577 5578 auto &FooVal = getFormula(*FooDecl, Env); 5579 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5580 }, 5581 {BuiltinOptions{ContextSensitiveOptions{}}}); 5582 } 5583 5584 TEST(TransferTest, ContextSensitiveSelfReferentialClass) { 5585 // Test that the `this` pointer seen in the constructor has the same value 5586 // as the address of the variable the object is constructed into. 5587 std::string Code = R"( 5588 class MyClass { 5589 public: 5590 MyClass() : Self(this) {} 5591 MyClass *Self; 5592 }; 5593 5594 void target() { 5595 MyClass MyObj; 5596 MyClass *SelfPtr = MyObj.Self; 5597 // [[p]] 5598 } 5599 )"; 5600 runDataflow( 5601 Code, 5602 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5603 ASTContext &ASTCtx) { 5604 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5605 5606 const ValueDecl *MyObjDecl = findValueDecl(ASTCtx, "MyObj"); 5607 ASSERT_THAT(MyObjDecl, NotNull()); 5608 5609 const ValueDecl *SelfDecl = findValueDecl(ASTCtx, "SelfPtr"); 5610 ASSERT_THAT(SelfDecl, NotNull()); 5611 5612 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5613 auto &SelfVal = *cast<PointerValue>(Env.getValue(*SelfDecl)); 5614 EXPECT_EQ(Env.getStorageLocation(*MyObjDecl), &SelfVal.getPointeeLoc()); 5615 }, 5616 {BuiltinOptions{ContextSensitiveOptions{}}}); 5617 } 5618 5619 TEST(TransferTest, UnnamedBitfieldInitializer) { 5620 std::string Code = R"( 5621 struct B {}; 5622 struct A { 5623 unsigned a; 5624 unsigned : 4; 5625 unsigned c; 5626 B b; 5627 }; 5628 void target() { 5629 A a = {}; 5630 A test = a; 5631 (void)test.c; 5632 } 5633 )"; 5634 runDataflow( 5635 Code, 5636 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5637 ASTContext &ASTCtx) { 5638 // This doesn't need a body because this test was crashing the framework 5639 // before handling correctly Unnamed bitfields in `InitListExpr`. 5640 }); 5641 } 5642 5643 // Repro for a crash that used to occur with chained short-circuiting logical 5644 // operators. 5645 TEST(TransferTest, ChainedLogicalOps) { 5646 std::string Code = R"( 5647 bool target() { 5648 bool b = true || false || false || false; 5649 // [[p]] 5650 return b; 5651 } 5652 )"; 5653 runDataflow( 5654 Code, 5655 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5656 ASTContext &ASTCtx) { 5657 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5658 auto &B = getValueForDecl<BoolValue>(ASTCtx, Env, "b").formula(); 5659 EXPECT_TRUE(Env.flowConditionImplies(B)); 5660 }); 5661 } 5662 5663 // Repro for a crash that used to occur when we call a `noreturn` function 5664 // within one of the operands of a `&&` or `||` operator. 5665 TEST(TransferTest, NoReturnFunctionInsideShortCircuitedBooleanOp) { 5666 std::string Code = R"( 5667 __attribute__((noreturn)) int doesnt_return(); 5668 bool some_condition(); 5669 void target(bool b1, bool b2) { 5670 // Neither of these should crash. In addition, if we don't terminate the 5671 // program, we know that the operators need to trigger the short-circuit 5672 // logic, so `NoreturnOnRhsOfAnd` will be false and `NoreturnOnRhsOfOr` 5673 // will be true. 5674 bool NoreturnOnRhsOfAnd = b1 && doesnt_return() > 0; 5675 bool NoreturnOnRhsOfOr = b2 || doesnt_return() > 0; 5676 5677 // Calling a `noreturn` function on the LHS of an `&&` or `||` makes the 5678 // entire expression unreachable. So we know that in both of the following 5679 // cases, if `target()` terminates, the `else` branch was taken. 5680 bool NoreturnOnLhsMakesAndUnreachable = false; 5681 if (some_condition()) 5682 doesnt_return() > 0 && some_condition(); 5683 else 5684 NoreturnOnLhsMakesAndUnreachable = true; 5685 5686 bool NoreturnOnLhsMakesOrUnreachable = false; 5687 if (some_condition()) 5688 doesnt_return() > 0 || some_condition(); 5689 else 5690 NoreturnOnLhsMakesOrUnreachable = true; 5691 5692 // [[p]] 5693 } 5694 )"; 5695 runDataflow( 5696 Code, 5697 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5698 ASTContext &ASTCtx) { 5699 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5700 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5701 auto &A = Env.arena(); 5702 5703 // Check that [[p]] is reachable with a non-false flow condition. 5704 EXPECT_FALSE(Env.flowConditionImplies(A.makeLiteral(false))); 5705 5706 auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, "b1").formula(); 5707 EXPECT_TRUE(Env.flowConditionImplies(A.makeNot(B1))); 5708 5709 auto &NoreturnOnRhsOfAnd = 5710 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfAnd").formula(); 5711 EXPECT_TRUE(Env.flowConditionImplies(A.makeNot(NoreturnOnRhsOfAnd))); 5712 5713 auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, "b2").formula(); 5714 EXPECT_TRUE(Env.flowConditionImplies(B2)); 5715 5716 auto &NoreturnOnRhsOfOr = 5717 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfOr") 5718 .formula(); 5719 EXPECT_TRUE(Env.flowConditionImplies(NoreturnOnRhsOfOr)); 5720 5721 auto &NoreturnOnLhsMakesAndUnreachable = getValueForDecl<BoolValue>( 5722 ASTCtx, Env, "NoreturnOnLhsMakesAndUnreachable").formula(); 5723 EXPECT_TRUE(Env.flowConditionImplies(NoreturnOnLhsMakesAndUnreachable)); 5724 5725 auto &NoreturnOnLhsMakesOrUnreachable = getValueForDecl<BoolValue>( 5726 ASTCtx, Env, "NoreturnOnLhsMakesOrUnreachable").formula(); 5727 EXPECT_TRUE(Env.flowConditionImplies(NoreturnOnLhsMakesOrUnreachable)); 5728 }); 5729 } 5730 5731 TEST(TransferTest, NewExpressions) { 5732 std::string Code = R"( 5733 void target() { 5734 int *p = new int(42); 5735 // [[after_new]] 5736 } 5737 )"; 5738 runDataflow( 5739 Code, 5740 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5741 ASTContext &ASTCtx) { 5742 const Environment &Env = 5743 getEnvironmentAtAnnotation(Results, "after_new"); 5744 5745 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p"); 5746 5747 EXPECT_THAT(Env.getValue(P.getPointeeLoc()), NotNull()); 5748 }); 5749 } 5750 5751 TEST(TransferTest, NewExpressions_Structs) { 5752 std::string Code = R"( 5753 struct Inner { 5754 int InnerField; 5755 }; 5756 5757 struct Outer { 5758 Inner OuterField; 5759 }; 5760 5761 void target() { 5762 Outer *p = new Outer; 5763 // Access the fields to make sure the analysis actually generates children 5764 // for them in the `RecordStorageLocation` and `RecordValue`. 5765 p->OuterField.InnerField; 5766 // [[after_new]] 5767 } 5768 )"; 5769 runDataflow( 5770 Code, 5771 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5772 ASTContext &ASTCtx) { 5773 const Environment &Env = 5774 getEnvironmentAtAnnotation(Results, "after_new"); 5775 5776 const ValueDecl *OuterField = findValueDecl(ASTCtx, "OuterField"); 5777 const ValueDecl *InnerField = findValueDecl(ASTCtx, "InnerField"); 5778 5779 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p"); 5780 5781 auto &OuterLoc = cast<RecordStorageLocation>(P.getPointeeLoc()); 5782 auto &OuterFieldLoc = 5783 *cast<RecordStorageLocation>(OuterLoc.getChild(*OuterField)); 5784 auto &InnerFieldLoc = *OuterFieldLoc.getChild(*InnerField); 5785 5786 // Values for the struct and all fields exist after the new. 5787 EXPECT_THAT(Env.getValue(OuterLoc), NotNull()); 5788 EXPECT_THAT(Env.getValue(OuterFieldLoc), NotNull()); 5789 EXPECT_THAT(Env.getValue(InnerFieldLoc), NotNull()); 5790 }); 5791 } 5792 5793 TEST(TransferTest, FunctionToPointerDecayHasValue) { 5794 std::string Code = R"( 5795 struct A { static void static_member_func(); }; 5796 void target() { 5797 // To check that we're treating function-to-pointer decay correctly, 5798 // create two pointers, then verify they refer to the same storage 5799 // location. 5800 // We need to do the test this way because even if an initializer (in this 5801 // case, the function-to-pointer decay) does not create a value, we still 5802 // create a value for the variable. 5803 void (*non_member_p1)() = target; 5804 void (*non_member_p2)() = target; 5805 5806 // Do the same thing but for a static member function. 5807 void (*member_p1)() = A::static_member_func; 5808 void (*member_p2)() = A::static_member_func; 5809 // [[p]] 5810 } 5811 )"; 5812 runDataflow( 5813 Code, 5814 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5815 ASTContext &ASTCtx) { 5816 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5817 5818 auto &NonMemberP1 = 5819 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p1"); 5820 auto &NonMemberP2 = 5821 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p2"); 5822 EXPECT_EQ(&NonMemberP1.getPointeeLoc(), &NonMemberP2.getPointeeLoc()); 5823 5824 auto &MemberP1 = 5825 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p1"); 5826 auto &MemberP2 = 5827 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p2"); 5828 EXPECT_EQ(&MemberP1.getPointeeLoc(), &MemberP2.getPointeeLoc()); 5829 }); 5830 } 5831 5832 // Check that a builtin function is not associated with a value. (It's only 5833 // possible to call builtin functions directly, not take their address.) 5834 TEST(TransferTest, BuiltinFunctionModeled) { 5835 std::string Code = R"( 5836 void target() { 5837 __builtin_expect(0, 0); 5838 // [[p]] 5839 } 5840 )"; 5841 runDataflow( 5842 Code, 5843 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5844 ASTContext &ASTCtx) { 5845 using ast_matchers::selectFirst; 5846 using ast_matchers::match; 5847 using ast_matchers::traverse; 5848 using ast_matchers::implicitCastExpr; 5849 using ast_matchers::hasCastKind; 5850 5851 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5852 5853 auto *ImplicitCast = selectFirst<ImplicitCastExpr>( 5854 "implicit_cast", 5855 match(traverse(TK_AsIs, 5856 implicitCastExpr(hasCastKind(CK_BuiltinFnToFnPtr)) 5857 .bind("implicit_cast")), 5858 ASTCtx)); 5859 5860 ASSERT_THAT(ImplicitCast, NotNull()); 5861 EXPECT_THAT(Env.getValue(*ImplicitCast), IsNull()); 5862 }); 5863 } 5864 5865 // Check that a callee of a member operator call is modeled as a `PointerValue`. 5866 // Member operator calls are unusual in that their callee is a pointer that 5867 // stems from a `FunctionToPointerDecay`. In calls to non-operator non-static 5868 // member functions, the callee is a `MemberExpr` (which does not have pointer 5869 // type). 5870 // We want to make sure that we produce a pointer value for the callee in this 5871 // specific scenario and that its storage location is durable (for convergence). 5872 TEST(TransferTest, MemberOperatorCallModelsPointerForCallee) { 5873 std::string Code = R"( 5874 struct S { 5875 bool operator!=(S s); 5876 }; 5877 void target() { 5878 S s; 5879 (void)(s != s); 5880 (void)(s != s); 5881 // [[p]] 5882 } 5883 )"; 5884 runDataflow( 5885 Code, 5886 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5887 ASTContext &ASTCtx) { 5888 using ast_matchers::selectFirst; 5889 using ast_matchers::match; 5890 using ast_matchers::traverse; 5891 using ast_matchers::cxxOperatorCallExpr; 5892 5893 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5894 5895 auto Matches = match( 5896 traverse(TK_AsIs, cxxOperatorCallExpr().bind("call")), ASTCtx); 5897 5898 ASSERT_EQ(Matches.size(), 2UL); 5899 5900 auto *Call1 = Matches[0].getNodeAs<CXXOperatorCallExpr>("call"); 5901 auto *Call2 = Matches[1].getNodeAs<CXXOperatorCallExpr>("call"); 5902 5903 ASSERT_THAT(Call1, NotNull()); 5904 ASSERT_THAT(Call2, NotNull()); 5905 5906 EXPECT_EQ(cast<ImplicitCastExpr>(Call1->getCallee())->getCastKind(), 5907 CK_FunctionToPointerDecay); 5908 EXPECT_EQ(cast<ImplicitCastExpr>(Call2->getCallee())->getCastKind(), 5909 CK_FunctionToPointerDecay); 5910 5911 auto *Ptr1 = cast<PointerValue>(Env.getValue(*Call1->getCallee())); 5912 auto *Ptr2 = cast<PointerValue>(Env.getValue(*Call2->getCallee())); 5913 5914 ASSERT_EQ(&Ptr1->getPointeeLoc(), &Ptr2->getPointeeLoc()); 5915 }); 5916 } 5917 5918 // Check that fields of anonymous records are modeled. 5919 TEST(TransferTest, AnonymousStruct) { 5920 std::string Code = R"( 5921 struct S { 5922 struct { 5923 bool b; 5924 }; 5925 }; 5926 void target() { 5927 S s; 5928 s.b = true; 5929 // [[p]] 5930 } 5931 )"; 5932 runDataflow( 5933 Code, 5934 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5935 ASTContext &ASTCtx) { 5936 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5937 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 5938 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b"); 5939 const IndirectFieldDecl *IndirectField = 5940 findIndirectFieldDecl(ASTCtx, "b"); 5941 5942 auto *S = cast<RecordStorageLocation>(Env.getStorageLocation(*SDecl)); 5943 auto &AnonStruct = *cast<RecordStorageLocation>( 5944 S->getChild(*cast<ValueDecl>(IndirectField->chain().front()))); 5945 5946 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env)); 5947 ASSERT_TRUE(Env.flowConditionImplies(B->formula())); 5948 }); 5949 } 5950 5951 TEST(TransferTest, AnonymousStructWithInitializer) { 5952 std::string Code = R"( 5953 struct target { 5954 target() { 5955 (void)0; 5956 // [[p]] 5957 } 5958 struct { 5959 bool b = true; 5960 }; 5961 }; 5962 )"; 5963 runDataflow( 5964 Code, 5965 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5966 ASTContext &ASTCtx) { 5967 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5968 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b"); 5969 const IndirectFieldDecl *IndirectField = 5970 findIndirectFieldDecl(ASTCtx, "b"); 5971 5972 auto *ThisLoc = 5973 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation()); 5974 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild( 5975 *cast<ValueDecl>(IndirectField->chain().front()))); 5976 5977 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env)); 5978 ASSERT_TRUE(Env.flowConditionImplies(B->formula())); 5979 }); 5980 } 5981 5982 TEST(TransferTest, AnonymousStructWithReferenceField) { 5983 std::string Code = R"( 5984 int global_i = 0; 5985 struct target { 5986 target() { 5987 (void)0; 5988 // [[p]] 5989 } 5990 struct { 5991 int &i = global_i; 5992 }; 5993 }; 5994 )"; 5995 runDataflow( 5996 Code, 5997 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5998 ASTContext &ASTCtx) { 5999 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6000 const ValueDecl *GlobalIDecl = findValueDecl(ASTCtx, "global_i"); 6001 const ValueDecl *IDecl = findValueDecl(ASTCtx, "i"); 6002 const IndirectFieldDecl *IndirectField = 6003 findIndirectFieldDecl(ASTCtx, "i"); 6004 6005 auto *ThisLoc = 6006 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation()); 6007 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild( 6008 *cast<ValueDecl>(IndirectField->chain().front()))); 6009 6010 ASSERT_EQ(AnonStruct.getChild(*IDecl), 6011 Env.getStorageLocation(*GlobalIDecl)); 6012 }); 6013 } 6014 6015 TEST(TransferTest, EvaluateBlockWithUnreachablePreds) { 6016 // This is a crash repro. 6017 // `false` block may not have been processed when we try to evaluate the `||` 6018 // after visiting `true`, because it is not necessary (and therefore the edge 6019 // is marked unreachable). Trying to get the analysis state via 6020 // `getEnvironment` for the subexpression still should not crash. 6021 std::string Code = R"( 6022 int target(int i) { 6023 if ((i < 0 && true) || false) { 6024 return 0; 6025 } 6026 return 0; 6027 } 6028 )"; 6029 runDataflow( 6030 Code, 6031 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6032 ASTContext &ASTCtx) {}); 6033 } 6034 6035 TEST(TransferTest, LambdaCaptureByCopy) { 6036 std::string Code = R"( 6037 void target(int Foo, int Bar) { 6038 [Foo]() { 6039 (void)0; 6040 // [[p]] 6041 }(); 6042 } 6043 )"; 6044 runDataflowOnLambda( 6045 Code, 6046 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6047 ASTContext &ASTCtx) { 6048 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6049 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6050 6051 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6052 ASSERT_THAT(FooDecl, NotNull()); 6053 6054 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6055 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6056 6057 const Value *FooVal = Env.getValue(*FooLoc); 6058 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6059 6060 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6061 ASSERT_THAT(BarDecl, NotNull()); 6062 6063 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6064 EXPECT_THAT(BarLoc, IsNull()); 6065 }); 6066 } 6067 6068 TEST(TransferTest, LambdaCaptureByReference) { 6069 std::string Code = R"( 6070 void target(int Foo, int Bar) { 6071 [&Foo]() { 6072 (void)0; 6073 // [[p]] 6074 }(); 6075 } 6076 )"; 6077 runDataflowOnLambda( 6078 Code, 6079 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6080 ASTContext &ASTCtx) { 6081 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6082 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6083 6084 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6085 ASSERT_THAT(FooDecl, NotNull()); 6086 6087 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6088 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6089 6090 const Value *FooVal = Env.getValue(*FooLoc); 6091 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6092 6093 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6094 ASSERT_THAT(BarDecl, NotNull()); 6095 6096 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6097 EXPECT_THAT(BarLoc, IsNull()); 6098 }); 6099 } 6100 6101 TEST(TransferTest, LambdaCaptureWithInitializer) { 6102 std::string Code = R"( 6103 void target(int Bar) { 6104 [Foo=Bar]() { 6105 (void)0; 6106 // [[p]] 6107 }(); 6108 } 6109 )"; 6110 runDataflowOnLambda( 6111 Code, 6112 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6113 ASTContext &ASTCtx) { 6114 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6115 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6116 6117 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6118 ASSERT_THAT(FooDecl, NotNull()); 6119 6120 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6121 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6122 6123 const Value *FooVal = Env.getValue(*FooLoc); 6124 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6125 6126 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6127 ASSERT_THAT(BarDecl, NotNull()); 6128 6129 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6130 EXPECT_THAT(BarLoc, IsNull()); 6131 }); 6132 } 6133 6134 TEST(TransferTest, LambdaCaptureByCopyImplicit) { 6135 std::string Code = R"( 6136 void target(int Foo, int Bar) { 6137 [=]() { 6138 Foo; 6139 // [[p]] 6140 }(); 6141 } 6142 )"; 6143 runDataflowOnLambda( 6144 Code, 6145 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6146 ASTContext &ASTCtx) { 6147 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6148 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6149 6150 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6151 ASSERT_THAT(FooDecl, NotNull()); 6152 6153 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6154 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6155 6156 const Value *FooVal = Env.getValue(*FooLoc); 6157 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6158 6159 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6160 ASSERT_THAT(BarDecl, NotNull()); 6161 6162 // There is no storage location for `Bar` because it isn't used in the 6163 // body of the lambda. 6164 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6165 EXPECT_THAT(BarLoc, IsNull()); 6166 }); 6167 } 6168 6169 TEST(TransferTest, LambdaCaptureByReferenceImplicit) { 6170 std::string Code = R"( 6171 void target(int Foo, int Bar) { 6172 [&]() { 6173 Foo; 6174 // [[p]] 6175 }(); 6176 } 6177 )"; 6178 runDataflowOnLambda( 6179 Code, 6180 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6181 ASTContext &ASTCtx) { 6182 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6183 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6184 6185 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6186 ASSERT_THAT(FooDecl, NotNull()); 6187 6188 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6189 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6190 6191 const Value *FooVal = Env.getValue(*FooLoc); 6192 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6193 6194 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6195 ASSERT_THAT(BarDecl, NotNull()); 6196 6197 // There is no storage location for `Bar` because it isn't used in the 6198 // body of the lambda. 6199 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6200 EXPECT_THAT(BarLoc, IsNull()); 6201 }); 6202 } 6203 6204 TEST(TransferTest, LambdaCaptureThis) { 6205 std::string Code = R"( 6206 struct Bar { 6207 int Foo; 6208 6209 void target() { 6210 [this]() { 6211 Foo; 6212 // [[p]] 6213 }(); 6214 } 6215 }; 6216 )"; 6217 runDataflowOnLambda( 6218 Code, 6219 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6220 ASTContext &ASTCtx) { 6221 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6222 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6223 6224 const RecordStorageLocation *ThisPointeeLoc = 6225 Env.getThisPointeeStorageLocation(); 6226 ASSERT_THAT(ThisPointeeLoc, NotNull()); 6227 6228 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6229 ASSERT_THAT(FooDecl, NotNull()); 6230 6231 const StorageLocation *FooLoc = ThisPointeeLoc->getChild(*FooDecl); 6232 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6233 6234 const Value *FooVal = Env.getValue(*FooLoc); 6235 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6236 }); 6237 } 6238 6239 TEST(TransferTest, DifferentReferenceLocInJoin) { 6240 // This test triggers a case where the storage location for a reference-type 6241 // variable is different for two states being joined. We used to believe this 6242 // could not happen and therefore had an assertion disallowing this; this test 6243 // exists to demonstrate that we can handle this condition without a failing 6244 // assertion. See also the discussion here: 6245 // https://discourse.llvm.org/t/70086/6 6246 std::string Code = R"( 6247 namespace std { 6248 template <class T> struct initializer_list { 6249 const T* begin(); 6250 const T* end(); 6251 }; 6252 } 6253 6254 void target(char* p, char* end) { 6255 while (p != end) { 6256 if (*p == ' ') { 6257 p++; 6258 continue; 6259 } 6260 6261 auto && range = {1, 2}; 6262 for (auto b = range.begin(), e = range.end(); b != e; ++b) { 6263 } 6264 (void)0; 6265 // [[p]] 6266 } 6267 } 6268 )"; 6269 runDataflow( 6270 Code, 6271 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6272 ASTContext &ASTCtx) { 6273 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6274 6275 // Joining environments with different storage locations for the same 6276 // declaration results in the declaration being removed from the joined 6277 // environment. 6278 const ValueDecl *VD = findValueDecl(ASTCtx, "range"); 6279 ASSERT_EQ(Env.getStorageLocation(*VD), nullptr); 6280 }); 6281 } 6282 6283 } // namespace 6284