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