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