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