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 &FooPointeeLoc = 651 cast<RecordStorageLocation>(FooVal.getPointeeLoc()); 652 653 const auto &BarVal = 654 *cast<PointerValue>(getFieldValue(&FooPointeeLoc, *BarDecl, Env)); 655 const auto &BarPointeeLoc = 656 cast<RecordStorageLocation>(BarVal.getPointeeLoc()); 657 658 EXPECT_THAT(getFieldValue(&BarPointeeLoc, *FooRefDecl, Env), NotNull()); 659 660 const auto &FooPtrVal = *cast<PointerValue>( 661 getFieldValue(&BarPointeeLoc, *FooPtrDecl, Env)); 662 const auto &FooPtrPointeeLoc = 663 cast<RecordStorageLocation>(FooPtrVal.getPointeeLoc()); 664 EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull()); 665 666 EXPECT_THAT(getFieldValue(&BarPointeeLoc, *BazRefDecl, Env), NotNull()); 667 668 const auto &BazPtrVal = *cast<PointerValue>( 669 getFieldValue(&BarPointeeLoc, *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, AssignmentOperatorFromBase) { 2128 // This is a crash repro. We don't model the copy this case, so no 2129 // expectations on the copied field of the base class are checked. 2130 std::string Code = R"( 2131 struct Base { 2132 int base; 2133 }; 2134 struct Derived : public Base { 2135 using Base::operator=; 2136 int derived; 2137 }; 2138 void target(Base B, Derived D) { 2139 D.base = 1; 2140 D.derived = 1; 2141 D = B; 2142 // [[p]] 2143 } 2144 )"; 2145 runDataflow( 2146 Code, 2147 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2148 ASTContext &ASTCtx) {}); 2149 } 2150 2151 TEST(TransferTest, AssignmentOperatorFromCallResult) { 2152 std::string Code = R"( 2153 struct A {}; 2154 A ReturnA(); 2155 2156 void target() { 2157 A MyA; 2158 MyA = ReturnA(); 2159 } 2160 )"; 2161 runDataflow( 2162 Code, 2163 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2164 ASTContext &ASTCtx) { 2165 // As of this writing, we don't produce a `Value` for the call 2166 // `ReturnA()`. The only condition we're testing for is that the 2167 // analysis should not crash in this case. 2168 }); 2169 } 2170 2171 TEST(TransferTest, AssignmentOperatorWithInitAndInheritance) { 2172 // This is a crash repro. 2173 std::string Code = R"( 2174 struct B { int Foo; }; 2175 struct S : public B {}; 2176 void target() { 2177 S S1 = { 1 }; 2178 S S2; 2179 S S3; 2180 S1 = S2; // Only Dst has InitListExpr. 2181 S3 = S1; // Only Src has InitListExpr. 2182 // [[p]] 2183 } 2184 )"; 2185 runDataflow( 2186 Code, 2187 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2188 ASTContext &ASTCtx) {}); 2189 } 2190 2191 TEST(TransferTest, CopyConstructor) { 2192 std::string Code = R"( 2193 struct A { 2194 int Baz; 2195 }; 2196 2197 void target() { 2198 A Foo = { 1 }; 2199 A Bar = Foo; 2200 // [[after_copy]] 2201 Foo.Baz = 2; 2202 // [[after_update]] 2203 } 2204 )"; 2205 runDataflow( 2206 Code, 2207 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2208 ASTContext &ASTCtx) { 2209 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2210 ASSERT_THAT(FooDecl, NotNull()); 2211 2212 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2213 ASSERT_THAT(BarDecl, NotNull()); 2214 2215 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2216 ASSERT_THAT(BazDecl, NotNull()); 2217 2218 // after_copy 2219 { 2220 const Environment &Env = 2221 getEnvironmentAtAnnotation(Results, "after_copy"); 2222 2223 const auto *FooLoc = 2224 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2225 const auto *BarLoc = 2226 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2227 2228 // `Foo` and `Bar` have different `RecordValue`s associated with them. 2229 const auto *FooVal = cast<RecordValue>(Env.getValue(*FooLoc)); 2230 const auto *BarVal = cast<RecordValue>(Env.getValue(*BarLoc)); 2231 EXPECT_NE(FooVal, BarVal); 2232 2233 // But the records compare equal. 2234 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env)); 2235 2236 // In particular, the value of `Baz` in both records is the same. 2237 const auto *FooBazVal = 2238 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2239 const auto *BarBazVal = 2240 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2241 EXPECT_EQ(FooBazVal, BarBazVal); 2242 } 2243 2244 // after_update 2245 { 2246 const Environment &Env = 2247 getEnvironmentAtAnnotation(Results, "after_update"); 2248 2249 const auto *FooLoc = 2250 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2251 const auto *BarLoc = 2252 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2253 2254 EXPECT_FALSE(recordsEqual(*FooLoc, *BarLoc, Env)); 2255 2256 const auto *FooBazVal = 2257 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2258 const auto *BarBazVal = 2259 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2260 EXPECT_NE(FooBazVal, BarBazVal); 2261 } 2262 }); 2263 } 2264 2265 TEST(TransferTest, CopyConstructorWithDefaultArgument) { 2266 std::string Code = R"( 2267 struct A { 2268 int Baz; 2269 A() = default; 2270 A(const A& a, bool def = true) { Baz = a.Baz; } 2271 }; 2272 2273 void target() { 2274 A Foo; 2275 (void)Foo.Baz; 2276 A Bar = Foo; 2277 // [[p]] 2278 } 2279 )"; 2280 runDataflow( 2281 Code, 2282 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2283 ASTContext &ASTCtx) { 2284 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2285 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2286 2287 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2288 ASSERT_THAT(FooDecl, NotNull()); 2289 2290 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2291 ASSERT_THAT(BarDecl, NotNull()); 2292 2293 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2294 ASSERT_THAT(BazDecl, NotNull()); 2295 2296 const auto *FooLoc = 2297 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2298 const auto *BarLoc = 2299 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2300 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env)); 2301 2302 const auto *FooBazVal = 2303 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2304 const auto *BarBazVal = 2305 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2306 EXPECT_EQ(FooBazVal, BarBazVal); 2307 }); 2308 } 2309 2310 TEST(TransferTest, CopyConstructorWithParens) { 2311 std::string Code = R"( 2312 struct A { 2313 int Baz; 2314 }; 2315 2316 void target() { 2317 A Foo; 2318 (void)Foo.Baz; 2319 A Bar((A(Foo))); 2320 // [[p]] 2321 } 2322 )"; 2323 runDataflow( 2324 Code, 2325 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2326 ASTContext &ASTCtx) { 2327 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2328 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2329 2330 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2331 ASSERT_THAT(FooDecl, NotNull()); 2332 2333 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2334 ASSERT_THAT(BarDecl, NotNull()); 2335 2336 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2337 ASSERT_THAT(BazDecl, NotNull()); 2338 2339 const auto *FooLoc = 2340 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2341 const auto *BarLoc = 2342 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2343 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env)); 2344 2345 const auto *FooBazVal = 2346 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2347 const auto *BarBazVal = 2348 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2349 EXPECT_EQ(FooBazVal, BarBazVal); 2350 }); 2351 } 2352 2353 TEST(TransferTest, CopyConstructorWithInitializerListAsSyntacticSugar) { 2354 std::string Code = R"( 2355 struct A { 2356 int Baz; 2357 }; 2358 void target() { 2359 A Foo = {3}; 2360 (void)Foo.Baz; 2361 A Bar = {A(Foo)}; 2362 // [[p]] 2363 } 2364 )"; 2365 runDataflow( 2366 Code, 2367 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2368 ASTContext &ASTCtx) { 2369 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2370 2371 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2372 2373 const auto &FooLoc = 2374 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo"); 2375 const auto &BarLoc = 2376 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar"); 2377 2378 const auto *FooBazVal = 2379 cast<IntegerValue>(getFieldValue(&FooLoc, *BazDecl, Env)); 2380 const auto *BarBazVal = 2381 cast<IntegerValue>(getFieldValue(&BarLoc, *BazDecl, Env)); 2382 EXPECT_EQ(FooBazVal, BarBazVal); 2383 }); 2384 } 2385 2386 TEST(TransferTest, CopyConstructorArgIsRefReturnedByFunction) { 2387 // This is a crash repro. 2388 std::string Code = R"( 2389 struct S {}; 2390 const S &returnsSRef(); 2391 void target() { 2392 S s(returnsSRef()); 2393 } 2394 )"; 2395 runDataflow( 2396 Code, 2397 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2398 ASTContext &ASTCtx) {}); 2399 } 2400 2401 TEST(TransferTest, MoveConstructor) { 2402 std::string Code = R"( 2403 namespace std { 2404 2405 template <typename T> struct remove_reference { using type = T; }; 2406 template <typename T> struct remove_reference<T&> { using type = T; }; 2407 template <typename T> struct remove_reference<T&&> { using type = T; }; 2408 2409 template <typename T> 2410 using remove_reference_t = typename remove_reference<T>::type; 2411 2412 template <typename T> 2413 std::remove_reference_t<T>&& move(T&& x); 2414 2415 } // namespace std 2416 2417 struct A { 2418 int Baz; 2419 }; 2420 2421 void target() { 2422 A Foo; 2423 A Bar; 2424 (void)Foo.Baz; 2425 // [[p1]] 2426 Foo = std::move(Bar); 2427 // [[p2]] 2428 } 2429 )"; 2430 runDataflow( 2431 Code, 2432 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2433 ASTContext &ASTCtx) { 2434 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 2435 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 2436 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 2437 2438 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2439 ASSERT_THAT(FooDecl, NotNull()); 2440 2441 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2442 ASSERT_THAT(BarDecl, NotNull()); 2443 2444 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2445 ASSERT_THAT(BazDecl, NotNull()); 2446 2447 const auto *FooLoc1 = 2448 cast<RecordStorageLocation>(Env1.getStorageLocation(*FooDecl)); 2449 const auto *BarLoc1 = 2450 cast<RecordStorageLocation>(Env1.getStorageLocation(*BarDecl)); 2451 2452 EXPECT_FALSE(recordsEqual(*FooLoc1, *BarLoc1, Env1)); 2453 2454 const auto *FooVal1 = cast<RecordValue>(Env1.getValue(*FooLoc1)); 2455 const auto *BarVal1 = cast<RecordValue>(Env1.getValue(*BarLoc1)); 2456 EXPECT_NE(FooVal1, BarVal1); 2457 2458 const auto *FooBazVal1 = 2459 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env1)); 2460 const auto *BarBazVal1 = 2461 cast<IntegerValue>(getFieldValue(BarLoc1, *BazDecl, Env1)); 2462 EXPECT_NE(FooBazVal1, BarBazVal1); 2463 2464 const auto *FooLoc2 = 2465 cast<RecordStorageLocation>(Env2.getStorageLocation(*FooDecl)); 2466 const auto *FooVal2 = cast<RecordValue>(Env2.getValue(*FooLoc2)); 2467 EXPECT_NE(FooVal2, BarVal1); 2468 EXPECT_TRUE(recordsEqual(*FooLoc2, Env2, *BarLoc1, Env1)); 2469 2470 const auto *FooBazVal2 = 2471 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env2)); 2472 EXPECT_EQ(FooBazVal2, BarBazVal1); 2473 }); 2474 } 2475 2476 TEST(TransferTest, BindTemporary) { 2477 std::string Code = R"( 2478 struct A { 2479 virtual ~A() = default; 2480 2481 int Baz; 2482 }; 2483 2484 void target(A Foo) { 2485 int Bar = A(Foo).Baz; 2486 // [[p]] 2487 } 2488 )"; 2489 runDataflow( 2490 Code, 2491 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2492 ASTContext &ASTCtx) { 2493 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2494 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2495 2496 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2497 ASSERT_THAT(FooDecl, NotNull()); 2498 2499 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2500 ASSERT_THAT(BarDecl, NotNull()); 2501 2502 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2503 ASSERT_THAT(BazDecl, NotNull()); 2504 2505 const auto &FooLoc = 2506 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2507 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 2508 EXPECT_EQ(BarVal, getFieldValue(&FooLoc, *BazDecl, Env)); 2509 }); 2510 } 2511 2512 TEST(TransferTest, StaticCast) { 2513 std::string Code = R"( 2514 void target(int Foo) { 2515 int Bar = static_cast<int>(Foo); 2516 // [[p]] 2517 } 2518 )"; 2519 runDataflow( 2520 Code, 2521 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2522 ASTContext &ASTCtx) { 2523 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2524 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2525 2526 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2527 ASSERT_THAT(FooDecl, NotNull()); 2528 2529 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2530 ASSERT_THAT(BarDecl, NotNull()); 2531 2532 const auto *FooVal = Env.getValue(*FooDecl); 2533 const auto *BarVal = Env.getValue(*BarDecl); 2534 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 2535 EXPECT_TRUE(isa<IntegerValue>(BarVal)); 2536 EXPECT_EQ(FooVal, BarVal); 2537 }); 2538 } 2539 2540 TEST(TransferTest, IntegralCast) { 2541 std::string Code = R"( 2542 void target(int Foo) { 2543 long Bar = Foo; 2544 // [[p]] 2545 } 2546 )"; 2547 runDataflow( 2548 Code, 2549 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2550 ASTContext &ASTCtx) { 2551 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2552 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2553 2554 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2555 ASSERT_THAT(FooDecl, NotNull()); 2556 2557 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2558 ASSERT_THAT(BarDecl, NotNull()); 2559 2560 const auto *FooVal = Env.getValue(*FooDecl); 2561 const auto *BarVal = Env.getValue(*BarDecl); 2562 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 2563 EXPECT_TRUE(isa<IntegerValue>(BarVal)); 2564 EXPECT_EQ(FooVal, BarVal); 2565 }); 2566 } 2567 2568 TEST(TransferTest, IntegraltoBooleanCast) { 2569 std::string Code = R"( 2570 void target(int Foo) { 2571 bool Bar = Foo; 2572 // [[p]] 2573 } 2574 )"; 2575 runDataflow( 2576 Code, 2577 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2578 ASTContext &ASTCtx) { 2579 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2580 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2581 2582 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2583 ASSERT_THAT(FooDecl, NotNull()); 2584 2585 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2586 ASSERT_THAT(BarDecl, NotNull()); 2587 2588 const auto *FooVal = Env.getValue(*FooDecl); 2589 const auto *BarVal = Env.getValue(*BarDecl); 2590 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 2591 EXPECT_TRUE(isa<BoolValue>(BarVal)); 2592 }); 2593 } 2594 2595 TEST(TransferTest, IntegralToBooleanCastFromBool) { 2596 std::string Code = R"( 2597 void target(bool Foo) { 2598 int Zab = Foo; 2599 bool Bar = Zab; 2600 // [[p]] 2601 } 2602 )"; 2603 runDataflow( 2604 Code, 2605 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2606 ASTContext &ASTCtx) { 2607 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2608 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2609 2610 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2611 ASSERT_THAT(FooDecl, NotNull()); 2612 2613 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2614 ASSERT_THAT(BarDecl, NotNull()); 2615 2616 const auto *FooVal = Env.getValue(*FooDecl); 2617 const auto *BarVal = Env.getValue(*BarDecl); 2618 EXPECT_TRUE(isa<BoolValue>(FooVal)); 2619 EXPECT_TRUE(isa<BoolValue>(BarVal)); 2620 EXPECT_EQ(FooVal, BarVal); 2621 }); 2622 } 2623 2624 TEST(TransferTest, NullToPointerCast) { 2625 std::string Code = R"( 2626 using my_nullptr_t = decltype(nullptr); 2627 struct Baz {}; 2628 void target() { 2629 int *FooX = nullptr; 2630 int *FooY = nullptr; 2631 bool **Bar = nullptr; 2632 Baz *Baz = nullptr; 2633 my_nullptr_t Null = 0; 2634 // [[p]] 2635 } 2636 )"; 2637 runDataflow( 2638 Code, 2639 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2640 ASTContext &ASTCtx) { 2641 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2642 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2643 2644 const ValueDecl *FooXDecl = findValueDecl(ASTCtx, "FooX"); 2645 ASSERT_THAT(FooXDecl, NotNull()); 2646 2647 const ValueDecl *FooYDecl = findValueDecl(ASTCtx, "FooY"); 2648 ASSERT_THAT(FooYDecl, NotNull()); 2649 2650 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2651 ASSERT_THAT(BarDecl, NotNull()); 2652 2653 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2654 ASSERT_THAT(BazDecl, NotNull()); 2655 2656 const ValueDecl *NullDecl = findValueDecl(ASTCtx, "Null"); 2657 ASSERT_THAT(NullDecl, NotNull()); 2658 2659 const auto *FooXVal = cast<PointerValue>(Env.getValue(*FooXDecl)); 2660 const auto *FooYVal = cast<PointerValue>(Env.getValue(*FooYDecl)); 2661 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 2662 const auto *BazVal = cast<PointerValue>(Env.getValue(*BazDecl)); 2663 const auto *NullVal = cast<PointerValue>(Env.getValue(*NullDecl)); 2664 2665 EXPECT_EQ(FooXVal, FooYVal); 2666 EXPECT_NE(FooXVal, BarVal); 2667 EXPECT_NE(FooXVal, BazVal); 2668 EXPECT_NE(BarVal, BazVal); 2669 2670 const StorageLocation &FooPointeeLoc = FooXVal->getPointeeLoc(); 2671 EXPECT_TRUE(isa<ScalarStorageLocation>(FooPointeeLoc)); 2672 EXPECT_THAT(Env.getValue(FooPointeeLoc), IsNull()); 2673 2674 const StorageLocation &BarPointeeLoc = BarVal->getPointeeLoc(); 2675 EXPECT_TRUE(isa<ScalarStorageLocation>(BarPointeeLoc)); 2676 EXPECT_THAT(Env.getValue(BarPointeeLoc), IsNull()); 2677 2678 const StorageLocation &BazPointeeLoc = BazVal->getPointeeLoc(); 2679 EXPECT_TRUE(isa<RecordStorageLocation>(BazPointeeLoc)); 2680 EXPECT_THAT(Env.getValue(BazPointeeLoc), IsNull()); 2681 2682 const StorageLocation &NullPointeeLoc = NullVal->getPointeeLoc(); 2683 EXPECT_TRUE(isa<ScalarStorageLocation>(NullPointeeLoc)); 2684 EXPECT_THAT(Env.getValue(NullPointeeLoc), IsNull()); 2685 }); 2686 } 2687 2688 TEST(TransferTest, PointerToMemberVariable) { 2689 std::string Code = R"( 2690 struct S { 2691 int i; 2692 }; 2693 void target() { 2694 int S::*MemberPointer = &S::i; 2695 // [[p]] 2696 } 2697 )"; 2698 runDataflow( 2699 Code, 2700 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2701 ASTContext &ASTCtx) { 2702 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2703 2704 const ValueDecl *MemberPointerDecl = 2705 findValueDecl(ASTCtx, "MemberPointer"); 2706 ASSERT_THAT(MemberPointerDecl, NotNull()); 2707 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 2708 }); 2709 } 2710 2711 TEST(TransferTest, PointerToMemberFunction) { 2712 std::string Code = R"( 2713 struct S { 2714 void Method(); 2715 }; 2716 void target() { 2717 void (S::*MemberPointer)() = &S::Method; 2718 // [[p]] 2719 } 2720 )"; 2721 runDataflow( 2722 Code, 2723 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2724 ASTContext &ASTCtx) { 2725 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2726 2727 const ValueDecl *MemberPointerDecl = 2728 findValueDecl(ASTCtx, "MemberPointer"); 2729 ASSERT_THAT(MemberPointerDecl, NotNull()); 2730 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 2731 }); 2732 } 2733 2734 TEST(TransferTest, NullToMemberPointerCast) { 2735 std::string Code = R"( 2736 struct Foo {}; 2737 void target() { 2738 int Foo::*MemberPointer = nullptr; 2739 // [[p]] 2740 } 2741 )"; 2742 runDataflow( 2743 Code, 2744 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2745 ASTContext &ASTCtx) { 2746 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2747 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2748 2749 const ValueDecl *MemberPointerDecl = 2750 findValueDecl(ASTCtx, "MemberPointer"); 2751 ASSERT_THAT(MemberPointerDecl, NotNull()); 2752 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 2753 }); 2754 } 2755 2756 TEST(TransferTest, AddrOfValue) { 2757 std::string Code = R"( 2758 void target() { 2759 int Foo; 2760 int *Bar = &Foo; 2761 // [[p]] 2762 } 2763 )"; 2764 runDataflow( 2765 Code, 2766 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2767 ASTContext &ASTCtx) { 2768 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2769 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2770 2771 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2772 ASSERT_THAT(FooDecl, NotNull()); 2773 2774 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2775 ASSERT_THAT(BarDecl, NotNull()); 2776 2777 const auto *FooLoc = 2778 cast<ScalarStorageLocation>(Env.getStorageLocation(*FooDecl)); 2779 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 2780 EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc); 2781 }); 2782 } 2783 2784 TEST(TransferTest, AddrOfReference) { 2785 std::string Code = R"( 2786 void target(int *Foo) { 2787 int *Bar = &(*Foo); 2788 // [[p]] 2789 } 2790 )"; 2791 runDataflow( 2792 Code, 2793 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2794 ASTContext &ASTCtx) { 2795 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2796 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2797 2798 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2799 ASSERT_THAT(FooDecl, NotNull()); 2800 2801 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2802 ASSERT_THAT(BarDecl, NotNull()); 2803 2804 const auto *FooVal = cast<PointerValue>(Env.getValue(*FooDecl)); 2805 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 2806 EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc()); 2807 }); 2808 } 2809 2810 TEST(TransferTest, CannotAnalyzeFunctionTemplate) { 2811 std::string Code = R"( 2812 template <typename T> 2813 void target() {} 2814 )"; 2815 ASSERT_THAT_ERROR( 2816 checkDataflowWithNoopAnalysis(Code), 2817 llvm::FailedWithMessage("Cannot analyze templated declarations")); 2818 } 2819 2820 TEST(TransferTest, CannotAnalyzeMethodOfClassTemplate) { 2821 std::string Code = R"( 2822 template <typename T> 2823 struct A { 2824 void target() {} 2825 }; 2826 )"; 2827 ASSERT_THAT_ERROR( 2828 checkDataflowWithNoopAnalysis(Code), 2829 llvm::FailedWithMessage("Cannot analyze templated declarations")); 2830 } 2831 2832 TEST(TransferTest, VarDeclInitAssignConditionalOperator) { 2833 std::string Code = R"( 2834 struct A {}; 2835 2836 void target(A Foo, A Bar, bool Cond) { 2837 A Baz = Cond ? Foo : Bar; 2838 /*[[p]]*/ 2839 } 2840 )"; 2841 runDataflow( 2842 Code, 2843 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2844 ASTContext &ASTCtx) { 2845 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2846 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2847 2848 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2849 ASSERT_THAT(FooDecl, NotNull()); 2850 2851 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2852 ASSERT_THAT(BarDecl, NotNull()); 2853 2854 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2855 ASSERT_THAT(BazDecl, NotNull()); 2856 2857 const auto *FooVal = cast<RecordValue>(Env.getValue(*FooDecl)); 2858 const auto *BarVal = cast<RecordValue>(Env.getValue(*BarDecl)); 2859 2860 const auto *BazVal = dyn_cast<RecordValue>(Env.getValue(*BazDecl)); 2861 ASSERT_THAT(BazVal, NotNull()); 2862 2863 EXPECT_NE(BazVal, FooVal); 2864 EXPECT_NE(BazVal, BarVal); 2865 }); 2866 } 2867 2868 TEST(TransferTest, VarDeclInDoWhile) { 2869 std::string Code = R"( 2870 void target(int *Foo) { 2871 do { 2872 int Bar = *Foo; 2873 // [[in_loop]] 2874 } while (false); 2875 (void)0; 2876 // [[after_loop]] 2877 } 2878 )"; 2879 runDataflow( 2880 Code, 2881 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2882 ASTContext &ASTCtx) { 2883 const Environment &EnvInLoop = 2884 getEnvironmentAtAnnotation(Results, "in_loop"); 2885 const Environment &EnvAfterLoop = 2886 getEnvironmentAtAnnotation(Results, "after_loop"); 2887 2888 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2889 ASSERT_THAT(FooDecl, NotNull()); 2890 2891 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2892 ASSERT_THAT(BarDecl, NotNull()); 2893 2894 const auto *FooVal = 2895 cast<PointerValue>(EnvAfterLoop.getValue(*FooDecl)); 2896 const auto *FooPointeeVal = 2897 cast<IntegerValue>(EnvAfterLoop.getValue(FooVal->getPointeeLoc())); 2898 2899 const auto *BarVal = cast<IntegerValue>(EnvInLoop.getValue(*BarDecl)); 2900 EXPECT_EQ(BarVal, FooPointeeVal); 2901 2902 // FIXME: This assertion documents current behavior, but we would prefer 2903 // declarations to be removed from the environment when their lifetime 2904 // ends. Once this is the case, change this assertion accordingly. 2905 ASSERT_THAT(EnvAfterLoop.getValue(*BarDecl), BarVal); 2906 }); 2907 } 2908 2909 TEST(TransferTest, UnreachableAfterWhileTrue) { 2910 std::string Code = R"( 2911 void target() { 2912 while (true) {} 2913 (void)0; 2914 /*[[p]]*/ 2915 } 2916 )"; 2917 runDataflow( 2918 Code, 2919 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2920 ASTContext &ASTCtx) { 2921 // The node after the while-true is pruned because it is trivially 2922 // known to be unreachable. 2923 ASSERT_TRUE(Results.empty()); 2924 }); 2925 } 2926 2927 TEST(TransferTest, AggregateInitialization) { 2928 std::string BracesCode = R"( 2929 struct A { 2930 int Foo; 2931 }; 2932 2933 struct B { 2934 int Bar; 2935 A Baz; 2936 int Qux; 2937 }; 2938 2939 void target(int BarArg, int FooArg, int QuxArg) { 2940 B Quux{BarArg, {FooArg}, QuxArg}; 2941 B OtherB; 2942 /*[[p]]*/ 2943 } 2944 )"; 2945 std::string BraceElisionCode = R"( 2946 struct A { 2947 int Foo; 2948 }; 2949 2950 struct B { 2951 int Bar; 2952 A Baz; 2953 int Qux; 2954 }; 2955 2956 void target(int BarArg, int FooArg, int QuxArg) { 2957 B Quux = {BarArg, FooArg, QuxArg}; 2958 B OtherB; 2959 /*[[p]]*/ 2960 } 2961 )"; 2962 for (const std::string &Code : {BracesCode, BraceElisionCode}) { 2963 runDataflow( 2964 Code, 2965 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2966 ASTContext &ASTCtx) { 2967 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2968 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2969 2970 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2971 ASSERT_THAT(FooDecl, NotNull()); 2972 2973 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2974 ASSERT_THAT(BarDecl, NotNull()); 2975 2976 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2977 ASSERT_THAT(BazDecl, NotNull()); 2978 2979 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 2980 ASSERT_THAT(QuxDecl, NotNull()); 2981 2982 const ValueDecl *FooArgDecl = findValueDecl(ASTCtx, "FooArg"); 2983 ASSERT_THAT(FooArgDecl, NotNull()); 2984 2985 const ValueDecl *BarArgDecl = findValueDecl(ASTCtx, "BarArg"); 2986 ASSERT_THAT(BarArgDecl, NotNull()); 2987 2988 const ValueDecl *QuxArgDecl = findValueDecl(ASTCtx, "QuxArg"); 2989 ASSERT_THAT(QuxArgDecl, NotNull()); 2990 2991 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 2992 ASSERT_THAT(QuuxDecl, NotNull()); 2993 2994 const auto *FooArgVal = cast<IntegerValue>(Env.getValue(*FooArgDecl)); 2995 const auto *BarArgVal = cast<IntegerValue>(Env.getValue(*BarArgDecl)); 2996 const auto *QuxArgVal = cast<IntegerValue>(Env.getValue(*QuxArgDecl)); 2997 2998 const auto &QuuxLoc = 2999 *cast<RecordStorageLocation>(Env.getStorageLocation(*QuuxDecl)); 3000 const auto &BazLoc = 3001 *cast<RecordStorageLocation>(QuuxLoc.getChild(*BazDecl)); 3002 3003 EXPECT_EQ(getFieldValue(&QuuxLoc, *BarDecl, Env), BarArgVal); 3004 EXPECT_EQ(getFieldValue(&BazLoc, *FooDecl, Env), FooArgVal); 3005 EXPECT_EQ(getFieldValue(&QuuxLoc, *QuxDecl, Env), QuxArgVal); 3006 3007 // Check that fields initialized in an initializer list are always 3008 // modeled in other instances of the same type. 3009 const auto &OtherBLoc = 3010 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "OtherB"); 3011 EXPECT_THAT(OtherBLoc.getChild(*BarDecl), NotNull()); 3012 EXPECT_THAT(OtherBLoc.getChild(*BazDecl), NotNull()); 3013 EXPECT_THAT(OtherBLoc.getChild(*QuxDecl), NotNull()); 3014 }); 3015 } 3016 } 3017 3018 TEST(TransferTest, AggregateInitializationReferenceField) { 3019 std::string Code = R"( 3020 struct S { 3021 int &RefField; 3022 }; 3023 3024 void target(int i) { 3025 S s = { i }; 3026 /*[[p]]*/ 3027 } 3028 )"; 3029 runDataflow( 3030 Code, 3031 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3032 ASTContext &ASTCtx) { 3033 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3034 3035 const ValueDecl *RefFieldDecl = findValueDecl(ASTCtx, "RefField"); 3036 3037 auto &ILoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "i"); 3038 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"); 3039 3040 EXPECT_EQ(SLoc.getChild(*RefFieldDecl), &ILoc); 3041 }); 3042 } 3043 3044 TEST(TransferTest, AggregateInitialization_NotExplicitlyInitializedField) { 3045 std::string Code = R"( 3046 struct S { 3047 int i1; 3048 int i2; 3049 }; 3050 3051 void target(int i) { 3052 S s = { i }; 3053 /*[[p]]*/ 3054 } 3055 )"; 3056 runDataflow( 3057 Code, 3058 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3059 ASTContext &ASTCtx) { 3060 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3061 3062 const ValueDecl *I1FieldDecl = findValueDecl(ASTCtx, "i1"); 3063 const ValueDecl *I2FieldDecl = findValueDecl(ASTCtx, "i2"); 3064 3065 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"); 3066 3067 auto &IValue = getValueForDecl<IntegerValue>(ASTCtx, Env, "i"); 3068 auto &I1Value = 3069 *cast<IntegerValue>(getFieldValue(&SLoc, *I1FieldDecl, Env)); 3070 EXPECT_EQ(&I1Value, &IValue); 3071 auto &I2Value = 3072 *cast<IntegerValue>(getFieldValue(&SLoc, *I2FieldDecl, Env)); 3073 EXPECT_NE(&I2Value, &IValue); 3074 }); 3075 } 3076 3077 TEST(TransferTest, AssignToUnionMember) { 3078 std::string Code = R"( 3079 union A { 3080 int Foo; 3081 }; 3082 3083 void target(int Bar) { 3084 A Baz; 3085 Baz.Foo = Bar; 3086 // [[p]] 3087 } 3088 )"; 3089 runDataflow( 3090 Code, 3091 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3092 ASTContext &ASTCtx) { 3093 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3094 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3095 3096 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3097 ASSERT_THAT(BazDecl, NotNull()); 3098 ASSERT_TRUE(BazDecl->getType()->isUnionType()); 3099 3100 auto BazFields = BazDecl->getType()->getAsRecordDecl()->fields(); 3101 FieldDecl *FooDecl = nullptr; 3102 for (FieldDecl *Field : BazFields) { 3103 if (Field->getNameAsString() == "Foo") { 3104 FooDecl = Field; 3105 } else { 3106 FAIL() << "Unexpected field: " << Field->getNameAsString(); 3107 } 3108 } 3109 ASSERT_THAT(FooDecl, NotNull()); 3110 3111 const auto *BazLoc = dyn_cast_or_null<RecordStorageLocation>( 3112 Env.getStorageLocation(*BazDecl)); 3113 ASSERT_THAT(BazLoc, NotNull()); 3114 ASSERT_THAT(Env.getValue(*BazLoc), NotNull()); 3115 3116 const auto *FooVal = 3117 cast<IntegerValue>(getFieldValue(BazLoc, *FooDecl, Env)); 3118 3119 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3120 ASSERT_THAT(BarDecl, NotNull()); 3121 const auto *BarLoc = Env.getStorageLocation(*BarDecl); 3122 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 3123 3124 EXPECT_EQ(Env.getValue(*BarLoc), FooVal); 3125 }); 3126 } 3127 3128 TEST(TransferTest, AssignFromBoolLiteral) { 3129 std::string Code = R"( 3130 void target() { 3131 bool Foo = true; 3132 bool Bar = false; 3133 // [[p]] 3134 } 3135 )"; 3136 runDataflow( 3137 Code, 3138 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3139 ASTContext &ASTCtx) { 3140 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3141 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3142 3143 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3144 ASSERT_THAT(FooDecl, NotNull()); 3145 3146 const auto *FooVal = 3147 dyn_cast_or_null<AtomicBoolValue>(Env.getValue(*FooDecl)); 3148 ASSERT_THAT(FooVal, NotNull()); 3149 3150 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3151 ASSERT_THAT(BarDecl, NotNull()); 3152 3153 const auto *BarVal = 3154 dyn_cast_or_null<AtomicBoolValue>(Env.getValue(*BarDecl)); 3155 ASSERT_THAT(BarVal, NotNull()); 3156 3157 EXPECT_EQ(FooVal, &Env.getBoolLiteralValue(true)); 3158 EXPECT_EQ(BarVal, &Env.getBoolLiteralValue(false)); 3159 }); 3160 } 3161 3162 TEST(TransferTest, AssignFromCompositeBoolExpression) { 3163 { 3164 std::string Code = R"( 3165 void target(bool Foo, bool Bar, bool Qux) { 3166 bool Baz = (Foo) && (Bar || Qux); 3167 // [[p]] 3168 } 3169 )"; 3170 runDataflow( 3171 Code, 3172 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3173 ASTContext &ASTCtx) { 3174 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3175 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3176 3177 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3178 ASSERT_THAT(FooDecl, NotNull()); 3179 3180 const auto *FooVal = 3181 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3182 ASSERT_THAT(FooVal, NotNull()); 3183 3184 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3185 ASSERT_THAT(BarDecl, NotNull()); 3186 3187 const auto *BarVal = 3188 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 3189 ASSERT_THAT(BarVal, NotNull()); 3190 3191 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 3192 ASSERT_THAT(QuxDecl, NotNull()); 3193 3194 const auto *QuxVal = 3195 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl)); 3196 ASSERT_THAT(QuxVal, NotNull()); 3197 3198 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3199 ASSERT_THAT(BazDecl, NotNull()); 3200 3201 const auto *BazVal = 3202 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl)); 3203 ASSERT_THAT(BazVal, NotNull()); 3204 auto &A = Env.arena(); 3205 EXPECT_EQ(&BazVal->formula(), 3206 &A.makeAnd(FooVal->formula(), 3207 A.makeOr(BarVal->formula(), QuxVal->formula()))); 3208 }); 3209 } 3210 3211 { 3212 std::string Code = R"( 3213 void target(bool Foo, bool Bar, bool Qux) { 3214 bool Baz = (Foo && Qux) || (Bar); 3215 // [[p]] 3216 } 3217 )"; 3218 runDataflow( 3219 Code, 3220 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3221 ASTContext &ASTCtx) { 3222 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3223 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3224 3225 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3226 ASSERT_THAT(FooDecl, NotNull()); 3227 3228 const auto *FooVal = 3229 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3230 ASSERT_THAT(FooVal, NotNull()); 3231 3232 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3233 ASSERT_THAT(BarDecl, NotNull()); 3234 3235 const auto *BarVal = 3236 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 3237 ASSERT_THAT(BarVal, NotNull()); 3238 3239 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 3240 ASSERT_THAT(QuxDecl, NotNull()); 3241 3242 const auto *QuxVal = 3243 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl)); 3244 ASSERT_THAT(QuxVal, NotNull()); 3245 3246 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3247 ASSERT_THAT(BazDecl, NotNull()); 3248 3249 const auto *BazVal = 3250 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl)); 3251 ASSERT_THAT(BazVal, NotNull()); 3252 auto &A = Env.arena(); 3253 EXPECT_EQ(&BazVal->formula(), 3254 &A.makeOr(A.makeAnd(FooVal->formula(), QuxVal->formula()), 3255 BarVal->formula())); 3256 }); 3257 } 3258 3259 { 3260 std::string Code = R"( 3261 void target(bool A, bool B, bool C, bool D) { 3262 bool Foo = ((A && B) && C) && D; 3263 // [[p]] 3264 } 3265 )"; 3266 runDataflow( 3267 Code, 3268 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3269 ASTContext &ASTCtx) { 3270 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3271 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3272 3273 const ValueDecl *ADecl = findValueDecl(ASTCtx, "A"); 3274 ASSERT_THAT(ADecl, NotNull()); 3275 3276 const auto *AVal = dyn_cast_or_null<BoolValue>(Env.getValue(*ADecl)); 3277 ASSERT_THAT(AVal, NotNull()); 3278 3279 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B"); 3280 ASSERT_THAT(BDecl, NotNull()); 3281 3282 const auto *BVal = dyn_cast_or_null<BoolValue>(Env.getValue(*BDecl)); 3283 ASSERT_THAT(BVal, NotNull()); 3284 3285 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C"); 3286 ASSERT_THAT(CDecl, NotNull()); 3287 3288 const auto *CVal = dyn_cast_or_null<BoolValue>(Env.getValue(*CDecl)); 3289 ASSERT_THAT(CVal, NotNull()); 3290 3291 const ValueDecl *DDecl = findValueDecl(ASTCtx, "D"); 3292 ASSERT_THAT(DDecl, NotNull()); 3293 3294 const auto *DVal = dyn_cast_or_null<BoolValue>(Env.getValue(*DDecl)); 3295 ASSERT_THAT(DVal, NotNull()); 3296 3297 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3298 ASSERT_THAT(FooDecl, NotNull()); 3299 3300 const auto *FooVal = 3301 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3302 ASSERT_THAT(FooVal, NotNull()); 3303 auto &A = Env.arena(); 3304 EXPECT_EQ( 3305 &FooVal->formula(), 3306 &A.makeAnd(A.makeAnd(A.makeAnd(AVal->formula(), BVal->formula()), 3307 CVal->formula()), 3308 DVal->formula())); 3309 }); 3310 } 3311 } 3312 3313 TEST(TransferTest, AssignFromBoolNegation) { 3314 std::string Code = R"( 3315 void target() { 3316 bool Foo = true; 3317 bool Bar = !(Foo); 3318 // [[p]] 3319 } 3320 )"; 3321 runDataflow( 3322 Code, 3323 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3324 ASTContext &ASTCtx) { 3325 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3326 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3327 3328 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3329 ASSERT_THAT(FooDecl, NotNull()); 3330 3331 const auto *FooVal = 3332 dyn_cast_or_null<AtomicBoolValue>(Env.getValue(*FooDecl)); 3333 ASSERT_THAT(FooVal, NotNull()); 3334 3335 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3336 ASSERT_THAT(BarDecl, NotNull()); 3337 3338 const auto *BarVal = 3339 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 3340 ASSERT_THAT(BarVal, NotNull()); 3341 auto &A = Env.arena(); 3342 EXPECT_EQ(&BarVal->formula(), &A.makeNot(FooVal->formula())); 3343 }); 3344 } 3345 3346 TEST(TransferTest, BuiltinExpect) { 3347 std::string Code = R"( 3348 void target(long Foo) { 3349 long Bar = __builtin_expect(Foo, true); 3350 /*[[p]]*/ 3351 } 3352 )"; 3353 runDataflow( 3354 Code, 3355 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3356 ASTContext &ASTCtx) { 3357 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3358 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3359 3360 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3361 ASSERT_THAT(FooDecl, NotNull()); 3362 3363 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3364 ASSERT_THAT(BarDecl, NotNull()); 3365 3366 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3367 }); 3368 } 3369 3370 // `__builtin_expect` takes and returns a `long` argument, so other types 3371 // involve casts. This verifies that we identify the input and output in that 3372 // case. 3373 TEST(TransferTest, BuiltinExpectBoolArg) { 3374 std::string Code = R"( 3375 void target(bool Foo) { 3376 bool Bar = __builtin_expect(Foo, true); 3377 /*[[p]]*/ 3378 } 3379 )"; 3380 runDataflow( 3381 Code, 3382 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3383 ASTContext &ASTCtx) { 3384 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3385 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3386 3387 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3388 ASSERT_THAT(FooDecl, NotNull()); 3389 3390 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3391 ASSERT_THAT(BarDecl, NotNull()); 3392 3393 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3394 }); 3395 } 3396 3397 TEST(TransferTest, BuiltinUnreachable) { 3398 std::string Code = R"( 3399 void target(bool Foo) { 3400 bool Bar = false; 3401 if (Foo) 3402 Bar = Foo; 3403 else 3404 __builtin_unreachable(); 3405 (void)0; 3406 /*[[p]]*/ 3407 } 3408 )"; 3409 runDataflow( 3410 Code, 3411 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3412 ASTContext &ASTCtx) { 3413 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3414 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3415 3416 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3417 ASSERT_THAT(FooDecl, NotNull()); 3418 3419 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3420 ASSERT_THAT(BarDecl, NotNull()); 3421 3422 // `__builtin_unreachable` promises that the code is 3423 // unreachable, so the compiler treats the "then" branch as the 3424 // only possible predecessor of this statement. 3425 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3426 }); 3427 } 3428 3429 TEST(TransferTest, BuiltinTrap) { 3430 std::string Code = R"( 3431 void target(bool Foo) { 3432 bool Bar = false; 3433 if (Foo) 3434 Bar = Foo; 3435 else 3436 __builtin_trap(); 3437 (void)0; 3438 /*[[p]]*/ 3439 } 3440 )"; 3441 runDataflow( 3442 Code, 3443 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3444 ASTContext &ASTCtx) { 3445 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3446 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3447 3448 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3449 ASSERT_THAT(FooDecl, NotNull()); 3450 3451 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3452 ASSERT_THAT(BarDecl, NotNull()); 3453 3454 // `__builtin_trap` ensures program termination, so only the 3455 // "then" branch is a predecessor of this statement. 3456 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3457 }); 3458 } 3459 3460 TEST(TransferTest, BuiltinDebugTrap) { 3461 std::string Code = R"( 3462 void target(bool Foo) { 3463 bool Bar = false; 3464 if (Foo) 3465 Bar = Foo; 3466 else 3467 __builtin_debugtrap(); 3468 (void)0; 3469 /*[[p]]*/ 3470 } 3471 )"; 3472 runDataflow( 3473 Code, 3474 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3475 ASTContext &ASTCtx) { 3476 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3477 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3478 3479 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3480 ASSERT_THAT(FooDecl, NotNull()); 3481 3482 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3483 ASSERT_THAT(BarDecl, NotNull()); 3484 3485 // `__builtin_debugtrap` doesn't ensure program termination. 3486 EXPECT_NE(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3487 }); 3488 } 3489 3490 TEST(TransferTest, StaticIntSingleVarDecl) { 3491 std::string Code = R"( 3492 void target() { 3493 static int Foo; 3494 // [[p]] 3495 } 3496 )"; 3497 runDataflow( 3498 Code, 3499 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3500 ASTContext &ASTCtx) { 3501 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3502 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3503 3504 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3505 ASSERT_THAT(FooDecl, NotNull()); 3506 3507 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 3508 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 3509 3510 const Value *FooVal = Env.getValue(*FooLoc); 3511 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 3512 }); 3513 } 3514 3515 TEST(TransferTest, StaticIntGroupVarDecl) { 3516 std::string Code = R"( 3517 void target() { 3518 static int Foo, Bar; 3519 (void)0; 3520 // [[p]] 3521 } 3522 )"; 3523 runDataflow( 3524 Code, 3525 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3526 ASTContext &ASTCtx) { 3527 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3528 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3529 3530 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3531 ASSERT_THAT(FooDecl, NotNull()); 3532 3533 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3534 ASSERT_THAT(BarDecl, NotNull()); 3535 3536 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 3537 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 3538 3539 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 3540 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 3541 3542 const Value *FooVal = Env.getValue(*FooLoc); 3543 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 3544 3545 const Value *BarVal = Env.getValue(*BarLoc); 3546 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 3547 3548 EXPECT_NE(FooVal, BarVal); 3549 }); 3550 } 3551 3552 TEST(TransferTest, GlobalIntVarDecl) { 3553 std::string Code = R"( 3554 static int Foo; 3555 3556 void target() { 3557 int Bar = Foo; 3558 int Baz = Foo; 3559 // [[p]] 3560 } 3561 )"; 3562 runDataflow( 3563 Code, 3564 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3565 ASTContext &ASTCtx) { 3566 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3567 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3568 3569 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3570 ASSERT_THAT(BarDecl, NotNull()); 3571 3572 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3573 ASSERT_THAT(BazDecl, NotNull()); 3574 3575 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 3576 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 3577 EXPECT_EQ(BarVal, BazVal); 3578 }); 3579 } 3580 3581 TEST(TransferTest, StaticMemberIntVarDecl) { 3582 std::string Code = R"( 3583 struct A { 3584 static int Foo; 3585 }; 3586 3587 void target(A a) { 3588 int Bar = a.Foo; 3589 int Baz = a.Foo; 3590 // [[p]] 3591 } 3592 )"; 3593 runDataflow( 3594 Code, 3595 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3596 ASTContext &ASTCtx) { 3597 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3598 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3599 3600 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3601 ASSERT_THAT(BarDecl, NotNull()); 3602 3603 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3604 ASSERT_THAT(BazDecl, NotNull()); 3605 3606 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 3607 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 3608 EXPECT_EQ(BarVal, BazVal); 3609 }); 3610 } 3611 3612 TEST(TransferTest, StaticMemberRefVarDecl) { 3613 std::string Code = R"( 3614 struct A { 3615 static int &Foo; 3616 }; 3617 3618 void target(A a) { 3619 int Bar = a.Foo; 3620 int Baz = a.Foo; 3621 // [[p]] 3622 } 3623 )"; 3624 runDataflow( 3625 Code, 3626 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3627 ASTContext &ASTCtx) { 3628 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3629 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3630 3631 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3632 ASSERT_THAT(BarDecl, NotNull()); 3633 3634 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3635 ASSERT_THAT(BazDecl, NotNull()); 3636 3637 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 3638 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 3639 EXPECT_EQ(BarVal, BazVal); 3640 }); 3641 } 3642 3643 TEST(TransferTest, AssignMemberBeforeCopy) { 3644 std::string Code = R"( 3645 struct A { 3646 int Foo; 3647 }; 3648 3649 void target() { 3650 A A1; 3651 A A2; 3652 int Bar; 3653 A1.Foo = Bar; 3654 A2 = A1; 3655 // [[p]] 3656 } 3657 )"; 3658 runDataflow( 3659 Code, 3660 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3661 ASTContext &ASTCtx) { 3662 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3663 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3664 3665 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3666 ASSERT_THAT(FooDecl, NotNull()); 3667 3668 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3669 ASSERT_THAT(BarDecl, NotNull()); 3670 3671 const ValueDecl *A1Decl = findValueDecl(ASTCtx, "A1"); 3672 ASSERT_THAT(A1Decl, NotNull()); 3673 3674 const ValueDecl *A2Decl = findValueDecl(ASTCtx, "A2"); 3675 ASSERT_THAT(A2Decl, NotNull()); 3676 3677 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 3678 3679 const auto &A2Loc = 3680 *cast<RecordStorageLocation>(Env.getStorageLocation(*A2Decl)); 3681 EXPECT_EQ(getFieldValue(&A2Loc, *FooDecl, Env), BarVal); 3682 }); 3683 } 3684 3685 TEST(TransferTest, BooleanEquality) { 3686 std::string Code = R"( 3687 void target(bool Bar) { 3688 bool Foo = true; 3689 if (Bar == Foo) { 3690 (void)0; 3691 /*[[p-then]]*/ 3692 } else { 3693 (void)0; 3694 /*[[p-else]]*/ 3695 } 3696 } 3697 )"; 3698 runDataflow( 3699 Code, 3700 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3701 ASTContext &ASTCtx) { 3702 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else")); 3703 const Environment &EnvThen = 3704 getEnvironmentAtAnnotation(Results, "p-then"); 3705 const Environment &EnvElse = 3706 getEnvironmentAtAnnotation(Results, "p-else"); 3707 3708 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3709 ASSERT_THAT(BarDecl, NotNull()); 3710 3711 auto &BarValThen = getFormula(*BarDecl, EnvThen); 3712 EXPECT_TRUE(EnvThen.flowConditionImplies(BarValThen)); 3713 3714 auto &BarValElse = getFormula(*BarDecl, EnvElse); 3715 EXPECT_TRUE( 3716 EnvElse.flowConditionImplies(EnvElse.arena().makeNot(BarValElse))); 3717 }); 3718 } 3719 3720 TEST(TransferTest, BooleanInequality) { 3721 std::string Code = R"( 3722 void target(bool Bar) { 3723 bool Foo = true; 3724 if (Bar != Foo) { 3725 (void)0; 3726 /*[[p-then]]*/ 3727 } else { 3728 (void)0; 3729 /*[[p-else]]*/ 3730 } 3731 } 3732 )"; 3733 runDataflow( 3734 Code, 3735 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3736 ASTContext &ASTCtx) { 3737 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else")); 3738 const Environment &EnvThen = 3739 getEnvironmentAtAnnotation(Results, "p-then"); 3740 const Environment &EnvElse = 3741 getEnvironmentAtAnnotation(Results, "p-else"); 3742 3743 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3744 ASSERT_THAT(BarDecl, NotNull()); 3745 3746 auto &BarValThen = getFormula(*BarDecl, EnvThen); 3747 EXPECT_TRUE( 3748 EnvThen.flowConditionImplies(EnvThen.arena().makeNot(BarValThen))); 3749 3750 auto &BarValElse = getFormula(*BarDecl, EnvElse); 3751 EXPECT_TRUE(EnvElse.flowConditionImplies(BarValElse)); 3752 }); 3753 } 3754 3755 TEST(TransferTest, IntegerLiteralEquality) { 3756 std::string Code = R"( 3757 void target() { 3758 bool equal = (42 == 42); 3759 // [[p]] 3760 } 3761 )"; 3762 runDataflow( 3763 Code, 3764 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3765 ASTContext &ASTCtx) { 3766 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3767 3768 auto &Equal = 3769 getValueForDecl<BoolValue>(ASTCtx, Env, "equal").formula(); 3770 EXPECT_TRUE(Env.flowConditionImplies(Equal)); 3771 }); 3772 } 3773 3774 TEST(TransferTest, CorrelatedBranches) { 3775 std::string Code = R"( 3776 void target(bool B, bool C) { 3777 if (B) { 3778 return; 3779 } 3780 (void)0; 3781 /*[[p0]]*/ 3782 if (C) { 3783 B = true; 3784 /*[[p1]]*/ 3785 } 3786 if (B) { 3787 (void)0; 3788 /*[[p2]]*/ 3789 } 3790 } 3791 )"; 3792 runDataflow( 3793 Code, 3794 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3795 ASTContext &ASTCtx) { 3796 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p0", "p1", "p2")); 3797 3798 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C"); 3799 ASSERT_THAT(CDecl, NotNull()); 3800 3801 { 3802 const Environment &Env = getEnvironmentAtAnnotation(Results, "p0"); 3803 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B"); 3804 ASSERT_THAT(BDecl, NotNull()); 3805 auto &BVal = getFormula(*BDecl, Env); 3806 3807 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(BVal))); 3808 } 3809 3810 { 3811 const Environment &Env = getEnvironmentAtAnnotation(Results, "p1"); 3812 auto &CVal = getFormula(*CDecl, Env); 3813 EXPECT_TRUE(Env.flowConditionImplies(CVal)); 3814 } 3815 3816 { 3817 const Environment &Env = getEnvironmentAtAnnotation(Results, "p2"); 3818 auto &CVal = getFormula(*CDecl, Env); 3819 EXPECT_TRUE(Env.flowConditionImplies(CVal)); 3820 } 3821 }); 3822 } 3823 3824 TEST(TransferTest, LoopWithAssignmentConverges) { 3825 std::string Code = R"( 3826 bool foo(); 3827 3828 void target() { 3829 do { 3830 bool Bar = foo(); 3831 if (Bar) break; 3832 (void)Bar; 3833 /*[[p]]*/ 3834 } while (true); 3835 } 3836 )"; 3837 // The key property that we are verifying is implicit in `runDataflow` -- 3838 // namely, that the analysis succeeds, rather than hitting the maximum number 3839 // of iterations. 3840 runDataflow( 3841 Code, 3842 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3843 ASTContext &ASTCtx) { 3844 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3845 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3846 3847 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3848 ASSERT_THAT(BarDecl, NotNull()); 3849 3850 auto &BarVal = getFormula(*BarDecl, Env); 3851 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(BarVal))); 3852 }); 3853 } 3854 3855 TEST(TransferTest, LoopWithStagedAssignments) { 3856 std::string Code = R"( 3857 bool foo(); 3858 3859 void target() { 3860 bool Bar = false; 3861 bool Err = false; 3862 while (foo()) { 3863 if (Bar) 3864 Err = true; 3865 Bar = true; 3866 /*[[p]]*/ 3867 } 3868 } 3869 )"; 3870 runDataflow( 3871 Code, 3872 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3873 ASTContext &ASTCtx) { 3874 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3875 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3876 3877 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3878 ASSERT_THAT(BarDecl, NotNull()); 3879 const ValueDecl *ErrDecl = findValueDecl(ASTCtx, "Err"); 3880 ASSERT_THAT(ErrDecl, NotNull()); 3881 3882 auto &BarVal = getFormula(*BarDecl, Env); 3883 auto &ErrVal = getFormula(*ErrDecl, Env); 3884 EXPECT_TRUE(Env.flowConditionImplies(BarVal)); 3885 // An unsound analysis, for example only evaluating the loop once, can 3886 // conclude that `Err` is false. So, we test that this conclusion is not 3887 // reached. 3888 EXPECT_FALSE( 3889 Env.flowConditionImplies(Env.arena().makeNot(ErrVal))); 3890 }); 3891 } 3892 3893 TEST(TransferTest, LoopWithReferenceAssignmentConverges) { 3894 std::string Code = R"( 3895 bool &foo(); 3896 3897 void target() { 3898 do { 3899 bool& Bar = foo(); 3900 if (Bar) break; 3901 (void)Bar; 3902 /*[[p]]*/ 3903 } while (true); 3904 } 3905 )"; 3906 // The key property that we are verifying is that the analysis succeeds, 3907 // rather than hitting the maximum number of iterations. 3908 runDataflow( 3909 Code, 3910 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3911 ASTContext &ASTCtx) { 3912 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3913 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3914 3915 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3916 ASSERT_THAT(BarDecl, NotNull()); 3917 3918 auto &BarVal = getFormula(*BarDecl, Env); 3919 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(BarVal))); 3920 }); 3921 } 3922 3923 TEST(TransferTest, LoopWithStructReferenceAssignmentConverges) { 3924 std::string Code = R"( 3925 struct Lookup { 3926 int x; 3927 }; 3928 3929 void target(Lookup val, bool b) { 3930 const Lookup* l = nullptr; 3931 while (b) { 3932 l = &val; 3933 /*[[p-inner]]*/ 3934 } 3935 (void)0; 3936 /*[[p-outer]]*/ 3937 } 3938 )"; 3939 // The key property that we are verifying is implicit in `runDataflow` -- 3940 // namely, that the analysis succeeds, rather than hitting the maximum number 3941 // of iterations. 3942 runDataflow( 3943 Code, 3944 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3945 ASTContext &ASTCtx) { 3946 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-inner", "p-outer")); 3947 const Environment &InnerEnv = 3948 getEnvironmentAtAnnotation(Results, "p-inner"); 3949 const Environment &OuterEnv = 3950 getEnvironmentAtAnnotation(Results, "p-outer"); 3951 3952 const ValueDecl *ValDecl = findValueDecl(ASTCtx, "val"); 3953 ASSERT_THAT(ValDecl, NotNull()); 3954 3955 const ValueDecl *LDecl = findValueDecl(ASTCtx, "l"); 3956 ASSERT_THAT(LDecl, NotNull()); 3957 3958 // Inner. 3959 auto *LVal = dyn_cast<PointerValue>(InnerEnv.getValue(*LDecl)); 3960 ASSERT_THAT(LVal, NotNull()); 3961 3962 EXPECT_EQ(&LVal->getPointeeLoc(), 3963 InnerEnv.getStorageLocation(*ValDecl)); 3964 3965 // Outer. 3966 LVal = dyn_cast<PointerValue>(OuterEnv.getValue(*LDecl)); 3967 ASSERT_THAT(LVal, NotNull()); 3968 3969 // The loop body may not have been executed, so we should not conclude 3970 // that `l` points to `val`. 3971 EXPECT_NE(&LVal->getPointeeLoc(), 3972 OuterEnv.getStorageLocation(*ValDecl)); 3973 }); 3974 } 3975 3976 TEST(TransferTest, LoopDereferencingChangingPointerConverges) { 3977 std::string Code = R"cc( 3978 bool some_condition(); 3979 3980 void target(int i1, int i2) { 3981 int *p = &i1; 3982 while (true) { 3983 (void)*p; 3984 if (some_condition()) 3985 p = &i1; 3986 else 3987 p = &i2; 3988 } 3989 } 3990 )cc"; 3991 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 3992 } 3993 3994 TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) { 3995 std::string Code = R"cc( 3996 struct Lookup { 3997 int x; 3998 }; 3999 4000 bool some_condition(); 4001 4002 void target(Lookup l1, Lookup l2) { 4003 Lookup *l = &l1; 4004 while (true) { 4005 (void)l->x; 4006 if (some_condition()) 4007 l = &l1; 4008 else 4009 l = &l2; 4010 } 4011 } 4012 )cc"; 4013 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 4014 } 4015 4016 TEST(TransferTest, DoesNotCrashOnUnionThisExpr) { 4017 std::string Code = R"( 4018 union Union { 4019 int A; 4020 float B; 4021 }; 4022 4023 void foo() { 4024 Union A; 4025 Union B; 4026 A = B; 4027 } 4028 )"; 4029 // This is a crash regression test when calling the transfer function on a 4030 // `CXXThisExpr` that refers to a union. 4031 runDataflow( 4032 Code, 4033 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &, 4034 ASTContext &) {}, 4035 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator="); 4036 } 4037 4038 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToRefs) { 4039 std::string Code = R"( 4040 struct A { 4041 int Foo; 4042 int Bar; 4043 }; 4044 4045 void target() { 4046 int Qux; 4047 A Baz; 4048 Baz.Foo = Qux; 4049 auto &FooRef = Baz.Foo; 4050 auto &BarRef = Baz.Bar; 4051 auto &[BoundFooRef, BoundBarRef] = Baz; 4052 // [[p]] 4053 } 4054 )"; 4055 runDataflow( 4056 Code, 4057 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4058 ASTContext &ASTCtx) { 4059 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4060 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4061 4062 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 4063 ASSERT_THAT(FooRefDecl, NotNull()); 4064 4065 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 4066 ASSERT_THAT(BarRefDecl, NotNull()); 4067 4068 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4069 ASSERT_THAT(QuxDecl, NotNull()); 4070 4071 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef"); 4072 ASSERT_THAT(BoundFooRefDecl, NotNull()); 4073 4074 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef"); 4075 ASSERT_THAT(BoundBarRefDecl, NotNull()); 4076 4077 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 4078 ASSERT_THAT(FooRefLoc, NotNull()); 4079 4080 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 4081 ASSERT_THAT(BarRefLoc, NotNull()); 4082 4083 const Value *QuxVal = Env.getValue(*QuxDecl); 4084 ASSERT_THAT(QuxVal, NotNull()); 4085 4086 const StorageLocation *BoundFooRefLoc = 4087 Env.getStorageLocation(*BoundFooRefDecl); 4088 EXPECT_EQ(BoundFooRefLoc, FooRefLoc); 4089 4090 const StorageLocation *BoundBarRefLoc = 4091 Env.getStorageLocation(*BoundBarRefDecl); 4092 EXPECT_EQ(BoundBarRefLoc, BarRefLoc); 4093 4094 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal); 4095 }); 4096 } 4097 4098 TEST(TransferTest, StructuredBindingAssignFromStructRefMembersToRefs) { 4099 std::string Code = R"( 4100 struct A { 4101 int &Foo; 4102 int &Bar; 4103 }; 4104 4105 void target(A Baz) { 4106 int Qux; 4107 Baz.Foo = Qux; 4108 auto &FooRef = Baz.Foo; 4109 auto &BarRef = Baz.Bar; 4110 auto &[BoundFooRef, BoundBarRef] = Baz; 4111 // [[p]] 4112 } 4113 )"; 4114 runDataflow( 4115 Code, 4116 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4117 ASTContext &ASTCtx) { 4118 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4119 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4120 4121 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 4122 ASSERT_THAT(FooRefDecl, NotNull()); 4123 4124 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 4125 ASSERT_THAT(BarRefDecl, NotNull()); 4126 4127 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4128 ASSERT_THAT(QuxDecl, NotNull()); 4129 4130 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef"); 4131 ASSERT_THAT(BoundFooRefDecl, NotNull()); 4132 4133 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef"); 4134 ASSERT_THAT(BoundBarRefDecl, NotNull()); 4135 4136 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 4137 ASSERT_THAT(FooRefLoc, NotNull()); 4138 4139 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 4140 ASSERT_THAT(BarRefLoc, NotNull()); 4141 4142 const Value *QuxVal = Env.getValue(*QuxDecl); 4143 ASSERT_THAT(QuxVal, NotNull()); 4144 4145 const StorageLocation *BoundFooRefLoc = 4146 Env.getStorageLocation(*BoundFooRefDecl); 4147 EXPECT_EQ(BoundFooRefLoc, FooRefLoc); 4148 4149 const StorageLocation *BoundBarRefLoc = 4150 Env.getStorageLocation(*BoundBarRefDecl); 4151 EXPECT_EQ(BoundBarRefLoc, BarRefLoc); 4152 4153 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal); 4154 }); 4155 } 4156 4157 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToInts) { 4158 std::string Code = R"( 4159 struct A { 4160 int Foo; 4161 int Bar; 4162 }; 4163 4164 void target() { 4165 int Qux; 4166 A Baz; 4167 Baz.Foo = Qux; 4168 auto &FooRef = Baz.Foo; 4169 auto &BarRef = Baz.Bar; 4170 auto [BoundFoo, BoundBar] = Baz; 4171 // [[p]] 4172 } 4173 )"; 4174 runDataflow( 4175 Code, 4176 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4177 ASTContext &ASTCtx) { 4178 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4179 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4180 4181 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 4182 ASSERT_THAT(FooRefDecl, NotNull()); 4183 4184 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 4185 ASSERT_THAT(BarRefDecl, NotNull()); 4186 4187 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 4188 ASSERT_THAT(BoundFooDecl, NotNull()); 4189 4190 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 4191 ASSERT_THAT(BoundBarDecl, NotNull()); 4192 4193 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4194 ASSERT_THAT(QuxDecl, NotNull()); 4195 4196 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 4197 ASSERT_THAT(FooRefLoc, NotNull()); 4198 4199 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 4200 ASSERT_THAT(BarRefLoc, NotNull()); 4201 4202 const Value *QuxVal = Env.getValue(*QuxDecl); 4203 ASSERT_THAT(QuxVal, NotNull()); 4204 4205 const StorageLocation *BoundFooLoc = 4206 Env.getStorageLocation(*BoundFooDecl); 4207 EXPECT_NE(BoundFooLoc, FooRefLoc); 4208 4209 const StorageLocation *BoundBarLoc = 4210 Env.getStorageLocation(*BoundBarDecl); 4211 EXPECT_NE(BoundBarLoc, BarRefLoc); 4212 4213 EXPECT_EQ(Env.getValue(*BoundFooDecl), QuxVal); 4214 }); 4215 } 4216 4217 TEST(TransferTest, StructuredBindingAssignFromTupleLikeType) { 4218 std::string Code = R"( 4219 namespace std { 4220 using size_t = int; 4221 template <class> struct tuple_size; 4222 template <std::size_t, class> struct tuple_element; 4223 template <class...> class tuple; 4224 4225 namespace { 4226 template <class T, T v> 4227 struct size_helper { static const T value = v; }; 4228 } // namespace 4229 4230 template <class... T> 4231 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {}; 4232 4233 template <std::size_t I, class... T> 4234 struct tuple_element<I, tuple<T...>> { 4235 using type = __type_pack_element<I, T...>; 4236 }; 4237 4238 template <class...> class tuple {}; 4239 4240 template <std::size_t I, class... T> 4241 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 4242 } // namespace std 4243 4244 std::tuple<bool, int> makeTuple(); 4245 4246 void target(bool B) { 4247 auto [BoundFoo, BoundBar] = makeTuple(); 4248 bool Baz; 4249 // Include if-then-else to test interaction of `BindingDecl` with join. 4250 if (B) { 4251 Baz = BoundFoo; 4252 (void)BoundBar; 4253 // [[p1]] 4254 } else { 4255 Baz = BoundFoo; 4256 } 4257 (void)0; 4258 // [[p2]] 4259 } 4260 )"; 4261 runDataflow( 4262 Code, 4263 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4264 ASTContext &ASTCtx) { 4265 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 4266 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 4267 4268 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 4269 ASSERT_THAT(BoundFooDecl, NotNull()); 4270 4271 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 4272 ASSERT_THAT(BoundBarDecl, NotNull()); 4273 4274 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4275 ASSERT_THAT(BazDecl, NotNull()); 4276 4277 // BindingDecls always map to references -- either lvalue or rvalue, so 4278 // we still need to skip here. 4279 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl); 4280 ASSERT_THAT(BoundFooValue, NotNull()); 4281 EXPECT_TRUE(isa<BoolValue>(BoundFooValue)); 4282 4283 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl); 4284 ASSERT_THAT(BoundBarValue, NotNull()); 4285 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue)); 4286 4287 // Test that a `DeclRefExpr` to a `BindingDecl` works as expected. 4288 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue); 4289 4290 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 4291 4292 // Test that `BoundFooDecl` retains the value we expect, after the join. 4293 BoundFooValue = Env2.getValue(*BoundFooDecl); 4294 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue); 4295 }); 4296 } 4297 4298 TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) { 4299 std::string Code = R"( 4300 namespace std { 4301 using size_t = int; 4302 template <class> struct tuple_size; 4303 template <std::size_t, class> struct tuple_element; 4304 template <class...> class tuple; 4305 4306 namespace { 4307 template <class T, T v> 4308 struct size_helper { static const T value = v; }; 4309 } // namespace 4310 4311 template <class... T> 4312 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {}; 4313 4314 template <std::size_t I, class... T> 4315 struct tuple_element<I, tuple<T...>> { 4316 using type = __type_pack_element<I, T...>; 4317 }; 4318 4319 template <class...> class tuple {}; 4320 4321 template <std::size_t I, class... T> 4322 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 4323 } // namespace std 4324 4325 std::tuple<bool, int> &getTuple(); 4326 4327 void target(bool B) { 4328 auto &[BoundFoo, BoundBar] = getTuple(); 4329 bool Baz; 4330 // Include if-then-else to test interaction of `BindingDecl` with join. 4331 if (B) { 4332 Baz = BoundFoo; 4333 (void)BoundBar; 4334 // [[p1]] 4335 } else { 4336 Baz = BoundFoo; 4337 } 4338 (void)0; 4339 // [[p2]] 4340 } 4341 )"; 4342 runDataflow( 4343 Code, 4344 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4345 ASTContext &ASTCtx) { 4346 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 4347 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 4348 4349 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 4350 ASSERT_THAT(BoundFooDecl, NotNull()); 4351 4352 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 4353 ASSERT_THAT(BoundBarDecl, NotNull()); 4354 4355 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4356 ASSERT_THAT(BazDecl, NotNull()); 4357 4358 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl); 4359 ASSERT_THAT(BoundFooValue, NotNull()); 4360 EXPECT_TRUE(isa<BoolValue>(BoundFooValue)); 4361 4362 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl); 4363 ASSERT_THAT(BoundBarValue, NotNull()); 4364 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue)); 4365 4366 // Test that a `DeclRefExpr` to a `BindingDecl` (with reference type) 4367 // works as expected. We don't test aliasing properties of the 4368 // reference, because we don't model `std::get` and so have no way to 4369 // equate separate references into the tuple. 4370 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue); 4371 4372 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 4373 4374 // Test that `BoundFooDecl` retains the value we expect, after the join. 4375 BoundFooValue = Env2.getValue(*BoundFooDecl); 4376 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue); 4377 }); 4378 } 4379 4380 TEST(TransferTest, BinaryOperatorComma) { 4381 std::string Code = R"( 4382 void target(int Foo, int Bar) { 4383 int &Baz = (Foo, Bar); 4384 // [[p]] 4385 } 4386 )"; 4387 runDataflow( 4388 Code, 4389 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4390 ASTContext &ASTCtx) { 4391 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4392 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4393 4394 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4395 ASSERT_THAT(BarDecl, NotNull()); 4396 4397 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4398 ASSERT_THAT(BazDecl, NotNull()); 4399 4400 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 4401 ASSERT_THAT(BarLoc, NotNull()); 4402 4403 const StorageLocation *BazLoc = Env.getStorageLocation(*BazDecl); 4404 EXPECT_EQ(BazLoc, BarLoc); 4405 }); 4406 } 4407 4408 TEST(TransferTest, IfStmtBranchExtendsFlowCondition) { 4409 std::string Code = R"( 4410 void target(bool Foo) { 4411 if (Foo) { 4412 (void)0; 4413 // [[if_then]] 4414 } else { 4415 (void)0; 4416 // [[if_else]] 4417 } 4418 } 4419 )"; 4420 runDataflow( 4421 Code, 4422 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4423 ASTContext &ASTCtx) { 4424 ASSERT_THAT(Results.keys(), UnorderedElementsAre("if_then", "if_else")); 4425 const Environment &ThenEnv = 4426 getEnvironmentAtAnnotation(Results, "if_then"); 4427 const Environment &ElseEnv = 4428 getEnvironmentAtAnnotation(Results, "if_else"); 4429 4430 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4431 ASSERT_THAT(FooDecl, NotNull()); 4432 4433 auto &ThenFooVal= getFormula(*FooDecl, ThenEnv); 4434 EXPECT_TRUE(ThenEnv.flowConditionImplies(ThenFooVal)); 4435 4436 auto &ElseFooVal = getFormula(*FooDecl, ElseEnv); 4437 EXPECT_TRUE( 4438 ElseEnv.flowConditionImplies(ElseEnv.arena().makeNot(ElseFooVal))); 4439 }); 4440 } 4441 4442 TEST(TransferTest, WhileStmtBranchExtendsFlowCondition) { 4443 std::string Code = R"( 4444 void target(bool Foo) { 4445 while (Foo) { 4446 (void)0; 4447 // [[loop_body]] 4448 } 4449 (void)0; 4450 // [[after_loop]] 4451 } 4452 )"; 4453 runDataflow( 4454 Code, 4455 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4456 ASTContext &ASTCtx) { 4457 ASSERT_THAT(Results.keys(), 4458 UnorderedElementsAre("loop_body", "after_loop")); 4459 const Environment &LoopBodyEnv = 4460 getEnvironmentAtAnnotation(Results, "loop_body"); 4461 const Environment &AfterLoopEnv = 4462 getEnvironmentAtAnnotation(Results, "after_loop"); 4463 4464 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4465 ASSERT_THAT(FooDecl, NotNull()); 4466 4467 auto &LoopBodyFooVal = getFormula(*FooDecl, LoopBodyEnv); 4468 EXPECT_TRUE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal)); 4469 4470 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 4471 EXPECT_TRUE(AfterLoopEnv.flowConditionImplies( 4472 AfterLoopEnv.arena().makeNot(AfterLoopFooVal))); 4473 }); 4474 } 4475 4476 TEST(TransferTest, DoWhileStmtBranchExtendsFlowCondition) { 4477 std::string Code = R"( 4478 void target(bool Foo) { 4479 bool Bar = true; 4480 do { 4481 (void)0; 4482 // [[loop_body]] 4483 Bar = false; 4484 } while (Foo); 4485 (void)0; 4486 // [[after_loop]] 4487 } 4488 )"; 4489 runDataflow( 4490 Code, 4491 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4492 ASTContext &ASTCtx) { 4493 ASSERT_THAT(Results.keys(), 4494 UnorderedElementsAre("loop_body", "after_loop")); 4495 const Environment &LoopBodyEnv = 4496 getEnvironmentAtAnnotation(Results, "loop_body"); 4497 const Environment &AfterLoopEnv = 4498 getEnvironmentAtAnnotation(Results, "after_loop"); 4499 auto &A = AfterLoopEnv.arena(); 4500 4501 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4502 ASSERT_THAT(FooDecl, NotNull()); 4503 4504 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4505 ASSERT_THAT(BarDecl, NotNull()); 4506 4507 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 4508 auto &LoopBodyBarVal = getFormula(*BarDecl, LoopBodyEnv); 4509 EXPECT_TRUE(LoopBodyEnv.flowConditionImplies( 4510 A.makeOr(LoopBodyBarVal, LoopBodyFooVal))); 4511 4512 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 4513 auto &AfterLoopBarVal = getFormula(*BarDecl, AfterLoopEnv); 4514 EXPECT_TRUE( 4515 AfterLoopEnv.flowConditionImplies(A.makeNot(AfterLoopFooVal))); 4516 EXPECT_TRUE( 4517 AfterLoopEnv.flowConditionImplies(A.makeNot(AfterLoopBarVal))); 4518 }); 4519 } 4520 4521 TEST(TransferTest, ForStmtBranchExtendsFlowCondition) { 4522 std::string Code = R"( 4523 void target(bool Foo) { 4524 for (; Foo;) { 4525 (void)0; 4526 // [[loop_body]] 4527 } 4528 (void)0; 4529 // [[after_loop]] 4530 } 4531 )"; 4532 runDataflow( 4533 Code, 4534 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4535 ASTContext &ASTCtx) { 4536 ASSERT_THAT(Results.keys(), 4537 UnorderedElementsAre("loop_body", "after_loop")); 4538 const Environment &LoopBodyEnv = 4539 getEnvironmentAtAnnotation(Results, "loop_body"); 4540 const Environment &AfterLoopEnv = 4541 getEnvironmentAtAnnotation(Results, "after_loop"); 4542 4543 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4544 ASSERT_THAT(FooDecl, NotNull()); 4545 4546 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 4547 EXPECT_TRUE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal)); 4548 4549 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 4550 EXPECT_TRUE(AfterLoopEnv.flowConditionImplies( 4551 AfterLoopEnv.arena().makeNot(AfterLoopFooVal))); 4552 }); 4553 } 4554 4555 TEST(TransferTest, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition) { 4556 std::string Code = R"( 4557 void target(bool Foo) { 4558 for (;;) { 4559 (void)0; 4560 // [[loop_body]] 4561 } 4562 } 4563 )"; 4564 runDataflow( 4565 Code, 4566 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4567 ASTContext &ASTCtx) { 4568 ASSERT_THAT(Results.keys(), UnorderedElementsAre("loop_body")); 4569 const Environment &LoopBodyEnv = 4570 getEnvironmentAtAnnotation(Results, "loop_body"); 4571 4572 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4573 ASSERT_THAT(FooDecl, NotNull()); 4574 4575 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 4576 EXPECT_FALSE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal)); 4577 }); 4578 } 4579 4580 TEST(TransferTest, ContextSensitiveOptionDisabled) { 4581 std::string Code = R"( 4582 bool GiveBool(); 4583 void SetBool(bool &Var) { Var = true; } 4584 4585 void target() { 4586 bool Foo = GiveBool(); 4587 SetBool(Foo); 4588 // [[p]] 4589 } 4590 )"; 4591 runDataflow( 4592 Code, 4593 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4594 ASTContext &ASTCtx) { 4595 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4596 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4597 4598 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4599 ASSERT_THAT(FooDecl, NotNull()); 4600 4601 auto &FooVal = getFormula(*FooDecl, Env); 4602 EXPECT_FALSE(Env.flowConditionImplies(FooVal)); 4603 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(FooVal))); 4604 }, 4605 {BuiltinOptions{/*.ContextSensitiveOpts=*/std::nullopt}}); 4606 } 4607 4608 TEST(TransferTest, ContextSensitiveReturnReference) { 4609 std::string Code = R"( 4610 class S {}; 4611 S& target(bool b, S &s) { 4612 return s; 4613 // [[p]] 4614 } 4615 )"; 4616 runDataflow( 4617 Code, 4618 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4619 ASTContext &ASTCtx) { 4620 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4621 4622 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 4623 ASSERT_THAT(SDecl, NotNull()); 4624 4625 auto *SLoc = Env.getStorageLocation(*SDecl); 4626 ASSERT_THAT(SLoc, NotNull()); 4627 4628 ASSERT_THAT(Env.getReturnStorageLocation(), Eq(SLoc)); 4629 }, 4630 {BuiltinOptions{ContextSensitiveOptions{}}}); 4631 } 4632 4633 // This test is a regression test, based on a real crash. 4634 TEST(TransferTest, ContextSensitiveReturnReferenceWithConditionalOperator) { 4635 std::string Code = R"( 4636 class S {}; 4637 S& target(bool b, S &s) { 4638 return b ? s : s; 4639 // [[p]] 4640 } 4641 )"; 4642 runDataflow( 4643 Code, 4644 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4645 ASTContext &ASTCtx) { 4646 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4647 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4648 4649 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 4650 ASSERT_THAT(SDecl, NotNull()); 4651 4652 auto *SLoc = Env.getStorageLocation(*SDecl); 4653 ASSERT_THAT(SLoc, NotNull()); 4654 EXPECT_THAT(Env.getValue(*SLoc), NotNull()); 4655 4656 auto *Loc = Env.getReturnStorageLocation(); 4657 ASSERT_THAT(Loc, NotNull()); 4658 EXPECT_THAT(Env.getValue(*Loc), NotNull()); 4659 4660 // TODO: We would really like to make this stronger assertion, but that 4661 // doesn't work because we don't propagate values correctly through 4662 // the conditional operator yet. 4663 // ASSERT_THAT(Loc, Eq(SLoc)); 4664 }, 4665 {BuiltinOptions{ContextSensitiveOptions{}}}); 4666 } 4667 4668 TEST(TransferTest, ContextSensitiveReturnOneOfTwoReferences) { 4669 std::string Code = R"( 4670 class S {}; 4671 S &callee(bool b, S &s1_parm, S &s2_parm) { 4672 if (b) 4673 return s1_parm; 4674 else 4675 return s2_parm; 4676 } 4677 void target(bool b) { 4678 S s1; 4679 S s2; 4680 S &return_s1 = s1; 4681 S &return_s2 = s2; 4682 S &return_dont_know = callee(b, s1, s2); 4683 // [[p]] 4684 } 4685 )"; 4686 runDataflow( 4687 Code, 4688 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4689 ASTContext &ASTCtx) { 4690 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4691 4692 const ValueDecl *S1 = findValueDecl(ASTCtx, "s1"); 4693 ASSERT_THAT(S1, NotNull()); 4694 const ValueDecl *S2 = findValueDecl(ASTCtx, "s2"); 4695 ASSERT_THAT(S2, NotNull()); 4696 const ValueDecl *ReturnS1 = findValueDecl(ASTCtx, "return_s1"); 4697 ASSERT_THAT(ReturnS1, NotNull()); 4698 const ValueDecl *ReturnS2 = findValueDecl(ASTCtx, "return_s2"); 4699 ASSERT_THAT(ReturnS2, NotNull()); 4700 const ValueDecl *ReturnDontKnow = 4701 findValueDecl(ASTCtx, "return_dont_know"); 4702 ASSERT_THAT(ReturnDontKnow, NotNull()); 4703 4704 StorageLocation *S1Loc = Env.getStorageLocation(*S1); 4705 StorageLocation *S2Loc = Env.getStorageLocation(*S2); 4706 4707 EXPECT_THAT(Env.getStorageLocation(*ReturnS1), Eq(S1Loc)); 4708 EXPECT_THAT(Env.getStorageLocation(*ReturnS2), Eq(S2Loc)); 4709 4710 // In the case where we don't have a consistent storage location for 4711 // the return value, the framework creates a new storage location, which 4712 // should be different from the storage locations of `s1` and `s2`. 4713 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S1Loc)); 4714 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S2Loc)); 4715 }, 4716 {BuiltinOptions{ContextSensitiveOptions{}}}); 4717 } 4718 4719 TEST(TransferTest, ContextSensitiveDepthZero) { 4720 std::string Code = R"( 4721 bool GiveBool(); 4722 void SetBool(bool &Var) { Var = true; } 4723 4724 void target() { 4725 bool Foo = GiveBool(); 4726 SetBool(Foo); 4727 // [[p]] 4728 } 4729 )"; 4730 runDataflow( 4731 Code, 4732 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4733 ASTContext &ASTCtx) { 4734 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4735 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4736 4737 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4738 ASSERT_THAT(FooDecl, NotNull()); 4739 4740 auto &FooVal = getFormula(*FooDecl, Env); 4741 EXPECT_FALSE(Env.flowConditionImplies(FooVal)); 4742 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(FooVal))); 4743 }, 4744 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/0}}}); 4745 } 4746 4747 TEST(TransferTest, ContextSensitiveSetTrue) { 4748 std::string Code = R"( 4749 bool GiveBool(); 4750 void SetBool(bool &Var) { Var = true; } 4751 4752 void target() { 4753 bool Foo = GiveBool(); 4754 SetBool(Foo); 4755 // [[p]] 4756 } 4757 )"; 4758 runDataflow( 4759 Code, 4760 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4761 ASTContext &ASTCtx) { 4762 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4763 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4764 4765 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4766 ASSERT_THAT(FooDecl, NotNull()); 4767 4768 auto &FooVal = getFormula(*FooDecl, Env); 4769 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4770 }, 4771 {BuiltinOptions{ContextSensitiveOptions{}}}); 4772 } 4773 4774 TEST(TransferTest, ContextSensitiveSetFalse) { 4775 std::string Code = R"( 4776 bool GiveBool(); 4777 void SetBool(bool &Var) { Var = false; } 4778 4779 void target() { 4780 bool Foo = GiveBool(); 4781 SetBool(Foo); 4782 // [[p]] 4783 } 4784 )"; 4785 runDataflow( 4786 Code, 4787 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4788 ASTContext &ASTCtx) { 4789 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4790 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4791 4792 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4793 ASSERT_THAT(FooDecl, NotNull()); 4794 4795 auto &FooVal = getFormula(*FooDecl, Env); 4796 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(FooVal))); 4797 }, 4798 {BuiltinOptions{ContextSensitiveOptions{}}}); 4799 } 4800 4801 TEST(TransferTest, ContextSensitiveSetBothTrueAndFalse) { 4802 std::string Code = R"( 4803 bool GiveBool(); 4804 void SetBool(bool &Var, bool Val) { Var = Val; } 4805 4806 void target() { 4807 bool Foo = GiveBool(); 4808 bool Bar = GiveBool(); 4809 SetBool(Foo, true); 4810 SetBool(Bar, false); 4811 // [[p]] 4812 } 4813 )"; 4814 runDataflow( 4815 Code, 4816 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4817 ASTContext &ASTCtx) { 4818 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4819 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4820 auto &A = Env.arena(); 4821 4822 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4823 ASSERT_THAT(FooDecl, NotNull()); 4824 4825 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4826 ASSERT_THAT(BarDecl, NotNull()); 4827 4828 auto &FooVal = getFormula(*FooDecl, Env); 4829 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4830 EXPECT_FALSE(Env.flowConditionImplies(A.makeNot(FooVal))); 4831 4832 auto &BarVal = getFormula(*BarDecl, Env); 4833 EXPECT_FALSE(Env.flowConditionImplies(BarVal)); 4834 EXPECT_TRUE(Env.flowConditionImplies(A.makeNot(BarVal))); 4835 }, 4836 {BuiltinOptions{ContextSensitiveOptions{}}}); 4837 } 4838 4839 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthOne) { 4840 std::string Code = R"( 4841 bool GiveBool(); 4842 void SetBool1(bool &Var) { Var = true; } 4843 void SetBool2(bool &Var) { SetBool1(Var); } 4844 4845 void target() { 4846 bool Foo = GiveBool(); 4847 SetBool2(Foo); 4848 // [[p]] 4849 } 4850 )"; 4851 runDataflow( 4852 Code, 4853 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4854 ASTContext &ASTCtx) { 4855 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4856 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4857 4858 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4859 ASSERT_THAT(FooDecl, NotNull()); 4860 4861 auto &FooVal = getFormula(*FooDecl, Env); 4862 EXPECT_FALSE(Env.flowConditionImplies(FooVal)); 4863 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(FooVal))); 4864 }, 4865 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/1}}}); 4866 } 4867 4868 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthTwo) { 4869 std::string Code = R"( 4870 bool GiveBool(); 4871 void SetBool1(bool &Var) { Var = true; } 4872 void SetBool2(bool &Var) { SetBool1(Var); } 4873 4874 void target() { 4875 bool Foo = GiveBool(); 4876 SetBool2(Foo); 4877 // [[p]] 4878 } 4879 )"; 4880 runDataflow( 4881 Code, 4882 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4883 ASTContext &ASTCtx) { 4884 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4885 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4886 4887 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4888 ASSERT_THAT(FooDecl, NotNull()); 4889 4890 auto &FooVal = getFormula(*FooDecl, Env); 4891 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4892 }, 4893 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}}); 4894 } 4895 4896 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthTwo) { 4897 std::string Code = R"( 4898 bool GiveBool(); 4899 void SetBool1(bool &Var) { Var = true; } 4900 void SetBool2(bool &Var) { SetBool1(Var); } 4901 void SetBool3(bool &Var) { SetBool2(Var); } 4902 4903 void target() { 4904 bool Foo = GiveBool(); 4905 SetBool3(Foo); 4906 // [[p]] 4907 } 4908 )"; 4909 runDataflow( 4910 Code, 4911 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4912 ASTContext &ASTCtx) { 4913 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4914 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4915 4916 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4917 ASSERT_THAT(FooDecl, NotNull()); 4918 4919 auto &FooVal = getFormula(*FooDecl, Env); 4920 EXPECT_FALSE(Env.flowConditionImplies(FooVal)); 4921 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(FooVal))); 4922 }, 4923 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}}); 4924 } 4925 4926 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthThree) { 4927 std::string Code = R"( 4928 bool GiveBool(); 4929 void SetBool1(bool &Var) { Var = true; } 4930 void SetBool2(bool &Var) { SetBool1(Var); } 4931 void SetBool3(bool &Var) { SetBool2(Var); } 4932 4933 void target() { 4934 bool Foo = GiveBool(); 4935 SetBool3(Foo); 4936 // [[p]] 4937 } 4938 )"; 4939 runDataflow( 4940 Code, 4941 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4942 ASTContext &ASTCtx) { 4943 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4944 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4945 4946 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4947 ASSERT_THAT(FooDecl, NotNull()); 4948 4949 auto &FooVal = getFormula(*FooDecl, Env); 4950 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4951 }, 4952 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/3}}}); 4953 } 4954 4955 TEST(TransferTest, ContextSensitiveMutualRecursion) { 4956 std::string Code = R"( 4957 bool Pong(bool X, bool Y); 4958 4959 bool Ping(bool X, bool Y) { 4960 if (X) { 4961 return Y; 4962 } else { 4963 return Pong(!X, Y); 4964 } 4965 } 4966 4967 bool Pong(bool X, bool Y) { 4968 if (Y) { 4969 return X; 4970 } else { 4971 return Ping(X, !Y); 4972 } 4973 } 4974 4975 void target() { 4976 bool Foo = Ping(false, false); 4977 // [[p]] 4978 } 4979 )"; 4980 runDataflow( 4981 Code, 4982 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4983 ASTContext &ASTCtx) { 4984 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4985 // The analysis doesn't crash... 4986 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4987 4988 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4989 ASSERT_THAT(FooDecl, NotNull()); 4990 4991 auto &FooVal = getFormula(*FooDecl, Env); 4992 // ... but it also can't prove anything here. 4993 EXPECT_FALSE(Env.flowConditionImplies(FooVal)); 4994 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(FooVal))); 4995 }, 4996 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/4}}}); 4997 } 4998 4999 TEST(TransferTest, ContextSensitiveSetMultipleLines) { 5000 std::string Code = R"( 5001 void SetBools(bool &Var1, bool &Var2) { 5002 Var1 = true; 5003 Var2 = false; 5004 } 5005 5006 void target() { 5007 bool Foo = false; 5008 bool Bar = true; 5009 SetBools(Foo, Bar); 5010 // [[p]] 5011 } 5012 )"; 5013 runDataflow( 5014 Code, 5015 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5016 ASTContext &ASTCtx) { 5017 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5018 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5019 5020 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5021 ASSERT_THAT(FooDecl, NotNull()); 5022 5023 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5024 ASSERT_THAT(BarDecl, NotNull()); 5025 5026 auto &FooVal = getFormula(*FooDecl, Env); 5027 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5028 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(FooVal))); 5029 5030 auto &BarVal = getFormula(*BarDecl, Env); 5031 EXPECT_FALSE(Env.flowConditionImplies(BarVal)); 5032 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(BarVal))); 5033 }, 5034 {BuiltinOptions{ContextSensitiveOptions{}}}); 5035 } 5036 5037 TEST(TransferTest, ContextSensitiveSetMultipleBlocks) { 5038 std::string Code = R"( 5039 void IfCond(bool Cond, bool &Then, bool &Else) { 5040 if (Cond) { 5041 Then = true; 5042 } else { 5043 Else = true; 5044 } 5045 } 5046 5047 void target() { 5048 bool Foo = false; 5049 bool Bar = false; 5050 bool Baz = false; 5051 IfCond(Foo, Bar, Baz); 5052 // [[p]] 5053 } 5054 )"; 5055 runDataflow( 5056 Code, 5057 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5058 ASTContext &ASTCtx) { 5059 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5060 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5061 5062 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5063 ASSERT_THAT(BarDecl, NotNull()); 5064 5065 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5066 ASSERT_THAT(BazDecl, NotNull()); 5067 5068 auto &BarVal = getFormula(*BarDecl, Env); 5069 EXPECT_FALSE(Env.flowConditionImplies(BarVal)); 5070 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(BarVal))); 5071 5072 auto &BazVal = getFormula(*BazDecl, Env); 5073 EXPECT_TRUE(Env.flowConditionImplies(BazVal)); 5074 EXPECT_FALSE(Env.flowConditionImplies(Env.arena().makeNot(BazVal))); 5075 }, 5076 {BuiltinOptions{ContextSensitiveOptions{}}}); 5077 } 5078 5079 TEST(TransferTest, ContextSensitiveReturnVoid) { 5080 std::string Code = R"( 5081 void Noop() { return; } 5082 5083 void target() { 5084 Noop(); 5085 // [[p]] 5086 } 5087 )"; 5088 runDataflow( 5089 Code, 5090 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5091 ASTContext &ASTCtx) { 5092 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5093 // This just tests that the analysis doesn't crash. 5094 }, 5095 {BuiltinOptions{ContextSensitiveOptions{}}}); 5096 } 5097 5098 TEST(TransferTest, ContextSensitiveReturnTrue) { 5099 std::string Code = R"( 5100 bool GiveBool() { return true; } 5101 5102 void target() { 5103 bool Foo = GiveBool(); 5104 // [[p]] 5105 } 5106 )"; 5107 runDataflow( 5108 Code, 5109 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5110 ASTContext &ASTCtx) { 5111 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5112 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5113 5114 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5115 ASSERT_THAT(FooDecl, NotNull()); 5116 5117 auto &FooVal = getFormula(*FooDecl, Env); 5118 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5119 }, 5120 {BuiltinOptions{ContextSensitiveOptions{}}}); 5121 } 5122 5123 TEST(TransferTest, ContextSensitiveReturnFalse) { 5124 std::string Code = R"( 5125 bool GiveBool() { return false; } 5126 5127 void target() { 5128 bool Foo = GiveBool(); 5129 // [[p]] 5130 } 5131 )"; 5132 runDataflow( 5133 Code, 5134 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5135 ASTContext &ASTCtx) { 5136 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5137 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5138 5139 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5140 ASSERT_THAT(FooDecl, NotNull()); 5141 5142 auto &FooVal = getFormula(*FooDecl, Env); 5143 EXPECT_TRUE(Env.flowConditionImplies(Env.arena().makeNot(FooVal))); 5144 }, 5145 {BuiltinOptions{ContextSensitiveOptions{}}}); 5146 } 5147 5148 TEST(TransferTest, ContextSensitiveReturnArg) { 5149 std::string Code = R"( 5150 bool GiveBool(); 5151 bool GiveBack(bool Arg) { return Arg; } 5152 5153 void target() { 5154 bool Foo = GiveBool(); 5155 bool Bar = GiveBack(Foo); 5156 bool Baz = Foo == Bar; 5157 // [[p]] 5158 } 5159 )"; 5160 runDataflow( 5161 Code, 5162 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5163 ASTContext &ASTCtx) { 5164 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5165 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5166 5167 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5168 ASSERT_THAT(BazDecl, NotNull()); 5169 5170 auto &BazVal = getFormula(*BazDecl, Env); 5171 EXPECT_TRUE(Env.flowConditionImplies(BazVal)); 5172 }, 5173 {BuiltinOptions{ContextSensitiveOptions{}}}); 5174 } 5175 5176 TEST(TransferTest, ContextSensitiveReturnInt) { 5177 std::string Code = R"( 5178 int identity(int x) { return x; } 5179 5180 void target() { 5181 int y = identity(42); 5182 // [[p]] 5183 } 5184 )"; 5185 runDataflow( 5186 Code, 5187 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5188 ASTContext &ASTCtx) { 5189 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5190 // This just tests that the analysis doesn't crash. 5191 }, 5192 {BuiltinOptions{ContextSensitiveOptions{}}}); 5193 } 5194 5195 TEST(TransferTest, ContextSensitiveMethodLiteral) { 5196 std::string Code = R"( 5197 class MyClass { 5198 public: 5199 bool giveBool() { return true; } 5200 }; 5201 5202 void target() { 5203 MyClass MyObj; 5204 bool Foo = MyObj.giveBool(); 5205 // [[p]] 5206 } 5207 )"; 5208 runDataflow( 5209 Code, 5210 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5211 ASTContext &ASTCtx) { 5212 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5213 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5214 5215 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5216 ASSERT_THAT(FooDecl, NotNull()); 5217 5218 auto &FooVal = getFormula(*FooDecl, Env); 5219 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5220 }, 5221 {BuiltinOptions{ContextSensitiveOptions{}}}); 5222 } 5223 5224 TEST(TransferTest, ContextSensitiveMethodGetter) { 5225 std::string Code = R"( 5226 class MyClass { 5227 public: 5228 bool getField() { return Field; } 5229 5230 bool Field; 5231 }; 5232 5233 void target() { 5234 MyClass MyObj; 5235 MyObj.Field = true; 5236 bool Foo = MyObj.getField(); 5237 // [[p]] 5238 } 5239 )"; 5240 runDataflow( 5241 Code, 5242 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5243 ASTContext &ASTCtx) { 5244 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5245 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5246 5247 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5248 ASSERT_THAT(FooDecl, NotNull()); 5249 5250 auto &FooVal = getFormula(*FooDecl, Env); 5251 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5252 }, 5253 {BuiltinOptions{ContextSensitiveOptions{}}}); 5254 } 5255 5256 TEST(TransferTest, ContextSensitiveMethodSetter) { 5257 std::string Code = R"( 5258 class MyClass { 5259 public: 5260 void setField(bool Val) { Field = Val; } 5261 5262 bool Field; 5263 }; 5264 5265 void target() { 5266 MyClass MyObj; 5267 MyObj.setField(true); 5268 bool Foo = MyObj.Field; 5269 // [[p]] 5270 } 5271 )"; 5272 runDataflow( 5273 Code, 5274 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5275 ASTContext &ASTCtx) { 5276 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5277 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5278 5279 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5280 ASSERT_THAT(FooDecl, NotNull()); 5281 5282 auto &FooVal = getFormula(*FooDecl, Env); 5283 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5284 }, 5285 {BuiltinOptions{ContextSensitiveOptions{}}}); 5286 } 5287 5288 TEST(TransferTest, ContextSensitiveMethodGetterAndSetter) { 5289 std::string Code = R"( 5290 class MyClass { 5291 public: 5292 bool getField() { return Field; } 5293 void setField(bool Val) { Field = Val; } 5294 5295 private: 5296 bool Field; 5297 }; 5298 5299 void target() { 5300 MyClass MyObj; 5301 MyObj.setField(true); 5302 bool Foo = MyObj.getField(); 5303 // [[p]] 5304 } 5305 )"; 5306 runDataflow( 5307 Code, 5308 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5309 ASTContext &ASTCtx) { 5310 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5311 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5312 5313 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5314 ASSERT_THAT(FooDecl, NotNull()); 5315 5316 auto &FooVal = getFormula(*FooDecl, Env); 5317 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5318 }, 5319 {BuiltinOptions{ContextSensitiveOptions{}}}); 5320 } 5321 5322 5323 TEST(TransferTest, ContextSensitiveMethodTwoLayersVoid) { 5324 std::string Code = R"( 5325 class MyClass { 5326 public: 5327 void Inner() { MyField = true; } 5328 void Outer() { Inner(); } 5329 5330 bool MyField; 5331 }; 5332 5333 void target() { 5334 MyClass MyObj; 5335 MyObj.Outer(); 5336 bool Foo = MyObj.MyField; 5337 // [[p]] 5338 } 5339 )"; 5340 runDataflow( 5341 Code, 5342 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5343 ASTContext &ASTCtx) { 5344 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5345 ; 5346 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5347 5348 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5349 ASSERT_THAT(FooDecl, NotNull()); 5350 5351 auto &FooVal = getFormula(*FooDecl, Env); 5352 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5353 }, 5354 {BuiltinOptions{ContextSensitiveOptions{}}}); 5355 } 5356 5357 TEST(TransferTest, ContextSensitiveMethodTwoLayersReturn) { 5358 std::string Code = R"( 5359 class MyClass { 5360 public: 5361 bool Inner() { return MyField; } 5362 bool Outer() { return Inner(); } 5363 5364 bool MyField; 5365 }; 5366 5367 void target() { 5368 MyClass MyObj; 5369 MyObj.MyField = true; 5370 bool Foo = MyObj.Outer(); 5371 // [[p]] 5372 } 5373 )"; 5374 runDataflow( 5375 Code, 5376 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5377 ASTContext &ASTCtx) { 5378 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5379 ; 5380 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5381 5382 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5383 ASSERT_THAT(FooDecl, NotNull()); 5384 5385 auto &FooVal = getFormula(*FooDecl, Env); 5386 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5387 }, 5388 {BuiltinOptions{ContextSensitiveOptions{}}}); 5389 } 5390 5391 TEST(TransferTest, ContextSensitiveConstructorBody) { 5392 std::string Code = R"( 5393 class MyClass { 5394 public: 5395 MyClass() { MyField = true; } 5396 5397 bool MyField; 5398 }; 5399 5400 void target() { 5401 MyClass MyObj; 5402 bool Foo = MyObj.MyField; 5403 // [[p]] 5404 } 5405 )"; 5406 runDataflow( 5407 Code, 5408 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5409 ASTContext &ASTCtx) { 5410 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5411 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5412 5413 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5414 ASSERT_THAT(FooDecl, NotNull()); 5415 5416 auto &FooVal = getFormula(*FooDecl, Env); 5417 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5418 }, 5419 {BuiltinOptions{ContextSensitiveOptions{}}}); 5420 } 5421 5422 TEST(TransferTest, ContextSensitiveConstructorInitializer) { 5423 std::string Code = R"( 5424 class MyClass { 5425 public: 5426 MyClass() : MyField(true) {} 5427 5428 bool MyField; 5429 }; 5430 5431 void target() { 5432 MyClass MyObj; 5433 bool Foo = MyObj.MyField; 5434 // [[p]] 5435 } 5436 )"; 5437 runDataflow( 5438 Code, 5439 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5440 ASTContext &ASTCtx) { 5441 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5442 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5443 5444 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5445 ASSERT_THAT(FooDecl, NotNull()); 5446 5447 auto &FooVal = getFormula(*FooDecl, Env); 5448 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5449 }, 5450 {BuiltinOptions{ContextSensitiveOptions{}}}); 5451 } 5452 5453 TEST(TransferTest, ContextSensitiveConstructorDefault) { 5454 std::string Code = R"( 5455 class MyClass { 5456 public: 5457 MyClass() = default; 5458 5459 bool MyField = true; 5460 }; 5461 5462 void target() { 5463 MyClass MyObj; 5464 bool Foo = MyObj.MyField; 5465 // [[p]] 5466 } 5467 )"; 5468 runDataflow( 5469 Code, 5470 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5471 ASTContext &ASTCtx) { 5472 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5473 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5474 5475 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5476 ASSERT_THAT(FooDecl, NotNull()); 5477 5478 auto &FooVal = getFormula(*FooDecl, Env); 5479 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 5480 }, 5481 {BuiltinOptions{ContextSensitiveOptions{}}}); 5482 } 5483 5484 TEST(TransferTest, UnnamedBitfieldInitializer) { 5485 std::string Code = R"( 5486 struct B {}; 5487 struct A { 5488 unsigned a; 5489 unsigned : 4; 5490 unsigned c; 5491 B b; 5492 }; 5493 void target() { 5494 A a = {}; 5495 A test = a; 5496 (void)test.c; 5497 } 5498 )"; 5499 runDataflow( 5500 Code, 5501 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5502 ASTContext &ASTCtx) { 5503 // This doesn't need a body because this test was crashing the framework 5504 // before handling correctly Unnamed bitfields in `InitListExpr`. 5505 }); 5506 } 5507 5508 // Repro for a crash that used to occur with chained short-circuiting logical 5509 // operators. 5510 TEST(TransferTest, ChainedLogicalOps) { 5511 std::string Code = R"( 5512 bool target() { 5513 bool b = true || false || false || false; 5514 // [[p]] 5515 return b; 5516 } 5517 )"; 5518 runDataflow( 5519 Code, 5520 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5521 ASTContext &ASTCtx) { 5522 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5523 auto &B = getValueForDecl<BoolValue>(ASTCtx, Env, "b").formula(); 5524 EXPECT_TRUE(Env.flowConditionImplies(B)); 5525 }); 5526 } 5527 5528 // Repro for a crash that used to occur when we call a `noreturn` function 5529 // within one of the operands of a `&&` or `||` operator. 5530 TEST(TransferTest, NoReturnFunctionInsideShortCircuitedBooleanOp) { 5531 std::string Code = R"( 5532 __attribute__((noreturn)) int doesnt_return(); 5533 bool some_condition(); 5534 void target(bool b1, bool b2) { 5535 // Neither of these should crash. In addition, if we don't terminate the 5536 // program, we know that the operators need to trigger the short-circuit 5537 // logic, so `NoreturnOnRhsOfAnd` will be false and `NoreturnOnRhsOfOr` 5538 // will be true. 5539 bool NoreturnOnRhsOfAnd = b1 && doesnt_return() > 0; 5540 bool NoreturnOnRhsOfOr = b2 || doesnt_return() > 0; 5541 5542 // Calling a `noreturn` function on the LHS of an `&&` or `||` makes the 5543 // entire expression unreachable. So we know that in both of the following 5544 // cases, if `target()` terminates, the `else` branch was taken. 5545 bool NoreturnOnLhsMakesAndUnreachable = false; 5546 if (some_condition()) 5547 doesnt_return() > 0 && some_condition(); 5548 else 5549 NoreturnOnLhsMakesAndUnreachable = true; 5550 5551 bool NoreturnOnLhsMakesOrUnreachable = false; 5552 if (some_condition()) 5553 doesnt_return() > 0 || some_condition(); 5554 else 5555 NoreturnOnLhsMakesOrUnreachable = true; 5556 5557 // [[p]] 5558 } 5559 )"; 5560 runDataflow( 5561 Code, 5562 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5563 ASTContext &ASTCtx) { 5564 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5565 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5566 auto &A = Env.arena(); 5567 5568 // Check that [[p]] is reachable with a non-false flow condition. 5569 EXPECT_FALSE(Env.flowConditionImplies(A.makeLiteral(false))); 5570 5571 auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, "b1").formula(); 5572 EXPECT_TRUE(Env.flowConditionImplies(A.makeNot(B1))); 5573 5574 auto &NoreturnOnRhsOfAnd = 5575 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfAnd").formula(); 5576 EXPECT_TRUE(Env.flowConditionImplies(A.makeNot(NoreturnOnRhsOfAnd))); 5577 5578 auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, "b2").formula(); 5579 EXPECT_TRUE(Env.flowConditionImplies(B2)); 5580 5581 auto &NoreturnOnRhsOfOr = 5582 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfOr") 5583 .formula(); 5584 EXPECT_TRUE(Env.flowConditionImplies(NoreturnOnRhsOfOr)); 5585 5586 auto &NoreturnOnLhsMakesAndUnreachable = getValueForDecl<BoolValue>( 5587 ASTCtx, Env, "NoreturnOnLhsMakesAndUnreachable").formula(); 5588 EXPECT_TRUE(Env.flowConditionImplies(NoreturnOnLhsMakesAndUnreachable)); 5589 5590 auto &NoreturnOnLhsMakesOrUnreachable = getValueForDecl<BoolValue>( 5591 ASTCtx, Env, "NoreturnOnLhsMakesOrUnreachable").formula(); 5592 EXPECT_TRUE(Env.flowConditionImplies(NoreturnOnLhsMakesOrUnreachable)); 5593 }); 5594 } 5595 5596 TEST(TransferTest, NewExpressions) { 5597 std::string Code = R"( 5598 void target() { 5599 int *p = new int(42); 5600 // [[after_new]] 5601 } 5602 )"; 5603 runDataflow( 5604 Code, 5605 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5606 ASTContext &ASTCtx) { 5607 const Environment &Env = 5608 getEnvironmentAtAnnotation(Results, "after_new"); 5609 5610 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p"); 5611 5612 EXPECT_THAT(Env.getValue(P.getPointeeLoc()), NotNull()); 5613 }); 5614 } 5615 5616 TEST(TransferTest, NewExpressions_Structs) { 5617 std::string Code = R"( 5618 struct Inner { 5619 int InnerField; 5620 }; 5621 5622 struct Outer { 5623 Inner OuterField; 5624 }; 5625 5626 void target() { 5627 Outer *p = new Outer; 5628 // Access the fields to make sure the analysis actually generates children 5629 // for them in the `RecordStorageLocation` and `RecordValue`. 5630 p->OuterField.InnerField; 5631 // [[after_new]] 5632 } 5633 )"; 5634 runDataflow( 5635 Code, 5636 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5637 ASTContext &ASTCtx) { 5638 const Environment &Env = 5639 getEnvironmentAtAnnotation(Results, "after_new"); 5640 5641 const ValueDecl *OuterField = findValueDecl(ASTCtx, "OuterField"); 5642 const ValueDecl *InnerField = findValueDecl(ASTCtx, "InnerField"); 5643 5644 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p"); 5645 5646 auto &OuterLoc = cast<RecordStorageLocation>(P.getPointeeLoc()); 5647 auto &OuterFieldLoc = 5648 *cast<RecordStorageLocation>(OuterLoc.getChild(*OuterField)); 5649 auto &InnerFieldLoc = *OuterFieldLoc.getChild(*InnerField); 5650 5651 // Values for the struct and all fields exist after the new. 5652 EXPECT_THAT(Env.getValue(OuterLoc), NotNull()); 5653 EXPECT_THAT(Env.getValue(OuterFieldLoc), NotNull()); 5654 EXPECT_THAT(Env.getValue(InnerFieldLoc), NotNull()); 5655 }); 5656 } 5657 5658 TEST(TransferTest, FunctionToPointerDecayHasValue) { 5659 std::string Code = R"( 5660 struct A { static void static_member_func(); }; 5661 void target() { 5662 // To check that we're treating function-to-pointer decay correctly, 5663 // create two pointers, then verify they refer to the same storage 5664 // location. 5665 // We need to do the test this way because even if an initializer (in this 5666 // case, the function-to-pointer decay) does not create a value, we still 5667 // create a value for the variable. 5668 void (*non_member_p1)() = target; 5669 void (*non_member_p2)() = target; 5670 5671 // Do the same thing but for a static member function. 5672 void (*member_p1)() = A::static_member_func; 5673 void (*member_p2)() = A::static_member_func; 5674 // [[p]] 5675 } 5676 )"; 5677 runDataflow( 5678 Code, 5679 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5680 ASTContext &ASTCtx) { 5681 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5682 5683 auto &NonMemberP1 = 5684 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p1"); 5685 auto &NonMemberP2 = 5686 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p2"); 5687 EXPECT_EQ(&NonMemberP1.getPointeeLoc(), &NonMemberP2.getPointeeLoc()); 5688 5689 auto &MemberP1 = 5690 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p1"); 5691 auto &MemberP2 = 5692 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p2"); 5693 EXPECT_EQ(&MemberP1.getPointeeLoc(), &MemberP2.getPointeeLoc()); 5694 }); 5695 } 5696 5697 // Check that a builtin function is not associated with a value. (It's only 5698 // possible to call builtin functions directly, not take their address.) 5699 TEST(TransferTest, BuiltinFunctionModeled) { 5700 std::string Code = R"( 5701 void target() { 5702 __builtin_expect(0, 0); 5703 // [[p]] 5704 } 5705 )"; 5706 runDataflow( 5707 Code, 5708 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5709 ASTContext &ASTCtx) { 5710 using ast_matchers::selectFirst; 5711 using ast_matchers::match; 5712 using ast_matchers::traverse; 5713 using ast_matchers::implicitCastExpr; 5714 using ast_matchers::hasCastKind; 5715 5716 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5717 5718 auto *ImplicitCast = selectFirst<ImplicitCastExpr>( 5719 "implicit_cast", 5720 match(traverse(TK_AsIs, 5721 implicitCastExpr(hasCastKind(CK_BuiltinFnToFnPtr)) 5722 .bind("implicit_cast")), 5723 ASTCtx)); 5724 5725 ASSERT_THAT(ImplicitCast, NotNull()); 5726 EXPECT_THAT(Env.getValue(*ImplicitCast), IsNull()); 5727 }); 5728 } 5729 5730 // Check that a callee of a member operator call is modeled as a `PointerValue`. 5731 // Member operator calls are unusual in that their callee is a pointer that 5732 // stems from a `FunctionToPointerDecay`. In calls to non-operator non-static 5733 // member functions, the callee is a `MemberExpr` (which does not have pointer 5734 // type). 5735 // We want to make sure that we produce a pointer value for the callee in this 5736 // specific scenario and that its storage location is durable (for convergence). 5737 TEST(TransferTest, MemberOperatorCallModelsPointerForCallee) { 5738 std::string Code = R"( 5739 struct S { 5740 bool operator!=(S s); 5741 }; 5742 void target() { 5743 S s; 5744 (void)(s != s); 5745 (void)(s != s); 5746 // [[p]] 5747 } 5748 )"; 5749 runDataflow( 5750 Code, 5751 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5752 ASTContext &ASTCtx) { 5753 using ast_matchers::selectFirst; 5754 using ast_matchers::match; 5755 using ast_matchers::traverse; 5756 using ast_matchers::cxxOperatorCallExpr; 5757 5758 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5759 5760 auto Matches = match( 5761 traverse(TK_AsIs, cxxOperatorCallExpr().bind("call")), ASTCtx); 5762 5763 ASSERT_EQ(Matches.size(), 2UL); 5764 5765 auto *Call1 = Matches[0].getNodeAs<CXXOperatorCallExpr>("call"); 5766 auto *Call2 = Matches[1].getNodeAs<CXXOperatorCallExpr>("call"); 5767 5768 ASSERT_THAT(Call1, NotNull()); 5769 ASSERT_THAT(Call2, NotNull()); 5770 5771 EXPECT_EQ(cast<ImplicitCastExpr>(Call1->getCallee())->getCastKind(), 5772 CK_FunctionToPointerDecay); 5773 EXPECT_EQ(cast<ImplicitCastExpr>(Call2->getCallee())->getCastKind(), 5774 CK_FunctionToPointerDecay); 5775 5776 auto *Ptr1 = cast<PointerValue>(Env.getValue(*Call1->getCallee())); 5777 auto *Ptr2 = cast<PointerValue>(Env.getValue(*Call2->getCallee())); 5778 5779 ASSERT_EQ(&Ptr1->getPointeeLoc(), &Ptr2->getPointeeLoc()); 5780 }); 5781 } 5782 5783 // Check that fields of anonymous records are modeled. 5784 TEST(TransferTest, AnonymousStruct) { 5785 std::string Code = R"( 5786 struct S { 5787 struct { 5788 bool b; 5789 }; 5790 }; 5791 void target() { 5792 S s; 5793 s.b = true; 5794 // [[p]] 5795 } 5796 )"; 5797 runDataflow( 5798 Code, 5799 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5800 ASTContext &ASTCtx) { 5801 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5802 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 5803 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b"); 5804 const IndirectFieldDecl *IndirectField = 5805 findIndirectFieldDecl(ASTCtx, "b"); 5806 5807 auto *S = cast<RecordStorageLocation>(Env.getStorageLocation(*SDecl)); 5808 auto &AnonStruct = *cast<RecordStorageLocation>( 5809 S->getChild(*cast<ValueDecl>(IndirectField->chain().front()))); 5810 5811 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env)); 5812 ASSERT_TRUE(Env.flowConditionImplies(B->formula())); 5813 }); 5814 } 5815 5816 TEST(TransferTest, AnonymousStructWithInitializer) { 5817 std::string Code = R"( 5818 struct target { 5819 target() { 5820 (void)0; 5821 // [[p]] 5822 } 5823 struct { 5824 bool b = true; 5825 }; 5826 }; 5827 )"; 5828 runDataflow( 5829 Code, 5830 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5831 ASTContext &ASTCtx) { 5832 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5833 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b"); 5834 const IndirectFieldDecl *IndirectField = 5835 findIndirectFieldDecl(ASTCtx, "b"); 5836 5837 auto *ThisLoc = 5838 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation()); 5839 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild( 5840 *cast<ValueDecl>(IndirectField->chain().front()))); 5841 5842 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env)); 5843 ASSERT_TRUE(Env.flowConditionImplies(B->formula())); 5844 }); 5845 } 5846 5847 TEST(TransferTest, AnonymousStructWithReferenceField) { 5848 std::string Code = R"( 5849 int global_i = 0; 5850 struct target { 5851 target() { 5852 (void)0; 5853 // [[p]] 5854 } 5855 struct { 5856 int &i = global_i; 5857 }; 5858 }; 5859 )"; 5860 runDataflow( 5861 Code, 5862 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5863 ASTContext &ASTCtx) { 5864 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5865 const ValueDecl *GlobalIDecl = findValueDecl(ASTCtx, "global_i"); 5866 const ValueDecl *IDecl = findValueDecl(ASTCtx, "i"); 5867 const IndirectFieldDecl *IndirectField = 5868 findIndirectFieldDecl(ASTCtx, "i"); 5869 5870 auto *ThisLoc = 5871 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation()); 5872 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild( 5873 *cast<ValueDecl>(IndirectField->chain().front()))); 5874 5875 ASSERT_EQ(AnonStruct.getChild(*IDecl), 5876 Env.getStorageLocation(*GlobalIDecl)); 5877 }); 5878 } 5879 5880 TEST(TransferTest, EvaluateBlockWithUnreachablePreds) { 5881 // This is a crash repro. 5882 // `false` block may not have been processed when we try to evaluate the `||` 5883 // after visiting `true`, because it is not necessary (and therefore the edge 5884 // is marked unreachable). Trying to get the analysis state via 5885 // `getEnvironment` for the subexpression still should not crash. 5886 std::string Code = R"( 5887 int target(int i) { 5888 if ((i < 0 && true) || false) { 5889 return 0; 5890 } 5891 return 0; 5892 } 5893 )"; 5894 runDataflow( 5895 Code, 5896 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5897 ASTContext &ASTCtx) {}); 5898 } 5899 5900 } // namespace 5901