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