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 A &Rval = (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 EXPECT_EQ(&getLocForDecl(ASTCtx, Env2, "Rval"), FooLoc2); 2278 2279 const auto *FooBazVal2 = 2280 cast<IntegerValue>(getFieldValue(FooLoc2, *BazDecl, Env2)); 2281 const auto *BarBazVal2 = 2282 cast<IntegerValue>(getFieldValue(BarLoc2, *BazDecl, Env2)); 2283 EXPECT_EQ(FooBazVal2, BarBazVal2); 2284 } 2285 2286 // After value update. 2287 { 2288 const Environment &Env3 = getEnvironmentAtAnnotation(Results, "p3"); 2289 2290 const auto *FooLoc3 = 2291 cast<RecordStorageLocation>(Env3.getStorageLocation(*FooDecl)); 2292 const auto *BarLoc3 = 2293 cast<RecordStorageLocation>(Env3.getStorageLocation(*BarDecl)); 2294 EXPECT_FALSE(recordsEqual(*FooLoc3, *BarLoc3, Env3)); 2295 2296 const auto *FooBazVal3 = 2297 cast<IntegerValue>(getFieldValue(FooLoc3, *BazDecl, Env3)); 2298 const auto *BarBazVal3 = 2299 cast<IntegerValue>(getFieldValue(BarLoc3, *BazDecl, Env3)); 2300 EXPECT_NE(FooBazVal3, BarBazVal3); 2301 } 2302 }); 2303 } 2304 2305 // It's legal for the assignment operator to take its source parameter by value. 2306 // Check that we handle this correctly. (This is a repro -- we used to 2307 // assert-fail on this.) 2308 TEST(TransferTest, AssignmentOperator_ArgByValue) { 2309 std::string Code = R"( 2310 struct A { 2311 int Baz; 2312 A &operator=(A); 2313 }; 2314 2315 void target() { 2316 A Foo = { 1 }; 2317 A Bar = { 2 }; 2318 Foo = Bar; 2319 // [[p]] 2320 } 2321 )"; 2322 runDataflow( 2323 Code, 2324 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2325 ASTContext &ASTCtx) { 2326 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2327 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2328 2329 const auto &FooLoc = 2330 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo"); 2331 const auto &BarLoc = 2332 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar"); 2333 2334 const auto *FooBazVal = 2335 cast<IntegerValue>(getFieldValue(&FooLoc, *BazDecl, Env)); 2336 const auto *BarBazVal = 2337 cast<IntegerValue>(getFieldValue(&BarLoc, *BazDecl, Env)); 2338 EXPECT_EQ(FooBazVal, BarBazVal); 2339 }); 2340 } 2341 2342 TEST(TransferTest, AssignmentOperatorFromBase) { 2343 std::string Code = R"( 2344 struct Base { 2345 int base; 2346 }; 2347 struct Derived : public Base { 2348 using Base::operator=; 2349 int derived; 2350 }; 2351 void target(Base B, Derived D) { 2352 D.base = 1; 2353 D.derived = 1; 2354 // [[before]] 2355 D = B; 2356 // [[after]] 2357 } 2358 )"; 2359 runDataflow( 2360 Code, 2361 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2362 ASTContext &ASTCtx) { 2363 const Environment &EnvBefore = 2364 getEnvironmentAtAnnotation(Results, "before"); 2365 const Environment &EnvAfter = 2366 getEnvironmentAtAnnotation(Results, "after"); 2367 2368 auto &BLoc = 2369 getLocForDecl<RecordStorageLocation>(ASTCtx, EnvBefore, "B"); 2370 auto &DLoc = 2371 getLocForDecl<RecordStorageLocation>(ASTCtx, EnvBefore, "D"); 2372 2373 EXPECT_NE(getFieldValue(&BLoc, "base", ASTCtx, EnvBefore), 2374 getFieldValue(&DLoc, "base", ASTCtx, EnvBefore)); 2375 EXPECT_EQ(getFieldValue(&BLoc, "base", ASTCtx, EnvAfter), 2376 getFieldValue(&DLoc, "base", ASTCtx, EnvAfter)); 2377 2378 EXPECT_EQ(getFieldValue(&DLoc, "derived", ASTCtx, EnvBefore), 2379 getFieldValue(&DLoc, "derived", ASTCtx, EnvAfter)); 2380 }); 2381 } 2382 2383 TEST(TransferTest, AssignmentOperatorFromCallResult) { 2384 std::string Code = R"( 2385 struct A {}; 2386 A ReturnA(); 2387 2388 void target() { 2389 A MyA; 2390 MyA = ReturnA(); 2391 } 2392 )"; 2393 runDataflow( 2394 Code, 2395 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2396 ASTContext &ASTCtx) { 2397 // As of this writing, we don't produce a `Value` for the call 2398 // `ReturnA()`. The only condition we're testing for is that the 2399 // analysis should not crash in this case. 2400 }); 2401 } 2402 2403 TEST(TransferTest, AssignmentOperatorWithInitAndInheritance) { 2404 // This is a crash repro. 2405 std::string Code = R"( 2406 struct B { int Foo; }; 2407 struct S : public B {}; 2408 void target() { 2409 S S1 = { 1 }; 2410 S S2; 2411 S S3; 2412 S1 = S2; // Only Dst has InitListExpr. 2413 S3 = S1; // Only Src has InitListExpr. 2414 // [[p]] 2415 } 2416 )"; 2417 runDataflow( 2418 Code, 2419 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2420 ASTContext &ASTCtx) {}); 2421 } 2422 2423 TEST(TransferTest, AssignmentOperatorReturnsVoid) { 2424 // This is a crash repro. 2425 std::string Code = R"( 2426 struct S { 2427 void operator=(S&& other); 2428 }; 2429 void target() { 2430 S s; 2431 s = S(); 2432 // [[p]] 2433 } 2434 )"; 2435 runDataflow( 2436 Code, 2437 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2438 ASTContext &ASTCtx) {}); 2439 } 2440 2441 TEST(TransferTest, AssignmentOperatorReturnsByValue) { 2442 // This is a crash repro. 2443 std::string Code = R"( 2444 struct S { 2445 S operator=(const S&); 2446 int i; 2447 }; 2448 void target() { 2449 S S1 = { 1 }; 2450 S S2 = { 2 }; 2451 S S3 = { 3 }; 2452 // [[before]] 2453 // Test that the returned value is modeled by assigning to another value. 2454 S1 = (S2 = S3); 2455 (void)0; 2456 // [[after]] 2457 } 2458 )"; 2459 runDataflow( 2460 Code, 2461 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2462 ASTContext &ASTCtx) { 2463 const ValueDecl *S1Decl = findValueDecl(ASTCtx, "S1"); 2464 const ValueDecl *S2Decl = findValueDecl(ASTCtx, "S2"); 2465 const ValueDecl *S3Decl = findValueDecl(ASTCtx, "S3"); 2466 2467 const Environment &EnvBefore = 2468 getEnvironmentAtAnnotation(Results, "before"); 2469 2470 EXPECT_FALSE(recordsEqual( 2471 *EnvBefore.get<RecordStorageLocation>(*S1Decl), 2472 *EnvBefore.get<RecordStorageLocation>(*S2Decl), EnvBefore)); 2473 EXPECT_FALSE(recordsEqual( 2474 *EnvBefore.get<RecordStorageLocation>(*S2Decl), 2475 *EnvBefore.get<RecordStorageLocation>(*S3Decl), EnvBefore)); 2476 2477 const Environment &EnvAfter = 2478 getEnvironmentAtAnnotation(Results, "after"); 2479 2480 EXPECT_TRUE(recordsEqual(*EnvAfter.get<RecordStorageLocation>(*S1Decl), 2481 *EnvAfter.get<RecordStorageLocation>(*S2Decl), 2482 EnvAfter)); 2483 EXPECT_TRUE(recordsEqual(*EnvAfter.get<RecordStorageLocation>(*S2Decl), 2484 *EnvAfter.get<RecordStorageLocation>(*S3Decl), 2485 EnvAfter)); 2486 }); 2487 } 2488 2489 TEST(TransferTest, AssignmentOperatorReturnsDifferentTypeByRef) { 2490 // This is a crash repro. 2491 std::string Code = R"( 2492 struct DifferentType {}; 2493 struct S { 2494 DifferentType& operator=(const S&); 2495 }; 2496 void target() { 2497 S s; 2498 s = S(); 2499 // [[p]] 2500 } 2501 )"; 2502 runDataflow( 2503 Code, 2504 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2505 ASTContext &ASTCtx) {}); 2506 } 2507 2508 TEST(TransferTest, AssignmentOperatorReturnsDifferentTypeByValue) { 2509 // This is a crash repro. 2510 std::string Code = R"( 2511 struct DifferentType {}; 2512 struct S { 2513 DifferentType operator=(const S&); 2514 }; 2515 void target() { 2516 S s; 2517 s = S(); 2518 // [[p]] 2519 } 2520 )"; 2521 runDataflow( 2522 Code, 2523 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2524 ASTContext &ASTCtx) {}); 2525 } 2526 2527 TEST(TransferTest, InitListExprAsXValue) { 2528 // This is a crash repro. 2529 std::string Code = R"( 2530 void target() { 2531 bool&& Foo{false}; 2532 // [[p]] 2533 } 2534 )"; 2535 runDataflow( 2536 Code, 2537 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2538 ASTContext &ASTCtx) { 2539 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2540 const auto &FooVal = getValueForDecl<BoolValue>(ASTCtx, Env, "Foo"); 2541 ASSERT_TRUE(FooVal.formula().isLiteral(false)); 2542 }); 2543 } 2544 2545 TEST(TransferTest, ArrayInitListExprOneRecordElement) { 2546 // This is a crash repro. 2547 std::string Code = R"cc( 2548 struct S {}; 2549 2550 void target() { S foo[] = {S()}; } 2551 )cc"; 2552 runDataflow( 2553 Code, 2554 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2555 ASTContext &ASTCtx) { 2556 // Just verify that it doesn't crash. 2557 }); 2558 } 2559 2560 TEST(TransferTest, InitListExprAsUnion) { 2561 // This is a crash repro. 2562 std::string Code = R"cc( 2563 class target { 2564 union { 2565 int *a; 2566 bool *b; 2567 } F; 2568 2569 public: 2570 constexpr target() : F{nullptr} { 2571 int *null = nullptr; 2572 F.b; // Make sure we reference 'b' so it is modeled. 2573 // [[p]] 2574 } 2575 }; 2576 )cc"; 2577 runDataflow( 2578 Code, 2579 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2580 ASTContext &ASTCtx) { 2581 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2582 2583 auto &FLoc = getFieldLoc<RecordStorageLocation>( 2584 *Env.getThisPointeeStorageLocation(), "F", ASTCtx); 2585 auto *AVal = cast<PointerValue>(getFieldValue(&FLoc, "a", ASTCtx, Env)); 2586 EXPECT_EQ(AVal, &getValueForDecl<PointerValue>(ASTCtx, Env, "null")); 2587 EXPECT_EQ(getFieldValue(&FLoc, "b", ASTCtx, Env), nullptr); 2588 }); 2589 } 2590 2591 TEST(TransferTest, EmptyInitListExprForUnion) { 2592 // This is a crash repro. 2593 std::string Code = R"cc( 2594 class target { 2595 union { 2596 int *a; 2597 bool *b; 2598 } F; 2599 2600 public: 2601 // Empty initializer list means that `F` is aggregate-initialized. 2602 // For a union, this has the effect that the first member of the union 2603 // is copy-initialized from an empty initializer list; in this specific 2604 // case, this has the effect of initializing `a` with null. 2605 constexpr target() : F{} { 2606 int *null = nullptr; 2607 F.b; // Make sure we reference 'b' so it is modeled. 2608 // [[p]] 2609 } 2610 }; 2611 )cc"; 2612 runDataflow( 2613 Code, 2614 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2615 ASTContext &ASTCtx) { 2616 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2617 2618 auto &FLoc = getFieldLoc<RecordStorageLocation>( 2619 *Env.getThisPointeeStorageLocation(), "F", ASTCtx); 2620 auto *AVal = cast<PointerValue>(getFieldValue(&FLoc, "a", ASTCtx, Env)); 2621 EXPECT_EQ(AVal, &getValueForDecl<PointerValue>(ASTCtx, Env, "null")); 2622 EXPECT_EQ(getFieldValue(&FLoc, "b", ASTCtx, Env), nullptr); 2623 }); 2624 } 2625 2626 TEST(TransferTest, EmptyInitListExprForStruct) { 2627 std::string Code = R"cc( 2628 class target { 2629 struct { 2630 int *a; 2631 bool *b; 2632 } F; 2633 2634 public: 2635 constexpr target() : F{} { 2636 int *NullIntPtr = nullptr; 2637 bool *NullBoolPtr = nullptr; 2638 // [[p]] 2639 } 2640 }; 2641 )cc"; 2642 runDataflow( 2643 Code, 2644 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2645 ASTContext &ASTCtx) { 2646 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2647 2648 auto &FLoc = getFieldLoc<RecordStorageLocation>( 2649 *Env.getThisPointeeStorageLocation(), "F", ASTCtx); 2650 auto *AVal = cast<PointerValue>(getFieldValue(&FLoc, "a", ASTCtx, Env)); 2651 EXPECT_EQ(AVal, 2652 &getValueForDecl<PointerValue>(ASTCtx, Env, "NullIntPtr")); 2653 auto *BVal = cast<PointerValue>(getFieldValue(&FLoc, "b", ASTCtx, Env)); 2654 EXPECT_EQ(BVal, 2655 &getValueForDecl<PointerValue>(ASTCtx, Env, "NullBoolPtr")); 2656 }); 2657 } 2658 2659 TEST(TransferTest, CopyConstructor) { 2660 std::string Code = R"( 2661 struct A { 2662 int Baz; 2663 }; 2664 2665 void target() { 2666 A Foo = { 1 }; 2667 A Bar = Foo; 2668 // [[after_copy]] 2669 Foo.Baz = 2; 2670 // [[after_update]] 2671 } 2672 )"; 2673 runDataflow( 2674 Code, 2675 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2676 ASTContext &ASTCtx) { 2677 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2678 ASSERT_THAT(FooDecl, NotNull()); 2679 2680 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2681 ASSERT_THAT(BarDecl, NotNull()); 2682 2683 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2684 ASSERT_THAT(BazDecl, NotNull()); 2685 2686 // after_copy 2687 { 2688 const Environment &Env = 2689 getEnvironmentAtAnnotation(Results, "after_copy"); 2690 2691 const auto *FooLoc = 2692 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2693 const auto *BarLoc = 2694 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2695 2696 // The records compare equal. 2697 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env)); 2698 2699 // In particular, the value of `Baz` in both records is the same. 2700 const auto *FooBazVal = 2701 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2702 const auto *BarBazVal = 2703 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2704 EXPECT_EQ(FooBazVal, BarBazVal); 2705 } 2706 2707 // after_update 2708 { 2709 const Environment &Env = 2710 getEnvironmentAtAnnotation(Results, "after_update"); 2711 2712 const auto *FooLoc = 2713 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2714 const auto *BarLoc = 2715 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2716 2717 EXPECT_FALSE(recordsEqual(*FooLoc, *BarLoc, Env)); 2718 2719 const auto *FooBazVal = 2720 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2721 const auto *BarBazVal = 2722 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2723 EXPECT_NE(FooBazVal, BarBazVal); 2724 } 2725 }); 2726 } 2727 2728 TEST(TransferTest, CopyConstructorWithDefaultArgument) { 2729 std::string Code = R"( 2730 struct A { 2731 int Baz; 2732 A() = default; 2733 A(const A& a, bool def = true) { Baz = a.Baz; } 2734 }; 2735 2736 void target() { 2737 A Foo; 2738 (void)Foo.Baz; 2739 A Bar = Foo; 2740 // [[p]] 2741 } 2742 )"; 2743 runDataflow( 2744 Code, 2745 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2746 ASTContext &ASTCtx) { 2747 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2748 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2749 2750 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2751 ASSERT_THAT(FooDecl, NotNull()); 2752 2753 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2754 ASSERT_THAT(BarDecl, NotNull()); 2755 2756 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2757 ASSERT_THAT(BazDecl, NotNull()); 2758 2759 const auto *FooLoc = 2760 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2761 const auto *BarLoc = 2762 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2763 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env)); 2764 2765 const auto *FooBazVal = 2766 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2767 const auto *BarBazVal = 2768 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2769 EXPECT_EQ(FooBazVal, BarBazVal); 2770 }); 2771 } 2772 2773 TEST(TransferTest, CopyConstructorWithParens) { 2774 std::string Code = R"( 2775 struct A { 2776 int Baz; 2777 }; 2778 2779 void target() { 2780 A Foo; 2781 (void)Foo.Baz; 2782 A Bar((A(Foo))); 2783 // [[p]] 2784 } 2785 )"; 2786 runDataflow( 2787 Code, 2788 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2789 ASTContext &ASTCtx) { 2790 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2791 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2792 2793 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2794 ASSERT_THAT(FooDecl, NotNull()); 2795 2796 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2797 ASSERT_THAT(BarDecl, NotNull()); 2798 2799 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2800 ASSERT_THAT(BazDecl, NotNull()); 2801 2802 const auto *FooLoc = 2803 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2804 const auto *BarLoc = 2805 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2806 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env)); 2807 2808 const auto *FooBazVal = 2809 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2810 const auto *BarBazVal = 2811 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2812 EXPECT_EQ(FooBazVal, BarBazVal); 2813 }); 2814 } 2815 2816 TEST(TransferTest, CopyConstructorWithInitializerListAsSyntacticSugar) { 2817 std::string Code = R"( 2818 struct A { 2819 int Baz; 2820 }; 2821 void target() { 2822 A Foo = {3}; 2823 (void)Foo.Baz; 2824 A Bar = {A(Foo)}; 2825 // [[p]] 2826 } 2827 )"; 2828 runDataflow( 2829 Code, 2830 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2831 ASTContext &ASTCtx) { 2832 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2833 2834 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2835 2836 const auto &FooLoc = 2837 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo"); 2838 const auto &BarLoc = 2839 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar"); 2840 2841 const auto *FooBazVal = 2842 cast<IntegerValue>(getFieldValue(&FooLoc, *BazDecl, Env)); 2843 const auto *BarBazVal = 2844 cast<IntegerValue>(getFieldValue(&BarLoc, *BazDecl, Env)); 2845 EXPECT_EQ(FooBazVal, BarBazVal); 2846 }); 2847 } 2848 2849 TEST(TransferTest, CopyConstructorArgIsRefReturnedByFunction) { 2850 // This is a crash repro. 2851 std::string Code = R"( 2852 struct S {}; 2853 const S &returnsSRef(); 2854 void target() { 2855 S s(returnsSRef()); 2856 } 2857 )"; 2858 runDataflow( 2859 Code, 2860 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2861 ASTContext &ASTCtx) {}); 2862 } 2863 2864 TEST(TransferTest, MoveConstructor) { 2865 std::string Code = R"( 2866 namespace std { 2867 2868 template <typename T> struct remove_reference { using type = T; }; 2869 template <typename T> struct remove_reference<T&> { using type = T; }; 2870 template <typename T> struct remove_reference<T&&> { using type = T; }; 2871 2872 template <typename T> 2873 using remove_reference_t = typename remove_reference<T>::type; 2874 2875 template <typename T> 2876 std::remove_reference_t<T>&& move(T&& x); 2877 2878 } // namespace std 2879 2880 struct A { 2881 int Baz; 2882 }; 2883 2884 void target() { 2885 A Foo; 2886 A Bar; 2887 (void)Foo.Baz; 2888 // [[p1]] 2889 Foo = std::move(Bar); 2890 // [[p2]] 2891 } 2892 )"; 2893 runDataflow( 2894 Code, 2895 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2896 ASTContext &ASTCtx) { 2897 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 2898 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 2899 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 2900 2901 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2902 ASSERT_THAT(FooDecl, NotNull()); 2903 2904 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2905 ASSERT_THAT(BarDecl, NotNull()); 2906 2907 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2908 ASSERT_THAT(BazDecl, NotNull()); 2909 2910 const auto *FooLoc1 = 2911 cast<RecordStorageLocation>(Env1.getStorageLocation(*FooDecl)); 2912 const auto *BarLoc1 = 2913 cast<RecordStorageLocation>(Env1.getStorageLocation(*BarDecl)); 2914 2915 EXPECT_FALSE(recordsEqual(*FooLoc1, *BarLoc1, Env1)); 2916 2917 const auto *FooBazVal1 = 2918 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env1)); 2919 const auto *BarBazVal1 = 2920 cast<IntegerValue>(getFieldValue(BarLoc1, *BazDecl, Env1)); 2921 EXPECT_NE(FooBazVal1, BarBazVal1); 2922 2923 const auto *FooLoc2 = 2924 cast<RecordStorageLocation>(Env2.getStorageLocation(*FooDecl)); 2925 EXPECT_TRUE(recordsEqual(*FooLoc2, Env2, *BarLoc1, Env1)); 2926 2927 const auto *FooBazVal2 = 2928 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env2)); 2929 EXPECT_EQ(FooBazVal2, BarBazVal1); 2930 }); 2931 } 2932 2933 TEST(TransferTest, BindTemporary) { 2934 std::string Code = R"( 2935 struct A { 2936 virtual ~A() = default; 2937 2938 int Baz; 2939 }; 2940 2941 void target(A Foo) { 2942 int Bar = A(Foo).Baz; 2943 // [[p]] 2944 } 2945 )"; 2946 runDataflow( 2947 Code, 2948 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2949 ASTContext &ASTCtx) { 2950 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2951 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2952 2953 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2954 ASSERT_THAT(FooDecl, NotNull()); 2955 2956 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2957 ASSERT_THAT(BarDecl, NotNull()); 2958 2959 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2960 ASSERT_THAT(BazDecl, NotNull()); 2961 2962 const auto &FooLoc = 2963 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2964 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 2965 EXPECT_EQ(BarVal, getFieldValue(&FooLoc, *BazDecl, Env)); 2966 }); 2967 } 2968 2969 TEST(TransferTest, ResultObjectLocation) { 2970 std::string Code = R"( 2971 struct A { 2972 virtual ~A() = default; 2973 }; 2974 2975 void target() { 2976 0, A(); 2977 (void)0; // [[p]] 2978 } 2979 )"; 2980 using ast_matchers::binaryOperator; 2981 using ast_matchers::cxxBindTemporaryExpr; 2982 using ast_matchers::cxxTemporaryObjectExpr; 2983 using ast_matchers::exprWithCleanups; 2984 using ast_matchers::has; 2985 using ast_matchers::hasOperatorName; 2986 using ast_matchers::hasRHS; 2987 using ast_matchers::match; 2988 using ast_matchers::selectFirst; 2989 using ast_matchers::traverse; 2990 runDataflow( 2991 Code, 2992 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2993 ASTContext &ASTCtx) { 2994 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2995 2996 // The expression `0, A()` in the code above produces the following 2997 // structure, consisting of four prvalues of record type. 2998 // `Env.getResultObjectLocation()` should return the same location for 2999 // all of these. 3000 auto MatchResult = match( 3001 traverse(TK_AsIs, 3002 exprWithCleanups( 3003 has(binaryOperator( 3004 hasOperatorName(","), 3005 hasRHS(cxxBindTemporaryExpr( 3006 has(cxxTemporaryObjectExpr().bind( 3007 "toe"))) 3008 .bind("bte"))) 3009 .bind("comma"))) 3010 .bind("ewc")), 3011 ASTCtx); 3012 auto *TOE = selectFirst<CXXTemporaryObjectExpr>("toe", MatchResult); 3013 ASSERT_NE(TOE, nullptr); 3014 auto *Comma = selectFirst<BinaryOperator>("comma", MatchResult); 3015 ASSERT_NE(Comma, nullptr); 3016 auto *EWC = selectFirst<ExprWithCleanups>("ewc", MatchResult); 3017 ASSERT_NE(EWC, nullptr); 3018 auto *BTE = selectFirst<CXXBindTemporaryExpr>("bte", MatchResult); 3019 ASSERT_NE(BTE, nullptr); 3020 3021 RecordStorageLocation &Loc = Env.getResultObjectLocation(*TOE); 3022 EXPECT_EQ(&Loc, &Env.getResultObjectLocation(*Comma)); 3023 EXPECT_EQ(&Loc, &Env.getResultObjectLocation(*EWC)); 3024 EXPECT_EQ(&Loc, &Env.getResultObjectLocation(*BTE)); 3025 }); 3026 } 3027 3028 TEST(TransferTest, ResultObjectLocationForDefaultArgExpr) { 3029 std::string Code = R"( 3030 struct Inner {}; 3031 struct Outer { 3032 Inner I = {}; 3033 }; 3034 3035 void funcWithDefaultArg(Outer O = {}); 3036 void target() { 3037 funcWithDefaultArg(); 3038 // [[p]] 3039 } 3040 )"; 3041 3042 using ast_matchers::cxxDefaultArgExpr; 3043 using ast_matchers::match; 3044 using ast_matchers::selectFirst; 3045 runDataflow( 3046 Code, 3047 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3048 ASTContext &ASTCtx) { 3049 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3050 3051 auto *DefaultArg = selectFirst<CXXDefaultArgExpr>( 3052 "default_arg", 3053 match(cxxDefaultArgExpr().bind("default_arg"), ASTCtx)); 3054 ASSERT_NE(DefaultArg, nullptr); 3055 3056 // The values for default arguments aren't modeled; we merely verify 3057 // that we can get a result object location for a default arg. 3058 Env.getResultObjectLocation(*DefaultArg); 3059 }); 3060 } 3061 3062 TEST(TransferTest, ResultObjectLocationForDefaultInitExpr) { 3063 std::string Code = R"( 3064 struct S {}; 3065 struct target { 3066 target () { 3067 (void)0; 3068 // [[p]] 3069 } 3070 S s = {}; 3071 }; 3072 )"; 3073 3074 using ast_matchers::cxxCtorInitializer; 3075 using ast_matchers::match; 3076 using ast_matchers::selectFirst; 3077 runDataflow( 3078 Code, 3079 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3080 ASTContext &ASTCtx) { 3081 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3082 3083 const ValueDecl *SField = findValueDecl(ASTCtx, "s"); 3084 3085 auto *CtorInit = selectFirst<CXXCtorInitializer>( 3086 "ctor_initializer", 3087 match(cxxCtorInitializer().bind("ctor_initializer"), ASTCtx)); 3088 ASSERT_NE(CtorInit, nullptr); 3089 3090 auto *DefaultInit = cast<CXXDefaultInitExpr>(CtorInit->getInit()); 3091 3092 RecordStorageLocation &Loc = Env.getResultObjectLocation(*DefaultInit); 3093 3094 EXPECT_EQ(&Loc, Env.getThisPointeeStorageLocation()->getChild(*SField)); 3095 }); 3096 } 3097 3098 // This test ensures that CXXOperatorCallExpr returning prvalues are correctly 3099 // handled by the transfer functions, especially that `getResultObjectLocation` 3100 // correctly returns a storage location for those. 3101 TEST(TransferTest, ResultObjectLocationForCXXOperatorCallExpr) { 3102 std::string Code = R"( 3103 struct A { 3104 A operator+(int); 3105 }; 3106 3107 void target() { 3108 A a; 3109 a + 3; 3110 (void)0; // [[p]] 3111 } 3112 )"; 3113 using ast_matchers::cxxOperatorCallExpr; 3114 using ast_matchers::match; 3115 using ast_matchers::selectFirst; 3116 using ast_matchers::traverse; 3117 runDataflow( 3118 Code, 3119 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3120 ASTContext &ASTCtx) { 3121 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3122 3123 auto *CallExpr = selectFirst<CXXOperatorCallExpr>( 3124 "call_expr", 3125 match(cxxOperatorCallExpr().bind("call_expr"), ASTCtx)); 3126 3127 EXPECT_NE(&Env.getResultObjectLocation(*CallExpr), nullptr); 3128 }); 3129 } 3130 3131 TEST(TransferTest, ResultObjectLocationForInitListExpr) { 3132 std::string Code = R"cc( 3133 struct Inner {}; 3134 3135 struct Outer { Inner I; }; 3136 3137 void target() { 3138 Outer O = { Inner() }; 3139 // [[p]] 3140 } 3141 )cc"; 3142 using ast_matchers::asString; 3143 using ast_matchers::cxxConstructExpr; 3144 using ast_matchers::hasType; 3145 using ast_matchers::match; 3146 using ast_matchers::selectFirst; 3147 using ast_matchers::traverse; 3148 runDataflow( 3149 Code, 3150 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3151 ASTContext &ASTCtx) { 3152 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3153 3154 auto *Construct = selectFirst<CXXConstructExpr>( 3155 "construct", 3156 match( 3157 cxxConstructExpr(hasType(asString("Inner"))).bind("construct"), 3158 ASTCtx)); 3159 3160 EXPECT_EQ( 3161 &Env.getResultObjectLocation(*Construct), 3162 &getFieldLoc(getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "O"), 3163 "I", ASTCtx)); 3164 }); 3165 } 3166 3167 TEST(TransferTest, ResultObjectLocationForParenInitListExpr) { 3168 std::string Code = R"cc( 3169 struct Inner {}; 3170 3171 struct Outer { Inner I; }; 3172 3173 void target() { 3174 Outer O((Inner())); 3175 // [[p]] 3176 } 3177 )cc"; 3178 using ast_matchers::asString; 3179 using ast_matchers::cxxConstructExpr; 3180 using ast_matchers::hasType; 3181 using ast_matchers::match; 3182 using ast_matchers::selectFirst; 3183 using ast_matchers::traverse; 3184 runDataflow( 3185 Code, 3186 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3187 ASTContext &ASTCtx) { 3188 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3189 3190 auto *Construct = selectFirst<CXXConstructExpr>( 3191 "construct", 3192 match( 3193 cxxConstructExpr(hasType(asString("Inner"))).bind("construct"), 3194 ASTCtx)); 3195 3196 EXPECT_EQ( 3197 &Env.getResultObjectLocation(*Construct), 3198 &getFieldLoc(getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "O"), 3199 "I", ASTCtx)); 3200 }, 3201 LangStandard::lang_cxx20); 3202 } 3203 3204 // Check that the `std::strong_ordering` object returned by builtin `<=>` has a 3205 // correctly modeled result object location. 3206 TEST(TransferTest, ResultObjectLocationForBuiltinSpaceshipOperator) { 3207 std::string Code = R"( 3208 namespace std { 3209 // This is the minimal definition required to get 3210 // `Sema::CheckComparisonCategoryType()` to accept this fake. 3211 struct strong_ordering { 3212 enum class ordering { less, equal, greater }; 3213 ordering o; 3214 static const strong_ordering less; 3215 static const strong_ordering equivalent; 3216 static const strong_ordering equal; 3217 static const strong_ordering greater; 3218 }; 3219 3220 inline constexpr strong_ordering strong_ordering::less = 3221 { strong_ordering::ordering::less }; 3222 inline constexpr strong_ordering strong_ordering::equal = 3223 { strong_ordering::ordering::equal }; 3224 inline constexpr strong_ordering strong_ordering::equivalent = 3225 { strong_ordering::ordering::equal }; 3226 inline constexpr strong_ordering strong_ordering::greater = 3227 { strong_ordering::ordering::greater }; 3228 } 3229 void target(int i, int j) { 3230 auto ordering = i <=> j; 3231 // [[p]] 3232 } 3233 )"; 3234 using ast_matchers::binaryOperator; 3235 using ast_matchers::hasOperatorName; 3236 using ast_matchers::match; 3237 using ast_matchers::selectFirst; 3238 using ast_matchers::traverse; 3239 runDataflow( 3240 Code, 3241 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3242 ASTContext &ASTCtx) { 3243 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3244 3245 auto *Spaceship = selectFirst<BinaryOperator>( 3246 "op", 3247 match(binaryOperator(hasOperatorName("<=>")).bind("op"), ASTCtx)); 3248 3249 EXPECT_EQ( 3250 &Env.getResultObjectLocation(*Spaceship), 3251 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "ordering")); 3252 }, 3253 LangStandard::lang_cxx20); 3254 } 3255 3256 TEST(TransferTest, ResultObjectLocationForStdInitializerListExpr) { 3257 std::string Code = R"( 3258 namespace std { 3259 template <typename T> 3260 struct initializer_list {}; 3261 } // namespace std 3262 3263 void target() { 3264 std::initializer_list<int> list = {1}; 3265 // [[p]] 3266 } 3267 )"; 3268 3269 using ast_matchers::cxxStdInitializerListExpr; 3270 using ast_matchers::match; 3271 using ast_matchers::selectFirst; 3272 runDataflow( 3273 Code, 3274 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3275 ASTContext &ASTCtx) { 3276 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3277 3278 auto *StdInitList = selectFirst<CXXStdInitializerListExpr>( 3279 "std_init_list", 3280 match(cxxStdInitializerListExpr().bind("std_init_list"), ASTCtx)); 3281 ASSERT_NE(StdInitList, nullptr); 3282 3283 EXPECT_EQ(&Env.getResultObjectLocation(*StdInitList), 3284 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "list")); 3285 }); 3286 } 3287 3288 TEST(TransferTest, ResultObjectLocationForStmtExpr) { 3289 std::string Code = R"( 3290 struct S {}; 3291 void target() { 3292 S s = ({ S(); }); 3293 // [[p]] 3294 } 3295 )"; 3296 using ast_matchers::cxxConstructExpr; 3297 using ast_matchers::match; 3298 using ast_matchers::selectFirst; 3299 using ast_matchers::traverse; 3300 runDataflow( 3301 Code, 3302 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3303 ASTContext &ASTCtx) { 3304 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3305 3306 auto *Construct = selectFirst<CXXConstructExpr>( 3307 "construct", match(cxxConstructExpr().bind("construct"), ASTCtx)); 3308 3309 EXPECT_EQ(&Env.getResultObjectLocation(*Construct), 3310 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s")); 3311 }); 3312 } 3313 3314 TEST(TransferTest, ResultObjectLocationForBuiltinBitCastExpr) { 3315 std::string Code = R"( 3316 struct S { int i; }; 3317 void target(int i) { 3318 S s = __builtin_bit_cast(S, i); 3319 // [[p]] 3320 } 3321 )"; 3322 using ast_matchers::explicitCastExpr; 3323 using ast_matchers::match; 3324 using ast_matchers::selectFirst; 3325 using ast_matchers::traverse; 3326 runDataflow( 3327 Code, 3328 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3329 ASTContext &ASTCtx) { 3330 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3331 3332 auto *BuiltinBitCast = selectFirst<BuiltinBitCastExpr>( 3333 "cast", match(explicitCastExpr().bind("cast"), ASTCtx)); 3334 3335 EXPECT_EQ(&Env.getResultObjectLocation(*BuiltinBitCast), 3336 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s")); 3337 }); 3338 } 3339 3340 TEST(TransferTest, ResultObjectLocationPropagatesThroughConditionalOperator) { 3341 std::string Code = R"( 3342 struct A { 3343 A(int); 3344 }; 3345 3346 void target(bool b) { 3347 A a = b ? A(0) : A(1); 3348 (void)0; // [[p]] 3349 } 3350 )"; 3351 using ast_matchers::cxxConstructExpr; 3352 using ast_matchers::equals; 3353 using ast_matchers::hasArgument; 3354 using ast_matchers::integerLiteral; 3355 using ast_matchers::match; 3356 using ast_matchers::selectFirst; 3357 using ast_matchers::traverse; 3358 runDataflow( 3359 Code, 3360 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3361 ASTContext &ASTCtx) { 3362 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3363 3364 auto *ConstructExpr0 = selectFirst<CXXConstructExpr>( 3365 "construct", 3366 match(cxxConstructExpr(hasArgument(0, integerLiteral(equals(0)))) 3367 .bind("construct"), 3368 ASTCtx)); 3369 auto *ConstructExpr1 = selectFirst<CXXConstructExpr>( 3370 "construct", 3371 match(cxxConstructExpr(hasArgument(0, integerLiteral(equals(1)))) 3372 .bind("construct"), 3373 ASTCtx)); 3374 3375 auto &ALoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "a"); 3376 EXPECT_EQ(&Env.getResultObjectLocation(*ConstructExpr0), &ALoc); 3377 EXPECT_EQ(&Env.getResultObjectLocation(*ConstructExpr1), &ALoc); 3378 }); 3379 } 3380 3381 TEST(TransferTest, ResultObjectLocationDontVisitNestedRecordDecl) { 3382 // This is a crash repro. 3383 // We used to crash because when propagating result objects, we would visit 3384 // nested record and function declarations, but we don't model fields used 3385 // only in these. 3386 std::string Code = R"( 3387 struct S1 {}; 3388 struct S2 { S1 s1; }; 3389 void target() { 3390 struct Nested { 3391 void f() { 3392 S2 s2 = { S1() }; 3393 } 3394 }; 3395 } 3396 )"; 3397 runDataflow( 3398 Code, 3399 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3400 ASTContext &ASTCtx) {}); 3401 } 3402 3403 TEST(TransferTest, ResultObjectLocationDontVisitUnevaluatedContexts) { 3404 // This is a crash repro. 3405 // We used to crash because when propagating result objects, we would visit 3406 // unevaluated contexts, but we don't model fields used only in these. 3407 3408 auto testFunction = [](llvm::StringRef Code, llvm::StringRef TargetFun) { 3409 runDataflow( 3410 Code, 3411 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3412 ASTContext &ASTCtx) {}, 3413 LangStandard::lang_gnucxx17, 3414 /* ApplyBuiltinTransfer= */ true, TargetFun); 3415 }; 3416 3417 std::string Code = R"cc( 3418 // Definitions needed for `typeid`. 3419 namespace std { 3420 class type_info {}; 3421 class bad_typeid {}; 3422 } // namespace std 3423 3424 struct S1 {}; 3425 struct S2 { S1 s1; }; 3426 3427 // We test each type of unevaluated context from a different target 3428 // function. Some types of unevaluated contexts may actually cause the 3429 // field `s1` to be modeled, and we don't want this to "pollute" the tests 3430 // for the other unevaluated contexts. 3431 void decltypeTarget() { 3432 decltype(S2{}) Dummy; 3433 } 3434 void typeofTarget() { 3435 typeof(S2{}) Dummy; 3436 } 3437 void typeidTarget() { 3438 #if __has_feature(cxx_rtti) 3439 typeid(S2{}); 3440 #endif 3441 } 3442 void sizeofTarget() { 3443 sizeof(S2{}); 3444 } 3445 void noexceptTarget() { 3446 noexcept(S2{}); 3447 } 3448 )cc"; 3449 3450 testFunction(Code, "decltypeTarget"); 3451 testFunction(Code, "typeofTarget"); 3452 testFunction(Code, "typeidTarget"); 3453 testFunction(Code, "sizeofTarget"); 3454 testFunction(Code, "noexceptTarget"); 3455 } 3456 3457 TEST(TransferTest, StaticCast) { 3458 std::string Code = R"( 3459 void target(int Foo) { 3460 int Bar = static_cast<int>(Foo); 3461 // [[p]] 3462 } 3463 )"; 3464 runDataflow( 3465 Code, 3466 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3467 ASTContext &ASTCtx) { 3468 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3469 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3470 3471 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3472 ASSERT_THAT(FooDecl, NotNull()); 3473 3474 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3475 ASSERT_THAT(BarDecl, NotNull()); 3476 3477 const auto *FooVal = Env.getValue(*FooDecl); 3478 const auto *BarVal = Env.getValue(*BarDecl); 3479 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 3480 EXPECT_TRUE(isa<IntegerValue>(BarVal)); 3481 EXPECT_EQ(FooVal, BarVal); 3482 }); 3483 } 3484 3485 TEST(TransferTest, IntegralCast) { 3486 std::string Code = R"( 3487 void target(int Foo) { 3488 long Bar = Foo; 3489 // [[p]] 3490 } 3491 )"; 3492 runDataflow( 3493 Code, 3494 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3495 ASTContext &ASTCtx) { 3496 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3497 3498 const auto &FooVal = getValueForDecl<IntegerValue>(ASTCtx, Env, "Foo"); 3499 const auto &BarVal = getValueForDecl<IntegerValue>(ASTCtx, Env, "Bar"); 3500 EXPECT_EQ(&FooVal, &BarVal); 3501 }); 3502 } 3503 3504 TEST(TransferTest, IntegraltoBooleanCast) { 3505 std::string Code = R"( 3506 void target(int Foo) { 3507 bool Bar = Foo; 3508 // [[p]] 3509 } 3510 )"; 3511 runDataflow( 3512 Code, 3513 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3514 ASTContext &ASTCtx) { 3515 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3516 3517 const auto &FooVal = getValueForDecl(ASTCtx, Env, "Foo"); 3518 const auto &BarVal = getValueForDecl(ASTCtx, Env, "Bar"); 3519 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 3520 EXPECT_TRUE(isa<BoolValue>(BarVal)); 3521 }); 3522 } 3523 3524 TEST(TransferTest, IntegralToBooleanCastFromBool) { 3525 std::string Code = R"( 3526 void target(bool Foo) { 3527 int Zab = Foo; 3528 bool Bar = Zab; 3529 // [[p]] 3530 } 3531 )"; 3532 runDataflow( 3533 Code, 3534 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3535 ASTContext &ASTCtx) { 3536 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3537 3538 const auto &FooVal = getValueForDecl<BoolValue>(ASTCtx, Env, "Foo"); 3539 const auto &BarVal = getValueForDecl<BoolValue>(ASTCtx, Env, "Bar"); 3540 EXPECT_EQ(&FooVal, &BarVal); 3541 }); 3542 } 3543 3544 TEST(TransferTest, WidenBoolValueInIntegerVariable) { 3545 // This is a crash repro. 3546 // This test sets up a case where we perform widening on an integer variable 3547 // that contains a `BoolValue` for the previous iteration and an 3548 // `IntegerValue` for the current iteration. We used to crash on this because 3549 // `widenDistinctValues()` assumed that if the previous iteration had a 3550 // `BoolValue`, the current iteration would too. 3551 // FIXME: The real fix here is to make sure we never store `BoolValue`s in 3552 // integer variables; see also the comment in `widenDistinctValues()`. 3553 std::string Code = R"cc( 3554 struct S { 3555 int i; 3556 S *next; 3557 }; 3558 void target(S *s) { 3559 for (; s; s = s->next) 3560 s->i = false; 3561 } 3562 )cc"; 3563 runDataflow(Code, 3564 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &, 3565 ASTContext &) {}); 3566 } 3567 3568 TEST(TransferTest, NullToPointerCast) { 3569 std::string Code = R"( 3570 using my_nullptr_t = decltype(nullptr); 3571 struct Baz {}; 3572 void target() { 3573 int *FooX = nullptr; 3574 int *FooY = nullptr; 3575 bool **Bar = nullptr; 3576 Baz *Baz = nullptr; 3577 my_nullptr_t Null = 0; 3578 // [[p]] 3579 } 3580 )"; 3581 runDataflow( 3582 Code, 3583 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3584 ASTContext &ASTCtx) { 3585 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3586 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3587 3588 const ValueDecl *FooXDecl = findValueDecl(ASTCtx, "FooX"); 3589 ASSERT_THAT(FooXDecl, NotNull()); 3590 3591 const ValueDecl *FooYDecl = findValueDecl(ASTCtx, "FooY"); 3592 ASSERT_THAT(FooYDecl, NotNull()); 3593 3594 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3595 ASSERT_THAT(BarDecl, NotNull()); 3596 3597 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3598 ASSERT_THAT(BazDecl, NotNull()); 3599 3600 const ValueDecl *NullDecl = findValueDecl(ASTCtx, "Null"); 3601 ASSERT_THAT(NullDecl, NotNull()); 3602 3603 const auto *FooXVal = cast<PointerValue>(Env.getValue(*FooXDecl)); 3604 const auto *FooYVal = cast<PointerValue>(Env.getValue(*FooYDecl)); 3605 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 3606 const auto *BazVal = cast<PointerValue>(Env.getValue(*BazDecl)); 3607 const auto *NullVal = cast<PointerValue>(Env.getValue(*NullDecl)); 3608 3609 EXPECT_EQ(FooXVal, FooYVal); 3610 EXPECT_NE(FooXVal, BarVal); 3611 EXPECT_NE(FooXVal, BazVal); 3612 EXPECT_NE(BarVal, BazVal); 3613 3614 const StorageLocation &FooPointeeLoc = FooXVal->getPointeeLoc(); 3615 EXPECT_TRUE(isa<ScalarStorageLocation>(FooPointeeLoc)); 3616 EXPECT_THAT(Env.getValue(FooPointeeLoc), IsNull()); 3617 3618 const StorageLocation &BarPointeeLoc = BarVal->getPointeeLoc(); 3619 EXPECT_TRUE(isa<ScalarStorageLocation>(BarPointeeLoc)); 3620 EXPECT_THAT(Env.getValue(BarPointeeLoc), IsNull()); 3621 3622 const StorageLocation &BazPointeeLoc = BazVal->getPointeeLoc(); 3623 EXPECT_TRUE(isa<RecordStorageLocation>(BazPointeeLoc)); 3624 EXPECT_EQ(BazVal, &Env.fork().getOrCreateNullPointerValue( 3625 BazPointeeLoc.getType())); 3626 3627 const StorageLocation &NullPointeeLoc = NullVal->getPointeeLoc(); 3628 EXPECT_TRUE(isa<ScalarStorageLocation>(NullPointeeLoc)); 3629 EXPECT_THAT(Env.getValue(NullPointeeLoc), IsNull()); 3630 }); 3631 } 3632 3633 TEST(TransferTest, PointerToMemberVariable) { 3634 std::string Code = R"( 3635 struct S { 3636 int i; 3637 }; 3638 void target() { 3639 int S::*MemberPointer = &S::i; 3640 // [[p]] 3641 } 3642 )"; 3643 runDataflow( 3644 Code, 3645 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3646 ASTContext &ASTCtx) { 3647 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3648 3649 const ValueDecl *MemberPointerDecl = 3650 findValueDecl(ASTCtx, "MemberPointer"); 3651 ASSERT_THAT(MemberPointerDecl, NotNull()); 3652 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 3653 }); 3654 } 3655 3656 TEST(TransferTest, PointerToMemberFunction) { 3657 std::string Code = R"( 3658 struct S { 3659 void Method(); 3660 }; 3661 void target() { 3662 void (S::*MemberPointer)() = &S::Method; 3663 // [[p]] 3664 } 3665 )"; 3666 runDataflow( 3667 Code, 3668 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3669 ASTContext &ASTCtx) { 3670 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3671 3672 const ValueDecl *MemberPointerDecl = 3673 findValueDecl(ASTCtx, "MemberPointer"); 3674 ASSERT_THAT(MemberPointerDecl, NotNull()); 3675 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 3676 }); 3677 } 3678 3679 TEST(TransferTest, NullToMemberPointerCast) { 3680 std::string Code = R"( 3681 struct Foo {}; 3682 void target() { 3683 int Foo::*MemberPointer = nullptr; 3684 // [[p]] 3685 } 3686 )"; 3687 runDataflow( 3688 Code, 3689 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3690 ASTContext &ASTCtx) { 3691 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3692 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3693 3694 const ValueDecl *MemberPointerDecl = 3695 findValueDecl(ASTCtx, "MemberPointer"); 3696 ASSERT_THAT(MemberPointerDecl, NotNull()); 3697 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 3698 }); 3699 } 3700 3701 TEST(TransferTest, AddrOfValue) { 3702 std::string Code = R"( 3703 void target() { 3704 int Foo; 3705 int *Bar = &Foo; 3706 // [[p]] 3707 } 3708 )"; 3709 runDataflow( 3710 Code, 3711 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3712 ASTContext &ASTCtx) { 3713 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3714 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3715 3716 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3717 ASSERT_THAT(FooDecl, NotNull()); 3718 3719 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3720 ASSERT_THAT(BarDecl, NotNull()); 3721 3722 const auto *FooLoc = 3723 cast<ScalarStorageLocation>(Env.getStorageLocation(*FooDecl)); 3724 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 3725 EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc); 3726 }); 3727 } 3728 3729 TEST(TransferTest, AddrOfReference) { 3730 std::string Code = R"( 3731 void target(int *Foo) { 3732 int *Bar = &(*Foo); 3733 // [[p]] 3734 } 3735 )"; 3736 runDataflow( 3737 Code, 3738 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3739 ASTContext &ASTCtx) { 3740 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3741 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3742 3743 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3744 ASSERT_THAT(FooDecl, NotNull()); 3745 3746 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3747 ASSERT_THAT(BarDecl, NotNull()); 3748 3749 const auto *FooVal = cast<PointerValue>(Env.getValue(*FooDecl)); 3750 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 3751 EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc()); 3752 }); 3753 } 3754 3755 TEST(TransferTest, CannotAnalyzeFunctionTemplate) { 3756 std::string Code = R"( 3757 template <typename T> 3758 void target() {} 3759 )"; 3760 ASSERT_THAT_ERROR( 3761 checkDataflowWithNoopAnalysis(Code), 3762 llvm::FailedWithMessage("Cannot analyze templated declarations")); 3763 } 3764 3765 TEST(TransferTest, CannotAnalyzeMethodOfClassTemplate) { 3766 std::string Code = R"( 3767 template <typename T> 3768 struct A { 3769 void target() {} 3770 }; 3771 )"; 3772 ASSERT_THAT_ERROR( 3773 checkDataflowWithNoopAnalysis(Code), 3774 llvm::FailedWithMessage("Cannot analyze templated declarations")); 3775 } 3776 3777 TEST(TransferTest, VarDeclInitAssignConditionalOperator) { 3778 std::string Code = R"( 3779 struct A { 3780 int i; 3781 }; 3782 3783 void target(A Foo, A Bar, bool Cond) { 3784 A Baz = Cond ? A(Foo) : A(Bar); 3785 // Make sure A::i is modeled. 3786 Baz.i; 3787 /*[[p]]*/ 3788 } 3789 )"; 3790 runDataflow( 3791 Code, 3792 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3793 ASTContext &ASTCtx) { 3794 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3795 3796 auto *FooIVal = cast<IntegerValue>(getFieldValue( 3797 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo"), "i", 3798 ASTCtx, Env)); 3799 auto *BarIVal = cast<IntegerValue>(getFieldValue( 3800 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar"), "i", 3801 ASTCtx, Env)); 3802 auto *BazIVal = cast<IntegerValue>(getFieldValue( 3803 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Baz"), "i", 3804 ASTCtx, Env)); 3805 3806 EXPECT_NE(BazIVal, FooIVal); 3807 EXPECT_NE(BazIVal, BarIVal); 3808 }); 3809 } 3810 3811 TEST(TransferTest, VarDeclInDoWhile) { 3812 std::string Code = R"( 3813 void target(int *Foo) { 3814 do { 3815 int Bar = *Foo; 3816 // [[in_loop]] 3817 } while (false); 3818 (void)0; 3819 // [[after_loop]] 3820 } 3821 )"; 3822 runDataflow( 3823 Code, 3824 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3825 ASTContext &ASTCtx) { 3826 const Environment &EnvInLoop = 3827 getEnvironmentAtAnnotation(Results, "in_loop"); 3828 const Environment &EnvAfterLoop = 3829 getEnvironmentAtAnnotation(Results, "after_loop"); 3830 3831 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3832 ASSERT_THAT(FooDecl, NotNull()); 3833 3834 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3835 ASSERT_THAT(BarDecl, NotNull()); 3836 3837 const auto *FooVal = 3838 cast<PointerValue>(EnvAfterLoop.getValue(*FooDecl)); 3839 const auto *FooPointeeVal = 3840 cast<IntegerValue>(EnvAfterLoop.getValue(FooVal->getPointeeLoc())); 3841 3842 const auto *BarVal = cast<IntegerValue>(EnvInLoop.getValue(*BarDecl)); 3843 EXPECT_EQ(BarVal, FooPointeeVal); 3844 3845 ASSERT_THAT(EnvAfterLoop.getValue(*BarDecl), IsNull()); 3846 }); 3847 } 3848 3849 TEST(TransferTest, UnreachableAfterWhileTrue) { 3850 std::string Code = R"( 3851 void target() { 3852 while (true) {} 3853 (void)0; 3854 /*[[p]]*/ 3855 } 3856 )"; 3857 runDataflow( 3858 Code, 3859 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3860 ASTContext &ASTCtx) { 3861 // The node after the while-true is pruned because it is trivially 3862 // known to be unreachable. 3863 ASSERT_TRUE(Results.empty()); 3864 }); 3865 } 3866 3867 TEST(TransferTest, AggregateInitialization) { 3868 std::string BracesCode = R"( 3869 struct A { 3870 int Foo; 3871 }; 3872 3873 struct B { 3874 int Bar; 3875 A Baz; 3876 int Qux; 3877 }; 3878 3879 void target(int BarArg, int FooArg, int QuxArg) { 3880 B Quux{BarArg, {FooArg}, QuxArg}; 3881 B OtherB; 3882 /*[[p]]*/ 3883 } 3884 )"; 3885 std::string BraceElisionCode = R"( 3886 struct A { 3887 int Foo; 3888 }; 3889 3890 struct B { 3891 int Bar; 3892 A Baz; 3893 int Qux; 3894 }; 3895 3896 void target(int BarArg, int FooArg, int QuxArg) { 3897 B Quux = {BarArg, FooArg, QuxArg}; 3898 B OtherB; 3899 /*[[p]]*/ 3900 } 3901 )"; 3902 for (const std::string &Code : {BracesCode, BraceElisionCode}) { 3903 runDataflow( 3904 Code, 3905 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3906 ASTContext &ASTCtx) { 3907 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3908 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3909 3910 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3911 ASSERT_THAT(FooDecl, NotNull()); 3912 3913 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3914 ASSERT_THAT(BarDecl, NotNull()); 3915 3916 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3917 ASSERT_THAT(BazDecl, NotNull()); 3918 3919 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 3920 ASSERT_THAT(QuxDecl, NotNull()); 3921 3922 const ValueDecl *FooArgDecl = findValueDecl(ASTCtx, "FooArg"); 3923 ASSERT_THAT(FooArgDecl, NotNull()); 3924 3925 const ValueDecl *BarArgDecl = findValueDecl(ASTCtx, "BarArg"); 3926 ASSERT_THAT(BarArgDecl, NotNull()); 3927 3928 const ValueDecl *QuxArgDecl = findValueDecl(ASTCtx, "QuxArg"); 3929 ASSERT_THAT(QuxArgDecl, NotNull()); 3930 3931 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 3932 ASSERT_THAT(QuuxDecl, NotNull()); 3933 3934 const auto *FooArgVal = cast<IntegerValue>(Env.getValue(*FooArgDecl)); 3935 const auto *BarArgVal = cast<IntegerValue>(Env.getValue(*BarArgDecl)); 3936 const auto *QuxArgVal = cast<IntegerValue>(Env.getValue(*QuxArgDecl)); 3937 3938 const auto &QuuxLoc = 3939 *cast<RecordStorageLocation>(Env.getStorageLocation(*QuuxDecl)); 3940 const auto &BazLoc = 3941 *cast<RecordStorageLocation>(QuuxLoc.getChild(*BazDecl)); 3942 3943 EXPECT_EQ(getFieldValue(&QuuxLoc, *BarDecl, Env), BarArgVal); 3944 EXPECT_EQ(getFieldValue(&BazLoc, *FooDecl, Env), FooArgVal); 3945 EXPECT_EQ(getFieldValue(&QuuxLoc, *QuxDecl, Env), QuxArgVal); 3946 3947 // Check that fields initialized in an initializer list are always 3948 // modeled in other instances of the same type. 3949 const auto &OtherBLoc = 3950 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "OtherB"); 3951 EXPECT_THAT(OtherBLoc.getChild(*BarDecl), NotNull()); 3952 EXPECT_THAT(OtherBLoc.getChild(*BazDecl), NotNull()); 3953 EXPECT_THAT(OtherBLoc.getChild(*QuxDecl), NotNull()); 3954 }); 3955 } 3956 } 3957 3958 TEST(TransferTest, AggregateInitializationReferenceField) { 3959 std::string Code = R"( 3960 struct S { 3961 int &RefField; 3962 }; 3963 3964 void target(int i) { 3965 S s = { i }; 3966 /*[[p]]*/ 3967 } 3968 )"; 3969 runDataflow( 3970 Code, 3971 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3972 ASTContext &ASTCtx) { 3973 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3974 3975 const ValueDecl *RefFieldDecl = findValueDecl(ASTCtx, "RefField"); 3976 3977 auto &ILoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "i"); 3978 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"); 3979 3980 EXPECT_EQ(SLoc.getChild(*RefFieldDecl), &ILoc); 3981 }); 3982 } 3983 3984 TEST(TransferTest, AggregateInitialization_NotExplicitlyInitializedField) { 3985 std::string Code = R"( 3986 struct S { 3987 int i1; 3988 int i2; 3989 }; 3990 3991 void target(int i) { 3992 S s = { i }; 3993 /*[[p]]*/ 3994 } 3995 )"; 3996 runDataflow( 3997 Code, 3998 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3999 ASTContext &ASTCtx) { 4000 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4001 4002 const ValueDecl *I1FieldDecl = findValueDecl(ASTCtx, "i1"); 4003 const ValueDecl *I2FieldDecl = findValueDecl(ASTCtx, "i2"); 4004 4005 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"); 4006 4007 auto &IValue = getValueForDecl<IntegerValue>(ASTCtx, Env, "i"); 4008 auto &I1Value = 4009 *cast<IntegerValue>(getFieldValue(&SLoc, *I1FieldDecl, Env)); 4010 EXPECT_EQ(&I1Value, &IValue); 4011 auto &I2Value = 4012 *cast<IntegerValue>(getFieldValue(&SLoc, *I2FieldDecl, Env)); 4013 EXPECT_NE(&I2Value, &IValue); 4014 }); 4015 } 4016 4017 TEST(TransferTest, AggregateInitializationFunctionPointer) { 4018 // This is a repro for an assertion failure. 4019 // nullptr takes on the type of a const function pointer, but its type was 4020 // asserted to be equal to the *unqualified* type of Field, which no longer 4021 // included the const. 4022 std::string Code = R"( 4023 struct S { 4024 void (*const Field)(); 4025 }; 4026 4027 void target() { 4028 S s{nullptr}; 4029 } 4030 )"; 4031 runDataflow( 4032 Code, 4033 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4034 ASTContext &ASTCtx) {}); 4035 } 4036 4037 TEST(TransferTest, AssignToUnionMember) { 4038 std::string Code = R"( 4039 union A { 4040 int Foo; 4041 }; 4042 4043 void target(int Bar) { 4044 A Baz; 4045 Baz.Foo = Bar; 4046 // [[p]] 4047 } 4048 )"; 4049 runDataflow( 4050 Code, 4051 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4052 ASTContext &ASTCtx) { 4053 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4054 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4055 4056 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4057 ASSERT_THAT(BazDecl, NotNull()); 4058 ASSERT_TRUE(BazDecl->getType()->isUnionType()); 4059 4060 auto BazFields = BazDecl->getType()->getAsRecordDecl()->fields(); 4061 FieldDecl *FooDecl = nullptr; 4062 for (FieldDecl *Field : BazFields) { 4063 if (Field->getNameAsString() == "Foo") { 4064 FooDecl = Field; 4065 } else { 4066 FAIL() << "Unexpected field: " << Field->getNameAsString(); 4067 } 4068 } 4069 ASSERT_THAT(FooDecl, NotNull()); 4070 4071 const auto *BazLoc = dyn_cast_or_null<RecordStorageLocation>( 4072 Env.getStorageLocation(*BazDecl)); 4073 ASSERT_THAT(BazLoc, NotNull()); 4074 4075 const auto *FooVal = 4076 cast<IntegerValue>(getFieldValue(BazLoc, *FooDecl, Env)); 4077 4078 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4079 ASSERT_THAT(BarDecl, NotNull()); 4080 const auto *BarLoc = Env.getStorageLocation(*BarDecl); 4081 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 4082 4083 EXPECT_EQ(Env.getValue(*BarLoc), FooVal); 4084 }); 4085 } 4086 4087 TEST(TransferTest, AssignFromBoolLiteral) { 4088 std::string Code = R"( 4089 void target() { 4090 bool Foo = true; 4091 bool Bar = false; 4092 // [[p]] 4093 } 4094 )"; 4095 runDataflow( 4096 Code, 4097 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4098 ASTContext &ASTCtx) { 4099 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4100 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4101 4102 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4103 ASSERT_THAT(FooDecl, NotNull()); 4104 4105 const auto *FooVal = 4106 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 4107 ASSERT_THAT(FooVal, NotNull()); 4108 4109 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4110 ASSERT_THAT(BarDecl, NotNull()); 4111 4112 const auto *BarVal = 4113 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 4114 ASSERT_THAT(BarVal, NotNull()); 4115 4116 EXPECT_EQ(FooVal, &Env.getBoolLiteralValue(true)); 4117 EXPECT_EQ(BarVal, &Env.getBoolLiteralValue(false)); 4118 }); 4119 } 4120 4121 TEST(TransferTest, AssignFromCompositeBoolExpression) { 4122 { 4123 std::string Code = R"( 4124 void target(bool Foo, bool Bar, bool Qux) { 4125 bool Baz = (Foo) && (Bar || Qux); 4126 // [[p]] 4127 } 4128 )"; 4129 runDataflow( 4130 Code, 4131 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4132 ASTContext &ASTCtx) { 4133 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4134 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4135 4136 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4137 ASSERT_THAT(FooDecl, NotNull()); 4138 4139 const auto *FooVal = 4140 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 4141 ASSERT_THAT(FooVal, NotNull()); 4142 4143 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4144 ASSERT_THAT(BarDecl, NotNull()); 4145 4146 const auto *BarVal = 4147 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 4148 ASSERT_THAT(BarVal, NotNull()); 4149 4150 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4151 ASSERT_THAT(QuxDecl, NotNull()); 4152 4153 const auto *QuxVal = 4154 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl)); 4155 ASSERT_THAT(QuxVal, NotNull()); 4156 4157 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4158 ASSERT_THAT(BazDecl, NotNull()); 4159 4160 const auto *BazVal = 4161 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl)); 4162 ASSERT_THAT(BazVal, NotNull()); 4163 auto &A = Env.arena(); 4164 EXPECT_EQ(&BazVal->formula(), 4165 &A.makeAnd(FooVal->formula(), 4166 A.makeOr(BarVal->formula(), QuxVal->formula()))); 4167 }); 4168 } 4169 4170 { 4171 std::string Code = R"( 4172 void target(bool Foo, bool Bar, bool Qux) { 4173 bool Baz = (Foo && Qux) || (Bar); 4174 // [[p]] 4175 } 4176 )"; 4177 runDataflow( 4178 Code, 4179 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4180 ASTContext &ASTCtx) { 4181 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4182 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4183 4184 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4185 ASSERT_THAT(FooDecl, NotNull()); 4186 4187 const auto *FooVal = 4188 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 4189 ASSERT_THAT(FooVal, NotNull()); 4190 4191 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4192 ASSERT_THAT(BarDecl, NotNull()); 4193 4194 const auto *BarVal = 4195 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 4196 ASSERT_THAT(BarVal, NotNull()); 4197 4198 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4199 ASSERT_THAT(QuxDecl, NotNull()); 4200 4201 const auto *QuxVal = 4202 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl)); 4203 ASSERT_THAT(QuxVal, NotNull()); 4204 4205 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4206 ASSERT_THAT(BazDecl, NotNull()); 4207 4208 const auto *BazVal = 4209 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl)); 4210 ASSERT_THAT(BazVal, NotNull()); 4211 auto &A = Env.arena(); 4212 EXPECT_EQ(&BazVal->formula(), 4213 &A.makeOr(A.makeAnd(FooVal->formula(), QuxVal->formula()), 4214 BarVal->formula())); 4215 }); 4216 } 4217 4218 { 4219 std::string Code = R"( 4220 void target(bool A, bool B, bool C, bool D) { 4221 bool Foo = ((A && B) && C) && D; 4222 // [[p]] 4223 } 4224 )"; 4225 runDataflow( 4226 Code, 4227 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4228 ASTContext &ASTCtx) { 4229 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4230 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4231 4232 const ValueDecl *ADecl = findValueDecl(ASTCtx, "A"); 4233 ASSERT_THAT(ADecl, NotNull()); 4234 4235 const auto *AVal = dyn_cast_or_null<BoolValue>(Env.getValue(*ADecl)); 4236 ASSERT_THAT(AVal, NotNull()); 4237 4238 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B"); 4239 ASSERT_THAT(BDecl, NotNull()); 4240 4241 const auto *BVal = dyn_cast_or_null<BoolValue>(Env.getValue(*BDecl)); 4242 ASSERT_THAT(BVal, NotNull()); 4243 4244 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C"); 4245 ASSERT_THAT(CDecl, NotNull()); 4246 4247 const auto *CVal = dyn_cast_or_null<BoolValue>(Env.getValue(*CDecl)); 4248 ASSERT_THAT(CVal, NotNull()); 4249 4250 const ValueDecl *DDecl = findValueDecl(ASTCtx, "D"); 4251 ASSERT_THAT(DDecl, NotNull()); 4252 4253 const auto *DVal = dyn_cast_or_null<BoolValue>(Env.getValue(*DDecl)); 4254 ASSERT_THAT(DVal, NotNull()); 4255 4256 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4257 ASSERT_THAT(FooDecl, NotNull()); 4258 4259 const auto *FooVal = 4260 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 4261 ASSERT_THAT(FooVal, NotNull()); 4262 auto &A = Env.arena(); 4263 EXPECT_EQ( 4264 &FooVal->formula(), 4265 &A.makeAnd(A.makeAnd(A.makeAnd(AVal->formula(), BVal->formula()), 4266 CVal->formula()), 4267 DVal->formula())); 4268 }); 4269 } 4270 } 4271 4272 TEST(TransferTest, AssignFromBoolNegation) { 4273 std::string Code = R"( 4274 void target() { 4275 bool Foo = true; 4276 bool Bar = !(Foo); 4277 // [[p]] 4278 } 4279 )"; 4280 runDataflow( 4281 Code, 4282 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4283 ASTContext &ASTCtx) { 4284 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4285 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4286 4287 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4288 ASSERT_THAT(FooDecl, NotNull()); 4289 4290 const auto *FooVal = 4291 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 4292 ASSERT_THAT(FooVal, NotNull()); 4293 4294 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4295 ASSERT_THAT(BarDecl, NotNull()); 4296 4297 const auto *BarVal = 4298 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 4299 ASSERT_THAT(BarVal, NotNull()); 4300 auto &A = Env.arena(); 4301 EXPECT_EQ(&BarVal->formula(), &A.makeNot(FooVal->formula())); 4302 }); 4303 } 4304 4305 TEST(TransferTest, BuiltinExpect) { 4306 std::string Code = R"( 4307 void target(long Foo) { 4308 long Bar = __builtin_expect(Foo, true); 4309 /*[[p]]*/ 4310 } 4311 )"; 4312 runDataflow( 4313 Code, 4314 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4315 ASTContext &ASTCtx) { 4316 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4317 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4318 4319 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4320 ASSERT_THAT(FooDecl, NotNull()); 4321 4322 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4323 ASSERT_THAT(BarDecl, NotNull()); 4324 4325 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 4326 }); 4327 } 4328 4329 // `__builtin_expect` takes and returns a `long` argument, so other types 4330 // involve casts. This verifies that we identify the input and output in that 4331 // case. 4332 TEST(TransferTest, BuiltinExpectBoolArg) { 4333 std::string Code = R"( 4334 void target(bool Foo) { 4335 bool Bar = __builtin_expect(Foo, true); 4336 /*[[p]]*/ 4337 } 4338 )"; 4339 runDataflow( 4340 Code, 4341 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4342 ASTContext &ASTCtx) { 4343 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4344 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4345 4346 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4347 ASSERT_THAT(FooDecl, NotNull()); 4348 4349 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4350 ASSERT_THAT(BarDecl, NotNull()); 4351 4352 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 4353 }); 4354 } 4355 4356 TEST(TransferTest, BuiltinUnreachable) { 4357 std::string Code = R"( 4358 void target(bool Foo) { 4359 bool Bar = false; 4360 if (Foo) 4361 Bar = Foo; 4362 else 4363 __builtin_unreachable(); 4364 (void)0; 4365 /*[[p]]*/ 4366 } 4367 )"; 4368 runDataflow( 4369 Code, 4370 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4371 ASTContext &ASTCtx) { 4372 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4373 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4374 4375 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4376 ASSERT_THAT(FooDecl, NotNull()); 4377 4378 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4379 ASSERT_THAT(BarDecl, NotNull()); 4380 4381 // `__builtin_unreachable` promises that the code is 4382 // unreachable, so the compiler treats the "then" branch as the 4383 // only possible predecessor of this statement. 4384 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 4385 }); 4386 } 4387 4388 TEST(TransferTest, BuiltinTrap) { 4389 std::string Code = R"( 4390 void target(bool Foo) { 4391 bool Bar = false; 4392 if (Foo) 4393 Bar = Foo; 4394 else 4395 __builtin_trap(); 4396 (void)0; 4397 /*[[p]]*/ 4398 } 4399 )"; 4400 runDataflow( 4401 Code, 4402 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4403 ASTContext &ASTCtx) { 4404 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4405 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4406 4407 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4408 ASSERT_THAT(FooDecl, NotNull()); 4409 4410 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4411 ASSERT_THAT(BarDecl, NotNull()); 4412 4413 // `__builtin_trap` ensures program termination, so only the 4414 // "then" branch is a predecessor of this statement. 4415 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 4416 }); 4417 } 4418 4419 TEST(TransferTest, BuiltinDebugTrap) { 4420 std::string Code = R"( 4421 void target(bool Foo) { 4422 bool Bar = false; 4423 if (Foo) 4424 Bar = Foo; 4425 else 4426 __builtin_debugtrap(); 4427 (void)0; 4428 /*[[p]]*/ 4429 } 4430 )"; 4431 runDataflow( 4432 Code, 4433 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4434 ASTContext &ASTCtx) { 4435 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4436 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4437 4438 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4439 ASSERT_THAT(FooDecl, NotNull()); 4440 4441 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4442 ASSERT_THAT(BarDecl, NotNull()); 4443 4444 // `__builtin_debugtrap` doesn't ensure program termination. 4445 EXPECT_NE(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 4446 }); 4447 } 4448 4449 TEST(TransferTest, StaticIntSingleVarDecl) { 4450 std::string Code = R"( 4451 void target() { 4452 static int Foo; 4453 // [[p]] 4454 } 4455 )"; 4456 runDataflow( 4457 Code, 4458 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4459 ASTContext &ASTCtx) { 4460 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4461 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4462 4463 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4464 ASSERT_THAT(FooDecl, NotNull()); 4465 4466 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 4467 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 4468 4469 const Value *FooVal = Env.getValue(*FooLoc); 4470 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 4471 }); 4472 } 4473 4474 TEST(TransferTest, StaticIntGroupVarDecl) { 4475 std::string Code = R"( 4476 void target() { 4477 static int Foo, Bar; 4478 (void)0; 4479 // [[p]] 4480 } 4481 )"; 4482 runDataflow( 4483 Code, 4484 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4485 ASTContext &ASTCtx) { 4486 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4487 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4488 4489 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4490 ASSERT_THAT(FooDecl, NotNull()); 4491 4492 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4493 ASSERT_THAT(BarDecl, NotNull()); 4494 4495 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 4496 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 4497 4498 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 4499 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 4500 4501 const Value *FooVal = Env.getValue(*FooLoc); 4502 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 4503 4504 const Value *BarVal = Env.getValue(*BarLoc); 4505 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 4506 4507 EXPECT_NE(FooVal, BarVal); 4508 }); 4509 } 4510 4511 TEST(TransferTest, GlobalIntVarDecl) { 4512 std::string Code = R"( 4513 static int Foo; 4514 4515 void target() { 4516 int Bar = Foo; 4517 int Baz = Foo; 4518 // [[p]] 4519 } 4520 )"; 4521 runDataflow( 4522 Code, 4523 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4524 ASTContext &ASTCtx) { 4525 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4526 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4527 4528 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4529 ASSERT_THAT(BarDecl, NotNull()); 4530 4531 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4532 ASSERT_THAT(BazDecl, NotNull()); 4533 4534 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 4535 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 4536 EXPECT_EQ(BarVal, BazVal); 4537 }); 4538 } 4539 4540 TEST(TransferTest, StaticMemberIntVarDecl) { 4541 std::string Code = R"( 4542 struct A { 4543 static int Foo; 4544 }; 4545 4546 void target(A a) { 4547 int Bar = a.Foo; 4548 int Baz = a.Foo; 4549 // [[p]] 4550 } 4551 )"; 4552 runDataflow( 4553 Code, 4554 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4555 ASTContext &ASTCtx) { 4556 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4557 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4558 4559 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4560 ASSERT_THAT(BarDecl, NotNull()); 4561 4562 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4563 ASSERT_THAT(BazDecl, NotNull()); 4564 4565 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 4566 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 4567 EXPECT_EQ(BarVal, BazVal); 4568 }); 4569 } 4570 4571 TEST(TransferTest, StaticMemberRefVarDecl) { 4572 std::string Code = R"( 4573 struct A { 4574 static int &Foo; 4575 }; 4576 4577 void target(A a) { 4578 int Bar = a.Foo; 4579 int Baz = a.Foo; 4580 // [[p]] 4581 } 4582 )"; 4583 runDataflow( 4584 Code, 4585 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4586 ASTContext &ASTCtx) { 4587 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4588 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4589 4590 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4591 ASSERT_THAT(BarDecl, NotNull()); 4592 4593 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4594 ASSERT_THAT(BazDecl, NotNull()); 4595 4596 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 4597 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 4598 EXPECT_EQ(BarVal, BazVal); 4599 }); 4600 } 4601 4602 TEST(TransferTest, AssignMemberBeforeCopy) { 4603 std::string Code = R"( 4604 struct A { 4605 int Foo; 4606 }; 4607 4608 void target() { 4609 A A1; 4610 A A2; 4611 int Bar; 4612 A1.Foo = Bar; 4613 A2 = A1; 4614 // [[p]] 4615 } 4616 )"; 4617 runDataflow( 4618 Code, 4619 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4620 ASTContext &ASTCtx) { 4621 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4622 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4623 4624 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4625 ASSERT_THAT(FooDecl, NotNull()); 4626 4627 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4628 ASSERT_THAT(BarDecl, NotNull()); 4629 4630 const ValueDecl *A1Decl = findValueDecl(ASTCtx, "A1"); 4631 ASSERT_THAT(A1Decl, NotNull()); 4632 4633 const ValueDecl *A2Decl = findValueDecl(ASTCtx, "A2"); 4634 ASSERT_THAT(A2Decl, NotNull()); 4635 4636 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 4637 4638 const auto &A2Loc = 4639 *cast<RecordStorageLocation>(Env.getStorageLocation(*A2Decl)); 4640 EXPECT_EQ(getFieldValue(&A2Loc, *FooDecl, Env), BarVal); 4641 }); 4642 } 4643 4644 TEST(TransferTest, BooleanEquality) { 4645 std::string Code = R"( 4646 void target(bool Bar) { 4647 bool Foo = true; 4648 if (Bar == Foo) { 4649 (void)0; 4650 /*[[p-then]]*/ 4651 } else { 4652 (void)0; 4653 /*[[p-else]]*/ 4654 } 4655 } 4656 )"; 4657 runDataflow( 4658 Code, 4659 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4660 ASTContext &ASTCtx) { 4661 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else")); 4662 const Environment &EnvThen = 4663 getEnvironmentAtAnnotation(Results, "p-then"); 4664 const Environment &EnvElse = 4665 getEnvironmentAtAnnotation(Results, "p-else"); 4666 4667 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4668 ASSERT_THAT(BarDecl, NotNull()); 4669 4670 auto &BarValThen = getFormula(*BarDecl, EnvThen); 4671 EXPECT_TRUE(EnvThen.proves(BarValThen)); 4672 4673 auto &BarValElse = getFormula(*BarDecl, EnvElse); 4674 EXPECT_TRUE(EnvElse.proves(EnvElse.arena().makeNot(BarValElse))); 4675 }); 4676 } 4677 4678 TEST(TransferTest, BooleanInequality) { 4679 std::string Code = R"( 4680 void target(bool Bar) { 4681 bool Foo = true; 4682 if (Bar != Foo) { 4683 (void)0; 4684 /*[[p-then]]*/ 4685 } else { 4686 (void)0; 4687 /*[[p-else]]*/ 4688 } 4689 } 4690 )"; 4691 runDataflow( 4692 Code, 4693 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4694 ASTContext &ASTCtx) { 4695 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else")); 4696 const Environment &EnvThen = 4697 getEnvironmentAtAnnotation(Results, "p-then"); 4698 const Environment &EnvElse = 4699 getEnvironmentAtAnnotation(Results, "p-else"); 4700 4701 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4702 ASSERT_THAT(BarDecl, NotNull()); 4703 4704 auto &BarValThen = getFormula(*BarDecl, EnvThen); 4705 EXPECT_TRUE(EnvThen.proves(EnvThen.arena().makeNot(BarValThen))); 4706 4707 auto &BarValElse = getFormula(*BarDecl, EnvElse); 4708 EXPECT_TRUE(EnvElse.proves(BarValElse)); 4709 }); 4710 } 4711 4712 TEST(TransferTest, PointerEquality) { 4713 std::string Code = R"cc( 4714 void target() { 4715 int i = 0; 4716 int i_other = 0; 4717 int *p1 = &i; 4718 int *p2 = &i; 4719 int *p_other = &i_other; 4720 int *null = nullptr; 4721 4722 bool p1_eq_p1 = (p1 == p1); 4723 bool p1_eq_p2 = (p1 == p2); 4724 bool p1_eq_p_other = (p1 == p_other); 4725 4726 bool p1_eq_null = (p1 == null); 4727 bool p1_eq_nullptr = (p1 == nullptr); 4728 bool null_eq_nullptr = (null == nullptr); 4729 bool nullptr_eq_nullptr = (nullptr == nullptr); 4730 4731 // We won't duplicate all of the tests above with `!=`, as we know that 4732 // the implementation simply negates the result of the `==` comparison. 4733 // Instaed, just spot-check one case. 4734 bool p1_ne_p1 = (p1 != p1); 4735 4736 (void)0; // [[p]] 4737 } 4738 )cc"; 4739 runDataflow( 4740 Code, 4741 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4742 ASTContext &ASTCtx) { 4743 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4744 4745 // Check the we have indeed set things up so that `p1` and `p2` have 4746 // different pointer values. 4747 EXPECT_NE(&getValueForDecl<PointerValue>(ASTCtx, Env, "p1"), 4748 &getValueForDecl<PointerValue>(ASTCtx, Env, "p2")); 4749 4750 EXPECT_EQ(&getValueForDecl<BoolValue>(ASTCtx, Env, "p1_eq_p1"), 4751 &Env.getBoolLiteralValue(true)); 4752 EXPECT_EQ(&getValueForDecl<BoolValue>(ASTCtx, Env, "p1_eq_p2"), 4753 &Env.getBoolLiteralValue(true)); 4754 EXPECT_TRUE(isa<AtomicBoolValue>( 4755 getValueForDecl<BoolValue>(ASTCtx, Env, "p1_eq_p_other"))); 4756 4757 EXPECT_TRUE(isa<AtomicBoolValue>( 4758 getValueForDecl<BoolValue>(ASTCtx, Env, "p1_eq_null"))); 4759 EXPECT_TRUE(isa<AtomicBoolValue>( 4760 getValueForDecl<BoolValue>(ASTCtx, Env, "p1_eq_nullptr"))); 4761 EXPECT_EQ(&getValueForDecl<BoolValue>(ASTCtx, Env, "null_eq_nullptr"), 4762 &Env.getBoolLiteralValue(true)); 4763 EXPECT_EQ( 4764 &getValueForDecl<BoolValue>(ASTCtx, Env, "nullptr_eq_nullptr"), 4765 &Env.getBoolLiteralValue(true)); 4766 4767 EXPECT_EQ(&getValueForDecl<BoolValue>(ASTCtx, Env, "p1_ne_p1"), 4768 &Env.getBoolLiteralValue(false)); 4769 }); 4770 } 4771 4772 TEST(TransferTest, PointerEqualityUnionMembers) { 4773 std::string Code = R"cc( 4774 union U { 4775 int i1; 4776 int i2; 4777 }; 4778 void target() { 4779 U u; 4780 bool i1_eq_i2 = (&u.i1 == &u.i2); 4781 4782 (void)0; // [[p]] 4783 } 4784 )cc"; 4785 runDataflow( 4786 Code, 4787 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4788 ASTContext &ASTCtx) { 4789 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4790 4791 // FIXME: By the standard, `u.i1` and `u.i2` should have the same 4792 // address, but we don't yet model this property of union members 4793 // correctly. The result is therefore weaker than it could be (just an 4794 // atom rather than a true literal), though not wrong. 4795 EXPECT_TRUE(isa<AtomicBoolValue>( 4796 getValueForDecl<BoolValue>(ASTCtx, Env, "i1_eq_i2"))); 4797 }); 4798 } 4799 4800 TEST(TransferTest, IntegerLiteralEquality) { 4801 std::string Code = R"( 4802 void target() { 4803 bool equal = (42 == 42); 4804 // [[p]] 4805 } 4806 )"; 4807 runDataflow( 4808 Code, 4809 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4810 ASTContext &ASTCtx) { 4811 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4812 4813 auto &Equal = 4814 getValueForDecl<BoolValue>(ASTCtx, Env, "equal").formula(); 4815 EXPECT_TRUE(Env.proves(Equal)); 4816 }); 4817 } 4818 4819 TEST(TransferTest, CorrelatedBranches) { 4820 std::string Code = R"( 4821 void target(bool B, bool C) { 4822 if (B) { 4823 return; 4824 } 4825 (void)0; 4826 /*[[p0]]*/ 4827 if (C) { 4828 B = true; 4829 /*[[p1]]*/ 4830 } 4831 if (B) { 4832 (void)0; 4833 /*[[p2]]*/ 4834 } 4835 } 4836 )"; 4837 runDataflow( 4838 Code, 4839 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4840 ASTContext &ASTCtx) { 4841 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p0", "p1", "p2")); 4842 4843 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C"); 4844 ASSERT_THAT(CDecl, NotNull()); 4845 4846 { 4847 const Environment &Env = getEnvironmentAtAnnotation(Results, "p0"); 4848 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B"); 4849 ASSERT_THAT(BDecl, NotNull()); 4850 auto &BVal = getFormula(*BDecl, Env); 4851 4852 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BVal))); 4853 } 4854 4855 { 4856 const Environment &Env = getEnvironmentAtAnnotation(Results, "p1"); 4857 auto &CVal = getFormula(*CDecl, Env); 4858 EXPECT_TRUE(Env.proves(CVal)); 4859 } 4860 4861 { 4862 const Environment &Env = getEnvironmentAtAnnotation(Results, "p2"); 4863 auto &CVal = getFormula(*CDecl, Env); 4864 EXPECT_TRUE(Env.proves(CVal)); 4865 } 4866 }); 4867 } 4868 4869 TEST(TransferTest, LoopWithAssignmentConverges) { 4870 std::string Code = R"( 4871 bool foo(); 4872 4873 void target() { 4874 do { 4875 bool Bar = foo(); 4876 if (Bar) break; 4877 (void)Bar; 4878 /*[[p]]*/ 4879 } while (true); 4880 } 4881 )"; 4882 // The key property that we are verifying is implicit in `runDataflow` -- 4883 // namely, that the analysis succeeds, rather than hitting the maximum number 4884 // of iterations. 4885 runDataflow( 4886 Code, 4887 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4888 ASTContext &ASTCtx) { 4889 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4890 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4891 4892 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4893 ASSERT_THAT(BarDecl, NotNull()); 4894 4895 auto &BarVal = getFormula(*BarDecl, Env); 4896 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 4897 }); 4898 } 4899 4900 TEST(TransferTest, LoopWithStagedAssignments) { 4901 std::string Code = R"( 4902 bool foo(); 4903 4904 void target() { 4905 bool Bar = false; 4906 bool Err = false; 4907 while (foo()) { 4908 if (Bar) 4909 Err = true; 4910 Bar = true; 4911 /*[[p]]*/ 4912 } 4913 } 4914 )"; 4915 runDataflow( 4916 Code, 4917 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4918 ASTContext &ASTCtx) { 4919 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4920 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4921 4922 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4923 ASSERT_THAT(BarDecl, NotNull()); 4924 const ValueDecl *ErrDecl = findValueDecl(ASTCtx, "Err"); 4925 ASSERT_THAT(ErrDecl, NotNull()); 4926 4927 auto &BarVal = getFormula(*BarDecl, Env); 4928 auto &ErrVal = getFormula(*ErrDecl, Env); 4929 EXPECT_TRUE(Env.proves(BarVal)); 4930 // An unsound analysis, for example only evaluating the loop once, can 4931 // conclude that `Err` is false. So, we test that this conclusion is not 4932 // reached. 4933 EXPECT_FALSE(Env.proves(Env.arena().makeNot(ErrVal))); 4934 }); 4935 } 4936 4937 TEST(TransferTest, LoopWithReferenceAssignmentConverges) { 4938 std::string Code = R"( 4939 bool &foo(); 4940 4941 void target() { 4942 do { 4943 bool& Bar = foo(); 4944 if (Bar) break; 4945 (void)Bar; 4946 /*[[p]]*/ 4947 } while (true); 4948 } 4949 )"; 4950 // The key property that we are verifying is that the analysis succeeds, 4951 // rather than hitting the maximum number of iterations. 4952 runDataflow( 4953 Code, 4954 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4955 ASTContext &ASTCtx) { 4956 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4957 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4958 4959 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4960 ASSERT_THAT(BarDecl, NotNull()); 4961 4962 auto &BarVal = getFormula(*BarDecl, Env); 4963 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 4964 }); 4965 } 4966 4967 TEST(TransferTest, LoopWithStructReferenceAssignmentConverges) { 4968 std::string Code = R"( 4969 struct Lookup { 4970 int x; 4971 }; 4972 4973 void target(Lookup val, bool b) { 4974 const Lookup* l = nullptr; 4975 while (b) { 4976 l = &val; 4977 /*[[p-inner]]*/ 4978 } 4979 (void)0; 4980 /*[[p-outer]]*/ 4981 } 4982 )"; 4983 // The key property that we are verifying is implicit in `runDataflow` -- 4984 // namely, that the analysis succeeds, rather than hitting the maximum number 4985 // of iterations. 4986 runDataflow( 4987 Code, 4988 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4989 ASTContext &ASTCtx) { 4990 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-inner", "p-outer")); 4991 const Environment &InnerEnv = 4992 getEnvironmentAtAnnotation(Results, "p-inner"); 4993 const Environment &OuterEnv = 4994 getEnvironmentAtAnnotation(Results, "p-outer"); 4995 4996 const ValueDecl *ValDecl = findValueDecl(ASTCtx, "val"); 4997 ASSERT_THAT(ValDecl, NotNull()); 4998 4999 const ValueDecl *LDecl = findValueDecl(ASTCtx, "l"); 5000 ASSERT_THAT(LDecl, NotNull()); 5001 5002 // Inner. 5003 auto *LVal = dyn_cast<PointerValue>(InnerEnv.getValue(*LDecl)); 5004 ASSERT_THAT(LVal, NotNull()); 5005 5006 EXPECT_EQ(&LVal->getPointeeLoc(), 5007 InnerEnv.getStorageLocation(*ValDecl)); 5008 5009 // Outer. 5010 LVal = dyn_cast<PointerValue>(OuterEnv.getValue(*LDecl)); 5011 ASSERT_THAT(LVal, NotNull()); 5012 5013 // The loop body may not have been executed, so we should not conclude 5014 // that `l` points to `val`. 5015 EXPECT_NE(&LVal->getPointeeLoc(), 5016 OuterEnv.getStorageLocation(*ValDecl)); 5017 }); 5018 } 5019 5020 TEST(TransferTest, LoopDereferencingChangingPointerConverges) { 5021 std::string Code = R"cc( 5022 bool some_condition(); 5023 5024 void target(int i1, int i2) { 5025 int *p = &i1; 5026 while (true) { 5027 (void)*p; 5028 if (some_condition()) 5029 p = &i1; 5030 else 5031 p = &i2; 5032 } 5033 } 5034 )cc"; 5035 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 5036 } 5037 5038 TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) { 5039 std::string Code = R"cc( 5040 struct Lookup { 5041 int x; 5042 }; 5043 5044 bool some_condition(); 5045 5046 void target(Lookup l1, Lookup l2) { 5047 Lookup *l = &l1; 5048 while (true) { 5049 (void)l->x; 5050 if (some_condition()) 5051 l = &l1; 5052 else 5053 l = &l2; 5054 } 5055 } 5056 )cc"; 5057 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 5058 } 5059 5060 TEST(TransferTest, LoopWithShortCircuitedConditionConverges) { 5061 std::string Code = R"cc( 5062 bool foo(); 5063 5064 void target() { 5065 bool c = false; 5066 while (foo() || foo()) { 5067 c = true; 5068 } 5069 } 5070 )cc"; 5071 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 5072 } 5073 5074 TEST(TransferTest, LoopCanProveInvariantForBoolean) { 5075 // Check that we can prove `b` is always false in the loop. 5076 // This test exercises the logic in `widenDistinctValues()` that preserves 5077 // information if the boolean can be proved to be either true or false in both 5078 // the previous and current iteration. 5079 std::string Code = R"cc( 5080 int return_int(); 5081 void target() { 5082 bool b = return_int() == 0; 5083 if (b) return; 5084 while (true) { 5085 b; 5086 // [[p]] 5087 b = return_int() == 0; 5088 if (b) return; 5089 } 5090 } 5091 )cc"; 5092 runDataflow( 5093 Code, 5094 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5095 ASTContext &ASTCtx) { 5096 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5097 auto &BVal = getValueForDecl<BoolValue>(ASTCtx, Env, "b"); 5098 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BVal.formula()))); 5099 }); 5100 } 5101 5102 TEST(TransferTest, DoesNotCrashOnUnionThisExpr) { 5103 std::string Code = R"cc( 5104 union Union { 5105 int A; 5106 float B; 5107 }; 5108 5109 void foo() { 5110 Union A; 5111 Union B; 5112 A = B; 5113 } 5114 )cc"; 5115 // This is a crash regression test when calling the transfer function on a 5116 // `CXXThisExpr` that refers to a union. 5117 runDataflow( 5118 Code, 5119 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &, 5120 ASTContext &) {}, 5121 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator="); 5122 } 5123 5124 TEST(TransferTest, DoesNotCrashOnNullChildren) { 5125 std::string Code = (CoroutineLibrary + R"cc( 5126 task target() noexcept { 5127 co_return; 5128 } 5129 )cc") 5130 .str(); 5131 // This is a crash regression test when calling `AdornedCFG::build` on a 5132 // statement (in this case, the `CoroutineBodyStmt`) with null children. 5133 runDataflow( 5134 Code, 5135 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &, 5136 ASTContext &) {}, 5137 LangStandard::lang_cxx20, /*ApplyBuiltinTransfer=*/true); 5138 } 5139 5140 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToRefs) { 5141 std::string Code = R"( 5142 struct A { 5143 int Foo; 5144 int Bar; 5145 }; 5146 5147 void target() { 5148 int Qux; 5149 A Baz; 5150 Baz.Foo = Qux; 5151 auto &FooRef = Baz.Foo; 5152 auto &BarRef = Baz.Bar; 5153 auto &[BoundFooRef, BoundBarRef] = Baz; 5154 // [[p]] 5155 } 5156 )"; 5157 runDataflow( 5158 Code, 5159 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5160 ASTContext &ASTCtx) { 5161 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5162 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5163 5164 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 5165 ASSERT_THAT(FooRefDecl, NotNull()); 5166 5167 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 5168 ASSERT_THAT(BarRefDecl, NotNull()); 5169 5170 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 5171 ASSERT_THAT(QuxDecl, NotNull()); 5172 5173 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef"); 5174 ASSERT_THAT(BoundFooRefDecl, NotNull()); 5175 5176 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef"); 5177 ASSERT_THAT(BoundBarRefDecl, NotNull()); 5178 5179 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 5180 ASSERT_THAT(FooRefLoc, NotNull()); 5181 5182 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 5183 ASSERT_THAT(BarRefLoc, NotNull()); 5184 5185 const Value *QuxVal = Env.getValue(*QuxDecl); 5186 ASSERT_THAT(QuxVal, NotNull()); 5187 5188 const StorageLocation *BoundFooRefLoc = 5189 Env.getStorageLocation(*BoundFooRefDecl); 5190 EXPECT_EQ(BoundFooRefLoc, FooRefLoc); 5191 5192 const StorageLocation *BoundBarRefLoc = 5193 Env.getStorageLocation(*BoundBarRefDecl); 5194 EXPECT_EQ(BoundBarRefLoc, BarRefLoc); 5195 5196 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal); 5197 }); 5198 } 5199 5200 TEST(TransferTest, StructuredBindingAssignFromStructRefMembersToRefs) { 5201 std::string Code = R"( 5202 struct A { 5203 int &Foo; 5204 int &Bar; 5205 }; 5206 5207 void target(A Baz) { 5208 int Qux; 5209 Baz.Foo = Qux; 5210 auto &FooRef = Baz.Foo; 5211 auto &BarRef = Baz.Bar; 5212 auto &[BoundFooRef, BoundBarRef] = Baz; 5213 // [[p]] 5214 } 5215 )"; 5216 runDataflow( 5217 Code, 5218 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5219 ASTContext &ASTCtx) { 5220 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5221 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5222 5223 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 5224 ASSERT_THAT(FooRefDecl, NotNull()); 5225 5226 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 5227 ASSERT_THAT(BarRefDecl, NotNull()); 5228 5229 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 5230 ASSERT_THAT(QuxDecl, NotNull()); 5231 5232 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef"); 5233 ASSERT_THAT(BoundFooRefDecl, NotNull()); 5234 5235 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef"); 5236 ASSERT_THAT(BoundBarRefDecl, NotNull()); 5237 5238 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 5239 ASSERT_THAT(FooRefLoc, NotNull()); 5240 5241 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 5242 ASSERT_THAT(BarRefLoc, NotNull()); 5243 5244 const Value *QuxVal = Env.getValue(*QuxDecl); 5245 ASSERT_THAT(QuxVal, NotNull()); 5246 5247 const StorageLocation *BoundFooRefLoc = 5248 Env.getStorageLocation(*BoundFooRefDecl); 5249 EXPECT_EQ(BoundFooRefLoc, FooRefLoc); 5250 5251 const StorageLocation *BoundBarRefLoc = 5252 Env.getStorageLocation(*BoundBarRefDecl); 5253 EXPECT_EQ(BoundBarRefLoc, BarRefLoc); 5254 5255 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal); 5256 }); 5257 } 5258 5259 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToInts) { 5260 std::string Code = R"( 5261 struct A { 5262 int Foo; 5263 int Bar; 5264 }; 5265 5266 void target() { 5267 int Qux; 5268 A Baz; 5269 Baz.Foo = Qux; 5270 auto &FooRef = Baz.Foo; 5271 auto &BarRef = Baz.Bar; 5272 auto [BoundFoo, BoundBar] = Baz; 5273 // [[p]] 5274 } 5275 )"; 5276 runDataflow( 5277 Code, 5278 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5279 ASTContext &ASTCtx) { 5280 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5281 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5282 5283 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 5284 ASSERT_THAT(FooRefDecl, NotNull()); 5285 5286 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 5287 ASSERT_THAT(BarRefDecl, NotNull()); 5288 5289 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 5290 ASSERT_THAT(BoundFooDecl, NotNull()); 5291 5292 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 5293 ASSERT_THAT(BoundBarDecl, NotNull()); 5294 5295 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 5296 ASSERT_THAT(QuxDecl, NotNull()); 5297 5298 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 5299 ASSERT_THAT(FooRefLoc, NotNull()); 5300 5301 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 5302 ASSERT_THAT(BarRefLoc, NotNull()); 5303 5304 const Value *QuxVal = Env.getValue(*QuxDecl); 5305 ASSERT_THAT(QuxVal, NotNull()); 5306 5307 const StorageLocation *BoundFooLoc = 5308 Env.getStorageLocation(*BoundFooDecl); 5309 EXPECT_NE(BoundFooLoc, FooRefLoc); 5310 5311 const StorageLocation *BoundBarLoc = 5312 Env.getStorageLocation(*BoundBarDecl); 5313 EXPECT_NE(BoundBarLoc, BarRefLoc); 5314 5315 EXPECT_EQ(Env.getValue(*BoundFooDecl), QuxVal); 5316 }); 5317 } 5318 5319 TEST(TransferTest, StructuredBindingAssignFromTupleLikeType) { 5320 std::string Code = R"( 5321 namespace std { 5322 using size_t = int; 5323 template <class> struct tuple_size; 5324 template <std::size_t, class> struct tuple_element; 5325 template <class...> class tuple; 5326 5327 namespace { 5328 template <class T, T v> 5329 struct size_helper { static const T value = v; }; 5330 } // namespace 5331 5332 template <class... T> 5333 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {}; 5334 5335 template <std::size_t I, class... T> 5336 struct tuple_element<I, tuple<T...>> { 5337 using type = __type_pack_element<I, T...>; 5338 }; 5339 5340 template <class...> class tuple {}; 5341 5342 template <std::size_t I, class... T> 5343 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 5344 } // namespace std 5345 5346 std::tuple<bool, int> makeTuple(); 5347 5348 void target(bool B) { 5349 auto [BoundFoo, BoundBar] = makeTuple(); 5350 bool Baz; 5351 // Include if-then-else to test interaction of `BindingDecl` with join. 5352 if (B) { 5353 Baz = BoundFoo; 5354 (void)BoundBar; 5355 // [[p1]] 5356 } else { 5357 Baz = BoundFoo; 5358 } 5359 (void)0; 5360 // [[p2]] 5361 } 5362 )"; 5363 runDataflow( 5364 Code, 5365 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5366 ASTContext &ASTCtx) { 5367 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 5368 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 5369 5370 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 5371 ASSERT_THAT(BoundFooDecl, NotNull()); 5372 5373 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 5374 ASSERT_THAT(BoundBarDecl, NotNull()); 5375 5376 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5377 ASSERT_THAT(BazDecl, NotNull()); 5378 5379 // BindingDecls always map to references -- either lvalue or rvalue, so 5380 // we still need to skip here. 5381 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl); 5382 ASSERT_THAT(BoundFooValue, NotNull()); 5383 EXPECT_TRUE(isa<BoolValue>(BoundFooValue)); 5384 5385 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl); 5386 ASSERT_THAT(BoundBarValue, NotNull()); 5387 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue)); 5388 5389 // Test that a `DeclRefExpr` to a `BindingDecl` works as expected. 5390 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue); 5391 5392 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 5393 5394 // Test that `BoundFooDecl` retains the value we expect, after the join. 5395 BoundFooValue = Env2.getValue(*BoundFooDecl); 5396 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue); 5397 }); 5398 } 5399 5400 TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) { 5401 std::string Code = R"( 5402 namespace std { 5403 using size_t = int; 5404 template <class> struct tuple_size; 5405 template <std::size_t, class> struct tuple_element; 5406 template <class...> class tuple; 5407 5408 namespace { 5409 template <class T, T v> 5410 struct size_helper { static const T value = v; }; 5411 } // namespace 5412 5413 template <class... T> 5414 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {}; 5415 5416 template <std::size_t I, class... T> 5417 struct tuple_element<I, tuple<T...>> { 5418 using type = __type_pack_element<I, T...>; 5419 }; 5420 5421 template <class...> class tuple {}; 5422 5423 template <std::size_t I, class... T> 5424 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 5425 } // namespace std 5426 5427 std::tuple<bool, int> &getTuple(); 5428 5429 void target(bool B) { 5430 auto &[BoundFoo, BoundBar] = getTuple(); 5431 bool Baz; 5432 // Include if-then-else to test interaction of `BindingDecl` with join. 5433 if (B) { 5434 Baz = BoundFoo; 5435 (void)BoundBar; 5436 // [[p1]] 5437 } else { 5438 Baz = BoundFoo; 5439 } 5440 (void)0; 5441 // [[p2]] 5442 } 5443 )"; 5444 runDataflow( 5445 Code, 5446 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5447 ASTContext &ASTCtx) { 5448 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 5449 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 5450 5451 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 5452 ASSERT_THAT(BoundFooDecl, NotNull()); 5453 5454 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 5455 ASSERT_THAT(BoundBarDecl, NotNull()); 5456 5457 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5458 ASSERT_THAT(BazDecl, NotNull()); 5459 5460 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl); 5461 ASSERT_THAT(BoundFooValue, NotNull()); 5462 EXPECT_TRUE(isa<BoolValue>(BoundFooValue)); 5463 5464 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl); 5465 ASSERT_THAT(BoundBarValue, NotNull()); 5466 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue)); 5467 5468 // Test that a `DeclRefExpr` to a `BindingDecl` (with reference type) 5469 // works as expected. We don't test aliasing properties of the 5470 // reference, because we don't model `std::get` and so have no way to 5471 // equate separate references into the tuple. 5472 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue); 5473 5474 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 5475 5476 // Test that `BoundFooDecl` retains the value we expect, after the join. 5477 BoundFooValue = Env2.getValue(*BoundFooDecl); 5478 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue); 5479 }); 5480 } 5481 5482 TEST(TransferTest, BinaryOperatorComma) { 5483 std::string Code = R"( 5484 void target(int Foo, int Bar) { 5485 int &Baz = (Foo, Bar); 5486 // [[p]] 5487 } 5488 )"; 5489 runDataflow( 5490 Code, 5491 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5492 ASTContext &ASTCtx) { 5493 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5494 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5495 5496 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5497 ASSERT_THAT(BarDecl, NotNull()); 5498 5499 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5500 ASSERT_THAT(BazDecl, NotNull()); 5501 5502 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 5503 ASSERT_THAT(BarLoc, NotNull()); 5504 5505 const StorageLocation *BazLoc = Env.getStorageLocation(*BazDecl); 5506 EXPECT_EQ(BazLoc, BarLoc); 5507 }); 5508 } 5509 5510 TEST(TransferTest, ConditionalOperatorValue) { 5511 std::string Code = R"( 5512 void target(bool Cond, bool B1, bool B2) { 5513 bool JoinSame = Cond ? B1 : B1; 5514 bool JoinDifferent = Cond ? B1 : B2; 5515 // [[p]] 5516 } 5517 )"; 5518 runDataflow( 5519 Code, 5520 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5521 ASTContext &ASTCtx) { 5522 Environment Env = getEnvironmentAtAnnotation(Results, "p").fork(); 5523 5524 auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, "B1"); 5525 auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, "B2"); 5526 auto &JoinSame = getValueForDecl<BoolValue>(ASTCtx, Env, "JoinSame"); 5527 auto &JoinDifferent = 5528 getValueForDecl<BoolValue>(ASTCtx, Env, "JoinDifferent"); 5529 5530 EXPECT_EQ(&JoinSame, &B1); 5531 5532 const Formula &JoinDifferentEqB1 = 5533 Env.arena().makeEquals(JoinDifferent.formula(), B1.formula()); 5534 EXPECT_TRUE(Env.allows(JoinDifferentEqB1)); 5535 EXPECT_FALSE(Env.proves(JoinDifferentEqB1)); 5536 5537 const Formula &JoinDifferentEqB2 = 5538 Env.arena().makeEquals(JoinDifferent.formula(), B2.formula()); 5539 EXPECT_TRUE(Env.allows(JoinDifferentEqB2)); 5540 EXPECT_FALSE(Env.proves(JoinDifferentEqB1)); 5541 }); 5542 } 5543 5544 TEST(TransferTest, ConditionalOperatorLocation) { 5545 std::string Code = R"( 5546 void target(bool Cond, int I1, int I2) { 5547 int &JoinSame = Cond ? I1 : I1; 5548 int &JoinDifferent = Cond ? I1 : I2; 5549 // [[p]] 5550 } 5551 )"; 5552 runDataflow( 5553 Code, 5554 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5555 ASTContext &ASTCtx) { 5556 Environment Env = getEnvironmentAtAnnotation(Results, "p").fork(); 5557 5558 StorageLocation &I1 = getLocForDecl(ASTCtx, Env, "I1"); 5559 StorageLocation &I2 = getLocForDecl(ASTCtx, Env, "I2"); 5560 StorageLocation &JoinSame = getLocForDecl(ASTCtx, Env, "JoinSame"); 5561 StorageLocation &JoinDifferent = 5562 getLocForDecl(ASTCtx, Env, "JoinDifferent"); 5563 5564 EXPECT_EQ(&JoinSame, &I1); 5565 5566 EXPECT_NE(&JoinDifferent, &I1); 5567 EXPECT_NE(&JoinDifferent, &I2); 5568 }); 5569 } 5570 5571 TEST(TransferTest, ConditionalOperatorOnConstantExpr) { 5572 // This is a regression test: We used to crash when a `ConstantExpr` was used 5573 // in the branches of a conditional operator. 5574 std::string Code = R"cc( 5575 consteval bool identity(bool B) { return B; } 5576 void target(bool Cond) { 5577 bool JoinTrueTrue = Cond ? identity(true) : identity(true); 5578 bool JoinTrueFalse = Cond ? identity(true) : identity(false); 5579 // [[p]] 5580 } 5581 )cc"; 5582 runDataflow( 5583 Code, 5584 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5585 ASTContext &ASTCtx) { 5586 Environment Env = getEnvironmentAtAnnotation(Results, "p").fork(); 5587 5588 auto &JoinTrueTrue = 5589 getValueForDecl<BoolValue>(ASTCtx, Env, "JoinTrueTrue"); 5590 // FIXME: This test documents the current behavior, namely that we 5591 // don't actually use the constant result of the `ConstantExpr` and 5592 // instead treat it like a normal function call. 5593 EXPECT_EQ(JoinTrueTrue.formula().kind(), Formula::Kind::AtomRef); 5594 // EXPECT_TRUE(JoinTrueTrue.formula().literal()); 5595 5596 auto &JoinTrueFalse = 5597 getValueForDecl<BoolValue>(ASTCtx, Env, "JoinTrueFalse"); 5598 EXPECT_EQ(JoinTrueFalse.formula().kind(), Formula::Kind::AtomRef); 5599 }, 5600 LangStandard::lang_cxx20); 5601 } 5602 5603 TEST(TransferTest, IfStmtBranchExtendsFlowCondition) { 5604 std::string Code = R"( 5605 void target(bool Foo) { 5606 if (Foo) { 5607 (void)0; 5608 // [[if_then]] 5609 } else { 5610 (void)0; 5611 // [[if_else]] 5612 } 5613 } 5614 )"; 5615 runDataflow( 5616 Code, 5617 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5618 ASTContext &ASTCtx) { 5619 ASSERT_THAT(Results.keys(), UnorderedElementsAre("if_then", "if_else")); 5620 const Environment &ThenEnv = 5621 getEnvironmentAtAnnotation(Results, "if_then"); 5622 const Environment &ElseEnv = 5623 getEnvironmentAtAnnotation(Results, "if_else"); 5624 5625 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5626 ASSERT_THAT(FooDecl, NotNull()); 5627 5628 auto &ThenFooVal= getFormula(*FooDecl, ThenEnv); 5629 EXPECT_TRUE(ThenEnv.proves(ThenFooVal)); 5630 5631 auto &ElseFooVal = getFormula(*FooDecl, ElseEnv); 5632 EXPECT_TRUE(ElseEnv.proves(ElseEnv.arena().makeNot(ElseFooVal))); 5633 }); 5634 } 5635 5636 TEST(TransferTest, WhileStmtBranchExtendsFlowCondition) { 5637 std::string Code = R"( 5638 void target(bool Foo) { 5639 while (Foo) { 5640 (void)0; 5641 // [[loop_body]] 5642 } 5643 (void)0; 5644 // [[after_loop]] 5645 } 5646 )"; 5647 runDataflow( 5648 Code, 5649 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5650 ASTContext &ASTCtx) { 5651 ASSERT_THAT(Results.keys(), 5652 UnorderedElementsAre("loop_body", "after_loop")); 5653 const Environment &LoopBodyEnv = 5654 getEnvironmentAtAnnotation(Results, "loop_body"); 5655 const Environment &AfterLoopEnv = 5656 getEnvironmentAtAnnotation(Results, "after_loop"); 5657 5658 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5659 ASSERT_THAT(FooDecl, NotNull()); 5660 5661 auto &LoopBodyFooVal = getFormula(*FooDecl, LoopBodyEnv); 5662 EXPECT_TRUE(LoopBodyEnv.proves(LoopBodyFooVal)); 5663 5664 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 5665 EXPECT_TRUE( 5666 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal))); 5667 }); 5668 } 5669 5670 TEST(TransferTest, DoWhileStmtBranchExtendsFlowCondition) { 5671 std::string Code = R"( 5672 void target(bool Foo) { 5673 bool Bar = true; 5674 do { 5675 (void)0; 5676 // [[loop_body]] 5677 Bar = false; 5678 } while (Foo); 5679 (void)0; 5680 // [[after_loop]] 5681 } 5682 )"; 5683 runDataflow( 5684 Code, 5685 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5686 ASTContext &ASTCtx) { 5687 ASSERT_THAT(Results.keys(), 5688 UnorderedElementsAre("loop_body", "after_loop")); 5689 const Environment &LoopBodyEnv = 5690 getEnvironmentAtAnnotation(Results, "loop_body"); 5691 const Environment &AfterLoopEnv = 5692 getEnvironmentAtAnnotation(Results, "after_loop"); 5693 auto &A = AfterLoopEnv.arena(); 5694 5695 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5696 ASSERT_THAT(FooDecl, NotNull()); 5697 5698 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5699 ASSERT_THAT(BarDecl, NotNull()); 5700 5701 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 5702 auto &LoopBodyBarVal = getFormula(*BarDecl, LoopBodyEnv); 5703 EXPECT_TRUE( 5704 LoopBodyEnv.proves(A.makeOr(LoopBodyBarVal, LoopBodyFooVal))); 5705 5706 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 5707 auto &AfterLoopBarVal = getFormula(*BarDecl, AfterLoopEnv); 5708 EXPECT_TRUE(AfterLoopEnv.proves(A.makeNot(AfterLoopFooVal))); 5709 EXPECT_TRUE(AfterLoopEnv.proves(A.makeNot(AfterLoopBarVal))); 5710 }); 5711 } 5712 5713 TEST(TransferTest, ForStmtBranchExtendsFlowCondition) { 5714 std::string Code = R"( 5715 void target(bool Foo) { 5716 for (; Foo;) { 5717 (void)0; 5718 // [[loop_body]] 5719 } 5720 (void)0; 5721 // [[after_loop]] 5722 } 5723 )"; 5724 runDataflow( 5725 Code, 5726 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5727 ASTContext &ASTCtx) { 5728 ASSERT_THAT(Results.keys(), 5729 UnorderedElementsAre("loop_body", "after_loop")); 5730 const Environment &LoopBodyEnv = 5731 getEnvironmentAtAnnotation(Results, "loop_body"); 5732 const Environment &AfterLoopEnv = 5733 getEnvironmentAtAnnotation(Results, "after_loop"); 5734 5735 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5736 ASSERT_THAT(FooDecl, NotNull()); 5737 5738 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 5739 EXPECT_TRUE(LoopBodyEnv.proves(LoopBodyFooVal)); 5740 5741 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 5742 EXPECT_TRUE( 5743 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal))); 5744 }); 5745 } 5746 5747 TEST(TransferTest, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition) { 5748 std::string Code = R"( 5749 void target(bool Foo) { 5750 for (;;) { 5751 (void)0; 5752 // [[loop_body]] 5753 } 5754 } 5755 )"; 5756 runDataflow( 5757 Code, 5758 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5759 ASTContext &ASTCtx) { 5760 ASSERT_THAT(Results.keys(), UnorderedElementsAre("loop_body")); 5761 const Environment &LoopBodyEnv = 5762 getEnvironmentAtAnnotation(Results, "loop_body"); 5763 5764 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5765 ASSERT_THAT(FooDecl, NotNull()); 5766 5767 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 5768 EXPECT_FALSE(LoopBodyEnv.proves(LoopBodyFooVal)); 5769 }); 5770 } 5771 5772 TEST(TransferTest, ContextSensitiveOptionDisabled) { 5773 std::string Code = R"( 5774 bool GiveBool(); 5775 void SetBool(bool &Var) { Var = true; } 5776 5777 void target() { 5778 bool Foo = GiveBool(); 5779 SetBool(Foo); 5780 // [[p]] 5781 } 5782 )"; 5783 runDataflow( 5784 Code, 5785 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5786 ASTContext &ASTCtx) { 5787 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5788 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5789 5790 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5791 ASSERT_THAT(FooDecl, NotNull()); 5792 5793 auto &FooVal = getFormula(*FooDecl, Env); 5794 EXPECT_FALSE(Env.proves(FooVal)); 5795 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5796 }, 5797 {BuiltinOptions{/*.ContextSensitiveOpts=*/std::nullopt}}); 5798 } 5799 5800 TEST(TransferTest, ContextSensitiveReturnReference) { 5801 std::string Code = R"( 5802 class S {}; 5803 S& target(bool b, S &s) { 5804 return s; 5805 // [[p]] 5806 } 5807 )"; 5808 runDataflow( 5809 Code, 5810 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5811 ASTContext &ASTCtx) { 5812 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5813 5814 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 5815 ASSERT_THAT(SDecl, NotNull()); 5816 5817 auto *SLoc = Env.getStorageLocation(*SDecl); 5818 ASSERT_THAT(SLoc, NotNull()); 5819 5820 ASSERT_THAT(Env.getReturnStorageLocation(), Eq(SLoc)); 5821 }, 5822 {BuiltinOptions{ContextSensitiveOptions{}}}); 5823 } 5824 5825 // This test is a regression test, based on a real crash. 5826 TEST(TransferTest, ContextSensitiveReturnReferenceWithConditionalOperator) { 5827 std::string Code = R"( 5828 class S {}; 5829 S& target(bool b, S &s) { 5830 return b ? s : s; 5831 // [[p]] 5832 } 5833 )"; 5834 runDataflow( 5835 Code, 5836 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5837 ASTContext &ASTCtx) { 5838 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5839 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5840 5841 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 5842 ASSERT_THAT(SDecl, NotNull()); 5843 5844 auto *SLoc = Env.getStorageLocation(*SDecl); 5845 EXPECT_THAT(SLoc, NotNull()); 5846 5847 auto *Loc = Env.getReturnStorageLocation(); 5848 EXPECT_THAT(Loc, NotNull()); 5849 5850 EXPECT_EQ(Loc, SLoc); 5851 }, 5852 {BuiltinOptions{ContextSensitiveOptions{}}}); 5853 } 5854 5855 TEST(TransferTest, ContextSensitiveReturnOneOfTwoReferences) { 5856 std::string Code = R"( 5857 class S {}; 5858 S &callee(bool b, S &s1_parm, S &s2_parm) { 5859 if (b) 5860 return s1_parm; 5861 else 5862 return s2_parm; 5863 } 5864 void target(bool b) { 5865 S s1; 5866 S s2; 5867 S &return_s1 = s1; 5868 S &return_s2 = s2; 5869 S &return_dont_know = callee(b, s1, s2); 5870 // [[p]] 5871 } 5872 )"; 5873 runDataflow( 5874 Code, 5875 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5876 ASTContext &ASTCtx) { 5877 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5878 5879 const ValueDecl *S1 = findValueDecl(ASTCtx, "s1"); 5880 ASSERT_THAT(S1, NotNull()); 5881 const ValueDecl *S2 = findValueDecl(ASTCtx, "s2"); 5882 ASSERT_THAT(S2, NotNull()); 5883 const ValueDecl *ReturnS1 = findValueDecl(ASTCtx, "return_s1"); 5884 ASSERT_THAT(ReturnS1, NotNull()); 5885 const ValueDecl *ReturnS2 = findValueDecl(ASTCtx, "return_s2"); 5886 ASSERT_THAT(ReturnS2, NotNull()); 5887 const ValueDecl *ReturnDontKnow = 5888 findValueDecl(ASTCtx, "return_dont_know"); 5889 ASSERT_THAT(ReturnDontKnow, NotNull()); 5890 5891 StorageLocation *S1Loc = Env.getStorageLocation(*S1); 5892 StorageLocation *S2Loc = Env.getStorageLocation(*S2); 5893 5894 EXPECT_THAT(Env.getStorageLocation(*ReturnS1), Eq(S1Loc)); 5895 EXPECT_THAT(Env.getStorageLocation(*ReturnS2), Eq(S2Loc)); 5896 5897 // In the case where we don't have a consistent storage location for 5898 // the return value, the framework creates a new storage location, which 5899 // should be different from the storage locations of `s1` and `s2`. 5900 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S1Loc)); 5901 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S2Loc)); 5902 }, 5903 {BuiltinOptions{ContextSensitiveOptions{}}}); 5904 } 5905 5906 TEST(TransferTest, ContextSensitiveDepthZero) { 5907 std::string Code = R"( 5908 bool GiveBool(); 5909 void SetBool(bool &Var) { Var = true; } 5910 5911 void target() { 5912 bool Foo = GiveBool(); 5913 SetBool(Foo); 5914 // [[p]] 5915 } 5916 )"; 5917 runDataflow( 5918 Code, 5919 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5920 ASTContext &ASTCtx) { 5921 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5922 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5923 5924 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5925 ASSERT_THAT(FooDecl, NotNull()); 5926 5927 auto &FooVal = getFormula(*FooDecl, Env); 5928 EXPECT_FALSE(Env.proves(FooVal)); 5929 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5930 }, 5931 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/0}}}); 5932 } 5933 5934 TEST(TransferTest, ContextSensitiveSetTrue) { 5935 std::string Code = R"( 5936 bool GiveBool(); 5937 void SetBool(bool &Var) { Var = true; } 5938 5939 void target() { 5940 bool Foo = GiveBool(); 5941 SetBool(Foo); 5942 // [[p]] 5943 } 5944 )"; 5945 runDataflow( 5946 Code, 5947 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5948 ASTContext &ASTCtx) { 5949 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5950 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5951 5952 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5953 ASSERT_THAT(FooDecl, NotNull()); 5954 5955 auto &FooVal = getFormula(*FooDecl, Env); 5956 EXPECT_TRUE(Env.proves(FooVal)); 5957 }, 5958 {BuiltinOptions{ContextSensitiveOptions{}}}); 5959 } 5960 5961 TEST(TransferTest, ContextSensitiveSetFalse) { 5962 std::string Code = R"( 5963 bool GiveBool(); 5964 void SetBool(bool &Var) { Var = false; } 5965 5966 void target() { 5967 bool Foo = GiveBool(); 5968 SetBool(Foo); 5969 // [[p]] 5970 } 5971 )"; 5972 runDataflow( 5973 Code, 5974 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5975 ASTContext &ASTCtx) { 5976 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5977 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5978 5979 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5980 ASSERT_THAT(FooDecl, NotNull()); 5981 5982 auto &FooVal = getFormula(*FooDecl, Env); 5983 EXPECT_TRUE(Env.proves(Env.arena().makeNot(FooVal))); 5984 }, 5985 {BuiltinOptions{ContextSensitiveOptions{}}}); 5986 } 5987 5988 TEST(TransferTest, ContextSensitiveSetBothTrueAndFalse) { 5989 std::string Code = R"( 5990 bool GiveBool(); 5991 void SetBool(bool &Var, bool Val) { Var = Val; } 5992 5993 void target() { 5994 bool Foo = GiveBool(); 5995 bool Bar = GiveBool(); 5996 SetBool(Foo, true); 5997 SetBool(Bar, false); 5998 // [[p]] 5999 } 6000 )"; 6001 runDataflow( 6002 Code, 6003 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6004 ASTContext &ASTCtx) { 6005 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6006 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6007 auto &A = Env.arena(); 6008 6009 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6010 ASSERT_THAT(FooDecl, NotNull()); 6011 6012 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6013 ASSERT_THAT(BarDecl, NotNull()); 6014 6015 auto &FooVal = getFormula(*FooDecl, Env); 6016 EXPECT_TRUE(Env.proves(FooVal)); 6017 EXPECT_FALSE(Env.proves(A.makeNot(FooVal))); 6018 6019 auto &BarVal = getFormula(*BarDecl, Env); 6020 EXPECT_FALSE(Env.proves(BarVal)); 6021 EXPECT_TRUE(Env.proves(A.makeNot(BarVal))); 6022 }, 6023 {BuiltinOptions{ContextSensitiveOptions{}}}); 6024 } 6025 6026 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthOne) { 6027 std::string Code = R"( 6028 bool GiveBool(); 6029 void SetBool1(bool &Var) { Var = true; } 6030 void SetBool2(bool &Var) { SetBool1(Var); } 6031 6032 void target() { 6033 bool Foo = GiveBool(); 6034 SetBool2(Foo); 6035 // [[p]] 6036 } 6037 )"; 6038 runDataflow( 6039 Code, 6040 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6041 ASTContext &ASTCtx) { 6042 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6043 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6044 6045 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6046 ASSERT_THAT(FooDecl, NotNull()); 6047 6048 auto &FooVal = getFormula(*FooDecl, Env); 6049 EXPECT_FALSE(Env.proves(FooVal)); 6050 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 6051 }, 6052 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/1}}}); 6053 } 6054 6055 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthTwo) { 6056 std::string Code = R"( 6057 bool GiveBool(); 6058 void SetBool1(bool &Var) { Var = true; } 6059 void SetBool2(bool &Var) { SetBool1(Var); } 6060 6061 void target() { 6062 bool Foo = GiveBool(); 6063 SetBool2(Foo); 6064 // [[p]] 6065 } 6066 )"; 6067 runDataflow( 6068 Code, 6069 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6070 ASTContext &ASTCtx) { 6071 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6072 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6073 6074 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6075 ASSERT_THAT(FooDecl, NotNull()); 6076 6077 auto &FooVal = getFormula(*FooDecl, Env); 6078 EXPECT_TRUE(Env.proves(FooVal)); 6079 }, 6080 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}}); 6081 } 6082 6083 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthTwo) { 6084 std::string Code = R"( 6085 bool GiveBool(); 6086 void SetBool1(bool &Var) { Var = true; } 6087 void SetBool2(bool &Var) { SetBool1(Var); } 6088 void SetBool3(bool &Var) { SetBool2(Var); } 6089 6090 void target() { 6091 bool Foo = GiveBool(); 6092 SetBool3(Foo); 6093 // [[p]] 6094 } 6095 )"; 6096 runDataflow( 6097 Code, 6098 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6099 ASTContext &ASTCtx) { 6100 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6101 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6102 6103 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6104 ASSERT_THAT(FooDecl, NotNull()); 6105 6106 auto &FooVal = getFormula(*FooDecl, Env); 6107 EXPECT_FALSE(Env.proves(FooVal)); 6108 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 6109 }, 6110 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}}); 6111 } 6112 6113 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthThree) { 6114 std::string Code = R"( 6115 bool GiveBool(); 6116 void SetBool1(bool &Var) { Var = true; } 6117 void SetBool2(bool &Var) { SetBool1(Var); } 6118 void SetBool3(bool &Var) { SetBool2(Var); } 6119 6120 void target() { 6121 bool Foo = GiveBool(); 6122 SetBool3(Foo); 6123 // [[p]] 6124 } 6125 )"; 6126 runDataflow( 6127 Code, 6128 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6129 ASTContext &ASTCtx) { 6130 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6131 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6132 6133 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6134 ASSERT_THAT(FooDecl, NotNull()); 6135 6136 auto &FooVal = getFormula(*FooDecl, Env); 6137 EXPECT_TRUE(Env.proves(FooVal)); 6138 }, 6139 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/3}}}); 6140 } 6141 6142 TEST(TransferTest, ContextSensitiveMutualRecursion) { 6143 std::string Code = R"( 6144 bool Pong(bool X, bool Y); 6145 6146 bool Ping(bool X, bool Y) { 6147 if (X) { 6148 return Y; 6149 } else { 6150 return Pong(!X, Y); 6151 } 6152 } 6153 6154 bool Pong(bool X, bool Y) { 6155 if (Y) { 6156 return X; 6157 } else { 6158 return Ping(X, !Y); 6159 } 6160 } 6161 6162 void target() { 6163 bool Foo = Ping(false, false); 6164 // [[p]] 6165 } 6166 )"; 6167 runDataflow( 6168 Code, 6169 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6170 ASTContext &ASTCtx) { 6171 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6172 // The analysis doesn't crash... 6173 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6174 6175 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6176 ASSERT_THAT(FooDecl, NotNull()); 6177 6178 auto &FooVal = getFormula(*FooDecl, Env); 6179 // ... but it also can't prove anything here. 6180 EXPECT_FALSE(Env.proves(FooVal)); 6181 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 6182 }, 6183 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/4}}}); 6184 } 6185 6186 TEST(TransferTest, ContextSensitiveSetMultipleLines) { 6187 std::string Code = R"( 6188 void SetBools(bool &Var1, bool &Var2) { 6189 Var1 = true; 6190 Var2 = false; 6191 } 6192 6193 void target() { 6194 bool Foo = false; 6195 bool Bar = true; 6196 SetBools(Foo, Bar); 6197 // [[p]] 6198 } 6199 )"; 6200 runDataflow( 6201 Code, 6202 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6203 ASTContext &ASTCtx) { 6204 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6205 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6206 6207 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6208 ASSERT_THAT(FooDecl, NotNull()); 6209 6210 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6211 ASSERT_THAT(BarDecl, NotNull()); 6212 6213 auto &FooVal = getFormula(*FooDecl, Env); 6214 EXPECT_TRUE(Env.proves(FooVal)); 6215 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 6216 6217 auto &BarVal = getFormula(*BarDecl, Env); 6218 EXPECT_FALSE(Env.proves(BarVal)); 6219 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 6220 }, 6221 {BuiltinOptions{ContextSensitiveOptions{}}}); 6222 } 6223 6224 TEST(TransferTest, ContextSensitiveSetMultipleBlocks) { 6225 std::string Code = R"( 6226 void IfCond(bool Cond, bool &Then, bool &Else) { 6227 if (Cond) { 6228 Then = true; 6229 } else { 6230 Else = true; 6231 } 6232 } 6233 6234 void target() { 6235 bool Foo = false; 6236 bool Bar = false; 6237 bool Baz = false; 6238 IfCond(Foo, Bar, Baz); 6239 // [[p]] 6240 } 6241 )"; 6242 runDataflow( 6243 Code, 6244 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6245 ASTContext &ASTCtx) { 6246 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6247 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6248 6249 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6250 ASSERT_THAT(BarDecl, NotNull()); 6251 6252 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 6253 ASSERT_THAT(BazDecl, NotNull()); 6254 6255 auto &BarVal = getFormula(*BarDecl, Env); 6256 EXPECT_FALSE(Env.proves(BarVal)); 6257 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 6258 6259 auto &BazVal = getFormula(*BazDecl, Env); 6260 EXPECT_TRUE(Env.proves(BazVal)); 6261 EXPECT_FALSE(Env.proves(Env.arena().makeNot(BazVal))); 6262 }, 6263 {BuiltinOptions{ContextSensitiveOptions{}}}); 6264 } 6265 6266 TEST(TransferTest, ContextSensitiveReturnVoid) { 6267 std::string Code = R"( 6268 void Noop() { return; } 6269 6270 void target() { 6271 Noop(); 6272 // [[p]] 6273 } 6274 )"; 6275 runDataflow( 6276 Code, 6277 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6278 ASTContext &ASTCtx) { 6279 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6280 // This just tests that the analysis doesn't crash. 6281 }, 6282 {BuiltinOptions{ContextSensitiveOptions{}}}); 6283 } 6284 6285 TEST(TransferTest, ContextSensitiveReturnTrue) { 6286 std::string Code = R"( 6287 bool GiveBool() { return true; } 6288 6289 void target() { 6290 bool Foo = GiveBool(); 6291 // [[p]] 6292 } 6293 )"; 6294 runDataflow( 6295 Code, 6296 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6297 ASTContext &ASTCtx) { 6298 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6299 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6300 6301 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6302 ASSERT_THAT(FooDecl, NotNull()); 6303 6304 auto &FooVal = getFormula(*FooDecl, Env); 6305 EXPECT_TRUE(Env.proves(FooVal)); 6306 }, 6307 {BuiltinOptions{ContextSensitiveOptions{}}}); 6308 } 6309 6310 TEST(TransferTest, ContextSensitiveReturnFalse) { 6311 std::string Code = R"( 6312 bool GiveBool() { return false; } 6313 6314 void target() { 6315 bool Foo = GiveBool(); 6316 // [[p]] 6317 } 6318 )"; 6319 runDataflow( 6320 Code, 6321 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6322 ASTContext &ASTCtx) { 6323 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6324 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6325 6326 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6327 ASSERT_THAT(FooDecl, NotNull()); 6328 6329 auto &FooVal = getFormula(*FooDecl, Env); 6330 EXPECT_TRUE(Env.proves(Env.arena().makeNot(FooVal))); 6331 }, 6332 {BuiltinOptions{ContextSensitiveOptions{}}}); 6333 } 6334 6335 TEST(TransferTest, ContextSensitiveReturnArg) { 6336 std::string Code = R"( 6337 bool GiveBool(); 6338 bool GiveBack(bool Arg) { return Arg; } 6339 6340 void target() { 6341 bool Foo = GiveBool(); 6342 bool Bar = GiveBack(Foo); 6343 bool Baz = Foo == Bar; 6344 // [[p]] 6345 } 6346 )"; 6347 runDataflow( 6348 Code, 6349 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6350 ASTContext &ASTCtx) { 6351 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6352 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6353 6354 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 6355 ASSERT_THAT(BazDecl, NotNull()); 6356 6357 auto &BazVal = getFormula(*BazDecl, Env); 6358 EXPECT_TRUE(Env.proves(BazVal)); 6359 }, 6360 {BuiltinOptions{ContextSensitiveOptions{}}}); 6361 } 6362 6363 TEST(TransferTest, ContextSensitiveReturnInt) { 6364 std::string Code = R"( 6365 int identity(int x) { return x; } 6366 6367 void target() { 6368 int y = identity(42); 6369 // [[p]] 6370 } 6371 )"; 6372 runDataflow( 6373 Code, 6374 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6375 ASTContext &ASTCtx) { 6376 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6377 // This just tests that the analysis doesn't crash. 6378 }, 6379 {BuiltinOptions{ContextSensitiveOptions{}}}); 6380 } 6381 6382 TEST(TransferTest, ContextSensitiveReturnRecord) { 6383 std::string Code = R"( 6384 struct S { 6385 bool B; 6386 }; 6387 6388 S makeS(bool BVal) { return {BVal}; } 6389 6390 void target() { 6391 S FalseS = makeS(false); 6392 S TrueS = makeS(true); 6393 // [[p]] 6394 } 6395 )"; 6396 runDataflow( 6397 Code, 6398 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6399 ASTContext &ASTCtx) { 6400 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6401 6402 auto &FalseSLoc = 6403 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "FalseS"); 6404 auto &TrueSLoc = 6405 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "TrueS"); 6406 6407 EXPECT_EQ(getFieldValue(&FalseSLoc, "B", ASTCtx, Env), 6408 &Env.getBoolLiteralValue(false)); 6409 EXPECT_EQ(getFieldValue(&TrueSLoc, "B", ASTCtx, Env), 6410 &Env.getBoolLiteralValue(true)); 6411 }, 6412 {BuiltinOptions{ContextSensitiveOptions{}}}); 6413 } 6414 6415 TEST(TransferTest, ContextSensitiveReturnSelfReferentialRecord) { 6416 std::string Code = R"( 6417 struct S { 6418 S() { self = this; } 6419 S *self; 6420 }; 6421 6422 S makeS() { 6423 // RVO guarantees that this will be constructed directly into `MyS`. 6424 return S(); 6425 } 6426 6427 void target() { 6428 S MyS = makeS(); 6429 // [[p]] 6430 } 6431 )"; 6432 runDataflow( 6433 Code, 6434 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6435 ASTContext &ASTCtx) { 6436 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6437 6438 auto &MySLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "MyS"); 6439 6440 auto *SelfVal = 6441 cast<PointerValue>(getFieldValue(&MySLoc, "self", ASTCtx, Env)); 6442 EXPECT_EQ(&SelfVal->getPointeeLoc(), &MySLoc); 6443 }, 6444 {BuiltinOptions{ContextSensitiveOptions{}}}); 6445 } 6446 6447 TEST(TransferTest, ContextSensitiveMethodLiteral) { 6448 std::string Code = R"( 6449 class MyClass { 6450 public: 6451 bool giveBool() { return true; } 6452 }; 6453 6454 void target() { 6455 MyClass MyObj; 6456 bool Foo = MyObj.giveBool(); 6457 // [[p]] 6458 } 6459 )"; 6460 runDataflow( 6461 Code, 6462 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6463 ASTContext &ASTCtx) { 6464 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6465 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6466 6467 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6468 ASSERT_THAT(FooDecl, NotNull()); 6469 6470 auto &FooVal = getFormula(*FooDecl, Env); 6471 EXPECT_TRUE(Env.proves(FooVal)); 6472 }, 6473 {BuiltinOptions{ContextSensitiveOptions{}}}); 6474 } 6475 6476 TEST(TransferTest, ContextSensitiveMethodGetter) { 6477 std::string Code = R"( 6478 class MyClass { 6479 public: 6480 bool getField() { return Field; } 6481 6482 bool Field; 6483 }; 6484 6485 void target() { 6486 MyClass MyObj; 6487 MyObj.Field = true; 6488 bool Foo = MyObj.getField(); 6489 // [[p]] 6490 } 6491 )"; 6492 runDataflow( 6493 Code, 6494 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6495 ASTContext &ASTCtx) { 6496 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6497 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6498 6499 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6500 ASSERT_THAT(FooDecl, NotNull()); 6501 6502 auto &FooVal = getFormula(*FooDecl, Env); 6503 EXPECT_TRUE(Env.proves(FooVal)); 6504 }, 6505 {BuiltinOptions{ContextSensitiveOptions{}}}); 6506 } 6507 6508 TEST(TransferTest, ContextSensitiveMethodSetter) { 6509 std::string Code = R"( 6510 class MyClass { 6511 public: 6512 void setField(bool Val) { Field = Val; } 6513 6514 bool Field; 6515 }; 6516 6517 void target() { 6518 MyClass MyObj; 6519 MyObj.setField(true); 6520 bool Foo = MyObj.Field; 6521 // [[p]] 6522 } 6523 )"; 6524 runDataflow( 6525 Code, 6526 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6527 ASTContext &ASTCtx) { 6528 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6529 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6530 6531 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6532 ASSERT_THAT(FooDecl, NotNull()); 6533 6534 auto &FooVal = getFormula(*FooDecl, Env); 6535 EXPECT_TRUE(Env.proves(FooVal)); 6536 }, 6537 {BuiltinOptions{ContextSensitiveOptions{}}}); 6538 } 6539 6540 TEST(TransferTest, ContextSensitiveMethodGetterAndSetter) { 6541 std::string Code = R"( 6542 class MyClass { 6543 public: 6544 bool getField() { return Field; } 6545 void setField(bool Val) { Field = Val; } 6546 6547 private: 6548 bool Field; 6549 }; 6550 6551 void target() { 6552 MyClass MyObj; 6553 MyObj.setField(true); 6554 bool Foo = MyObj.getField(); 6555 // [[p]] 6556 } 6557 )"; 6558 runDataflow( 6559 Code, 6560 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6561 ASTContext &ASTCtx) { 6562 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6563 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6564 6565 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6566 ASSERT_THAT(FooDecl, NotNull()); 6567 6568 auto &FooVal = getFormula(*FooDecl, Env); 6569 EXPECT_TRUE(Env.proves(FooVal)); 6570 }, 6571 {BuiltinOptions{ContextSensitiveOptions{}}}); 6572 } 6573 6574 6575 TEST(TransferTest, ContextSensitiveMethodTwoLayersVoid) { 6576 std::string Code = R"( 6577 class MyClass { 6578 public: 6579 void Inner() { MyField = true; } 6580 void Outer() { Inner(); } 6581 6582 bool MyField; 6583 }; 6584 6585 void target() { 6586 MyClass MyObj; 6587 MyObj.Outer(); 6588 bool Foo = MyObj.MyField; 6589 // [[p]] 6590 } 6591 )"; 6592 runDataflow( 6593 Code, 6594 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6595 ASTContext &ASTCtx) { 6596 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6597 ; 6598 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6599 6600 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6601 ASSERT_THAT(FooDecl, NotNull()); 6602 6603 auto &FooVal = getFormula(*FooDecl, Env); 6604 EXPECT_TRUE(Env.proves(FooVal)); 6605 }, 6606 {BuiltinOptions{ContextSensitiveOptions{}}}); 6607 } 6608 6609 TEST(TransferTest, ContextSensitiveMethodTwoLayersReturn) { 6610 std::string Code = R"( 6611 class MyClass { 6612 public: 6613 bool Inner() { return MyField; } 6614 bool Outer() { return Inner(); } 6615 6616 bool MyField; 6617 }; 6618 6619 void target() { 6620 MyClass MyObj; 6621 MyObj.MyField = true; 6622 bool Foo = MyObj.Outer(); 6623 // [[p]] 6624 } 6625 )"; 6626 runDataflow( 6627 Code, 6628 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6629 ASTContext &ASTCtx) { 6630 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6631 ; 6632 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6633 6634 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6635 ASSERT_THAT(FooDecl, NotNull()); 6636 6637 auto &FooVal = getFormula(*FooDecl, Env); 6638 EXPECT_TRUE(Env.proves(FooVal)); 6639 }, 6640 {BuiltinOptions{ContextSensitiveOptions{}}}); 6641 } 6642 6643 TEST(TransferTest, ContextSensitiveConstructorBody) { 6644 std::string Code = R"( 6645 class MyClass { 6646 public: 6647 MyClass() { MyField = true; } 6648 6649 bool MyField; 6650 }; 6651 6652 void target() { 6653 MyClass MyObj; 6654 bool Foo = MyObj.MyField; 6655 // [[p]] 6656 } 6657 )"; 6658 runDataflow( 6659 Code, 6660 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6661 ASTContext &ASTCtx) { 6662 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6663 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6664 6665 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6666 ASSERT_THAT(FooDecl, NotNull()); 6667 6668 auto &FooVal = getFormula(*FooDecl, Env); 6669 EXPECT_TRUE(Env.proves(FooVal)); 6670 }, 6671 {BuiltinOptions{ContextSensitiveOptions{}}}); 6672 } 6673 6674 TEST(TransferTest, ContextSensitiveConstructorInitializer) { 6675 std::string Code = R"( 6676 class MyClass { 6677 public: 6678 MyClass() : MyField(true) {} 6679 6680 bool MyField; 6681 }; 6682 6683 void target() { 6684 MyClass MyObj; 6685 bool Foo = MyObj.MyField; 6686 // [[p]] 6687 } 6688 )"; 6689 runDataflow( 6690 Code, 6691 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6692 ASTContext &ASTCtx) { 6693 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6694 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6695 6696 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6697 ASSERT_THAT(FooDecl, NotNull()); 6698 6699 auto &FooVal = getFormula(*FooDecl, Env); 6700 EXPECT_TRUE(Env.proves(FooVal)); 6701 }, 6702 {BuiltinOptions{ContextSensitiveOptions{}}}); 6703 } 6704 6705 TEST(TransferTest, ContextSensitiveConstructorDefault) { 6706 std::string Code = R"( 6707 class MyClass { 6708 public: 6709 MyClass() = default; 6710 6711 bool MyField = true; 6712 }; 6713 6714 void target() { 6715 MyClass MyObj; 6716 bool Foo = MyObj.MyField; 6717 // [[p]] 6718 } 6719 )"; 6720 runDataflow( 6721 Code, 6722 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6723 ASTContext &ASTCtx) { 6724 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6725 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6726 6727 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6728 ASSERT_THAT(FooDecl, NotNull()); 6729 6730 auto &FooVal = getFormula(*FooDecl, Env); 6731 EXPECT_TRUE(Env.proves(FooVal)); 6732 }, 6733 {BuiltinOptions{ContextSensitiveOptions{}}}); 6734 } 6735 6736 TEST(TransferTest, ContextSensitiveSelfReferentialClass) { 6737 // Test that the `this` pointer seen in the constructor has the same value 6738 // as the address of the variable the object is constructed into. 6739 std::string Code = R"( 6740 class MyClass { 6741 public: 6742 MyClass() : Self(this) {} 6743 MyClass *Self; 6744 }; 6745 6746 void target() { 6747 MyClass MyObj; 6748 MyClass *SelfPtr = MyObj.Self; 6749 // [[p]] 6750 } 6751 )"; 6752 runDataflow( 6753 Code, 6754 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6755 ASTContext &ASTCtx) { 6756 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6757 6758 const ValueDecl *MyObjDecl = findValueDecl(ASTCtx, "MyObj"); 6759 ASSERT_THAT(MyObjDecl, NotNull()); 6760 6761 const ValueDecl *SelfDecl = findValueDecl(ASTCtx, "SelfPtr"); 6762 ASSERT_THAT(SelfDecl, NotNull()); 6763 6764 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6765 auto &SelfVal = *cast<PointerValue>(Env.getValue(*SelfDecl)); 6766 EXPECT_EQ(Env.getStorageLocation(*MyObjDecl), &SelfVal.getPointeeLoc()); 6767 }, 6768 {BuiltinOptions{ContextSensitiveOptions{}}}); 6769 } 6770 6771 TEST(TransferTest, UnnamedBitfieldInitializer) { 6772 std::string Code = R"( 6773 struct B {}; 6774 struct A { 6775 unsigned a; 6776 unsigned : 4; 6777 unsigned c; 6778 B b; 6779 }; 6780 void target() { 6781 A a = {}; 6782 A test = a; 6783 (void)test.c; 6784 } 6785 )"; 6786 runDataflow( 6787 Code, 6788 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6789 ASTContext &ASTCtx) { 6790 // This doesn't need a body because this test was crashing the framework 6791 // before handling correctly Unnamed bitfields in `InitListExpr`. 6792 }); 6793 } 6794 6795 // Repro for a crash that used to occur with chained short-circuiting logical 6796 // operators. 6797 TEST(TransferTest, ChainedLogicalOps) { 6798 std::string Code = R"( 6799 bool target() { 6800 bool b = true || false || false || false; 6801 // [[p]] 6802 return b; 6803 } 6804 )"; 6805 runDataflow( 6806 Code, 6807 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6808 ASTContext &ASTCtx) { 6809 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6810 auto &B = getValueForDecl<BoolValue>(ASTCtx, Env, "b").formula(); 6811 EXPECT_TRUE(Env.proves(B)); 6812 }); 6813 } 6814 6815 // Repro for a crash that used to occur when we call a `noreturn` function 6816 // within one of the operands of a `&&` or `||` operator. 6817 TEST(TransferTest, NoReturnFunctionInsideShortCircuitedBooleanOp) { 6818 std::string Code = R"( 6819 __attribute__((noreturn)) int doesnt_return(); 6820 bool some_condition(); 6821 void target(bool b1, bool b2) { 6822 // Neither of these should crash. In addition, if we don't terminate the 6823 // program, we know that the operators need to trigger the short-circuit 6824 // logic, so `NoreturnOnRhsOfAnd` will be false and `NoreturnOnRhsOfOr` 6825 // will be true. 6826 bool NoreturnOnRhsOfAnd = b1 && doesnt_return() > 0; 6827 bool NoreturnOnRhsOfOr = b2 || doesnt_return() > 0; 6828 6829 // Calling a `noreturn` function on the LHS of an `&&` or `||` makes the 6830 // entire expression unreachable. So we know that in both of the following 6831 // cases, if `target()` terminates, the `else` branch was taken. 6832 bool NoreturnOnLhsMakesAndUnreachable = false; 6833 if (some_condition()) 6834 doesnt_return() > 0 && some_condition(); 6835 else 6836 NoreturnOnLhsMakesAndUnreachable = true; 6837 6838 bool NoreturnOnLhsMakesOrUnreachable = false; 6839 if (some_condition()) 6840 doesnt_return() > 0 || some_condition(); 6841 else 6842 NoreturnOnLhsMakesOrUnreachable = true; 6843 6844 // [[p]] 6845 } 6846 )"; 6847 runDataflow( 6848 Code, 6849 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6850 ASTContext &ASTCtx) { 6851 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6852 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6853 auto &A = Env.arena(); 6854 6855 // Check that [[p]] is reachable with a non-false flow condition. 6856 EXPECT_FALSE(Env.proves(A.makeLiteral(false))); 6857 6858 auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, "b1").formula(); 6859 EXPECT_TRUE(Env.proves(A.makeNot(B1))); 6860 6861 auto &NoreturnOnRhsOfAnd = 6862 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfAnd").formula(); 6863 EXPECT_TRUE(Env.proves(A.makeNot(NoreturnOnRhsOfAnd))); 6864 6865 auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, "b2").formula(); 6866 EXPECT_TRUE(Env.proves(B2)); 6867 6868 auto &NoreturnOnRhsOfOr = 6869 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfOr") 6870 .formula(); 6871 EXPECT_TRUE(Env.proves(NoreturnOnRhsOfOr)); 6872 6873 auto &NoreturnOnLhsMakesAndUnreachable = getValueForDecl<BoolValue>( 6874 ASTCtx, Env, "NoreturnOnLhsMakesAndUnreachable").formula(); 6875 EXPECT_TRUE(Env.proves(NoreturnOnLhsMakesAndUnreachable)); 6876 6877 auto &NoreturnOnLhsMakesOrUnreachable = getValueForDecl<BoolValue>( 6878 ASTCtx, Env, "NoreturnOnLhsMakesOrUnreachable").formula(); 6879 EXPECT_TRUE(Env.proves(NoreturnOnLhsMakesOrUnreachable)); 6880 }); 6881 } 6882 6883 TEST(TransferTest, NewExpressions) { 6884 std::string Code = R"( 6885 void target() { 6886 int *p = new int(42); 6887 // [[after_new]] 6888 } 6889 )"; 6890 runDataflow( 6891 Code, 6892 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6893 ASTContext &ASTCtx) { 6894 const Environment &Env = 6895 getEnvironmentAtAnnotation(Results, "after_new"); 6896 6897 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p"); 6898 6899 EXPECT_THAT(Env.getValue(P.getPointeeLoc()), NotNull()); 6900 }); 6901 } 6902 6903 TEST(TransferTest, NewExpressions_Structs) { 6904 std::string Code = R"( 6905 struct Inner { 6906 int InnerField; 6907 }; 6908 6909 struct Outer { 6910 Inner OuterField; 6911 }; 6912 6913 void target() { 6914 Outer *p = new Outer; 6915 // Access the fields to make sure the analysis actually generates children 6916 // for them in the `RecordStorageLocation`. 6917 p->OuterField.InnerField; 6918 // [[after_new]] 6919 } 6920 )"; 6921 runDataflow( 6922 Code, 6923 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6924 ASTContext &ASTCtx) { 6925 const Environment &Env = 6926 getEnvironmentAtAnnotation(Results, "after_new"); 6927 6928 const ValueDecl *OuterField = findValueDecl(ASTCtx, "OuterField"); 6929 const ValueDecl *InnerField = findValueDecl(ASTCtx, "InnerField"); 6930 6931 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p"); 6932 6933 auto &OuterLoc = cast<RecordStorageLocation>(P.getPointeeLoc()); 6934 auto &OuterFieldLoc = 6935 *cast<RecordStorageLocation>(OuterLoc.getChild(*OuterField)); 6936 auto &InnerFieldLoc = *OuterFieldLoc.getChild(*InnerField); 6937 6938 EXPECT_THAT(Env.getValue(InnerFieldLoc), NotNull()); 6939 }); 6940 } 6941 6942 TEST(TransferTest, FunctionToPointerDecayHasValue) { 6943 std::string Code = R"( 6944 struct A { static void static_member_func(); }; 6945 void target() { 6946 // To check that we're treating function-to-pointer decay correctly, 6947 // create two pointers, then verify they refer to the same storage 6948 // location. 6949 // We need to do the test this way because even if an initializer (in this 6950 // case, the function-to-pointer decay) does not create a value, we still 6951 // create a value for the variable. 6952 void (*non_member_p1)() = target; 6953 void (*non_member_p2)() = target; 6954 6955 // Do the same thing but for a static member function. 6956 void (*member_p1)() = A::static_member_func; 6957 void (*member_p2)() = A::static_member_func; 6958 // [[p]] 6959 } 6960 )"; 6961 runDataflow( 6962 Code, 6963 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6964 ASTContext &ASTCtx) { 6965 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6966 6967 auto &NonMemberP1 = 6968 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p1"); 6969 auto &NonMemberP2 = 6970 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p2"); 6971 EXPECT_EQ(&NonMemberP1.getPointeeLoc(), &NonMemberP2.getPointeeLoc()); 6972 6973 auto &MemberP1 = 6974 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p1"); 6975 auto &MemberP2 = 6976 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p2"); 6977 EXPECT_EQ(&MemberP1.getPointeeLoc(), &MemberP2.getPointeeLoc()); 6978 }); 6979 } 6980 6981 // Check that a builtin function is not associated with a value. (It's only 6982 // possible to call builtin functions directly, not take their address.) 6983 TEST(TransferTest, BuiltinFunctionModeled) { 6984 std::string Code = R"( 6985 void target() { 6986 __builtin_expect(0, 0); 6987 // [[p]] 6988 } 6989 )"; 6990 runDataflow( 6991 Code, 6992 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6993 ASTContext &ASTCtx) { 6994 using ast_matchers::selectFirst; 6995 using ast_matchers::match; 6996 using ast_matchers::traverse; 6997 using ast_matchers::implicitCastExpr; 6998 using ast_matchers::hasCastKind; 6999 7000 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7001 7002 auto *ImplicitCast = selectFirst<ImplicitCastExpr>( 7003 "implicit_cast", 7004 match(traverse(TK_AsIs, 7005 implicitCastExpr(hasCastKind(CK_BuiltinFnToFnPtr)) 7006 .bind("implicit_cast")), 7007 ASTCtx)); 7008 7009 ASSERT_THAT(ImplicitCast, NotNull()); 7010 EXPECT_THAT(Env.getValue(*ImplicitCast), IsNull()); 7011 }); 7012 } 7013 7014 // Check that a callee of a member operator call is modeled as a `PointerValue`. 7015 // Member operator calls are unusual in that their callee is a pointer that 7016 // stems from a `FunctionToPointerDecay`. In calls to non-operator non-static 7017 // member functions, the callee is a `MemberExpr` (which does not have pointer 7018 // type). 7019 // We want to make sure that we produce a pointer value for the callee in this 7020 // specific scenario and that its storage location is durable (for convergence). 7021 TEST(TransferTest, MemberOperatorCallModelsPointerForCallee) { 7022 std::string Code = R"( 7023 struct S { 7024 bool operator!=(S s); 7025 }; 7026 void target() { 7027 S s; 7028 (void)(s != s); 7029 (void)(s != s); 7030 // [[p]] 7031 } 7032 )"; 7033 runDataflow( 7034 Code, 7035 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7036 ASTContext &ASTCtx) { 7037 using ast_matchers::selectFirst; 7038 using ast_matchers::match; 7039 using ast_matchers::traverse; 7040 using ast_matchers::cxxOperatorCallExpr; 7041 7042 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7043 7044 auto Matches = match( 7045 traverse(TK_AsIs, cxxOperatorCallExpr().bind("call")), ASTCtx); 7046 7047 ASSERT_EQ(Matches.size(), 2UL); 7048 7049 auto *Call1 = Matches[0].getNodeAs<CXXOperatorCallExpr>("call"); 7050 auto *Call2 = Matches[1].getNodeAs<CXXOperatorCallExpr>("call"); 7051 7052 ASSERT_THAT(Call1, NotNull()); 7053 ASSERT_THAT(Call2, NotNull()); 7054 7055 EXPECT_EQ(cast<ImplicitCastExpr>(Call1->getCallee())->getCastKind(), 7056 CK_FunctionToPointerDecay); 7057 EXPECT_EQ(cast<ImplicitCastExpr>(Call2->getCallee())->getCastKind(), 7058 CK_FunctionToPointerDecay); 7059 7060 auto *Ptr1 = cast<PointerValue>(Env.getValue(*Call1->getCallee())); 7061 auto *Ptr2 = cast<PointerValue>(Env.getValue(*Call2->getCallee())); 7062 7063 ASSERT_EQ(&Ptr1->getPointeeLoc(), &Ptr2->getPointeeLoc()); 7064 }); 7065 } 7066 7067 // Check that fields of anonymous records are modeled. 7068 TEST(TransferTest, AnonymousStruct) { 7069 std::string Code = R"( 7070 struct S { 7071 struct { 7072 bool b; 7073 }; 7074 }; 7075 void target() { 7076 S s; 7077 s.b = true; 7078 // [[p]] 7079 } 7080 )"; 7081 runDataflow( 7082 Code, 7083 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7084 ASTContext &ASTCtx) { 7085 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7086 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 7087 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b"); 7088 const IndirectFieldDecl *IndirectField = 7089 findIndirectFieldDecl(ASTCtx, "b"); 7090 7091 auto *S = cast<RecordStorageLocation>(Env.getStorageLocation(*SDecl)); 7092 auto &AnonStruct = *cast<RecordStorageLocation>( 7093 S->getChild(*cast<ValueDecl>(IndirectField->chain().front()))); 7094 7095 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env)); 7096 ASSERT_TRUE(Env.proves(B->formula())); 7097 }); 7098 } 7099 7100 TEST(TransferTest, AnonymousStructWithInitializer) { 7101 std::string Code = R"( 7102 struct target { 7103 target() { 7104 (void)0; 7105 // [[p]] 7106 } 7107 struct { 7108 bool b = true; 7109 }; 7110 }; 7111 )"; 7112 runDataflow( 7113 Code, 7114 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7115 ASTContext &ASTCtx) { 7116 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7117 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b"); 7118 const IndirectFieldDecl *IndirectField = 7119 findIndirectFieldDecl(ASTCtx, "b"); 7120 7121 auto *ThisLoc = 7122 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation()); 7123 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild( 7124 *cast<ValueDecl>(IndirectField->chain().front()))); 7125 7126 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env)); 7127 ASSERT_TRUE(Env.proves(B->formula())); 7128 }); 7129 } 7130 7131 TEST(TransferTest, AnonymousStructWithReferenceField) { 7132 std::string Code = R"( 7133 int global_i = 0; 7134 struct target { 7135 target() { 7136 (void)0; 7137 // [[p]] 7138 } 7139 struct { 7140 int &i = global_i; 7141 }; 7142 }; 7143 )"; 7144 runDataflow( 7145 Code, 7146 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7147 ASTContext &ASTCtx) { 7148 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7149 const ValueDecl *GlobalIDecl = findValueDecl(ASTCtx, "global_i"); 7150 const ValueDecl *IDecl = findValueDecl(ASTCtx, "i"); 7151 const IndirectFieldDecl *IndirectField = 7152 findIndirectFieldDecl(ASTCtx, "i"); 7153 7154 auto *ThisLoc = 7155 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation()); 7156 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild( 7157 *cast<ValueDecl>(IndirectField->chain().front()))); 7158 7159 ASSERT_EQ(AnonStruct.getChild(*IDecl), 7160 Env.getStorageLocation(*GlobalIDecl)); 7161 }); 7162 } 7163 7164 TEST(TransferTest, EvaluateBlockWithUnreachablePreds) { 7165 // This is a crash repro. 7166 // `false` block may not have been processed when we try to evaluate the `||` 7167 // after visiting `true`, because it is not necessary (and therefore the edge 7168 // is marked unreachable). Trying to get the analysis state via 7169 // `getEnvironment` for the subexpression still should not crash. 7170 std::string Code = R"( 7171 int target(int i) { 7172 if ((i < 0 && true) || false) { 7173 return 0; 7174 } 7175 return 0; 7176 } 7177 )"; 7178 runDataflow( 7179 Code, 7180 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7181 ASTContext &ASTCtx) {}); 7182 } 7183 7184 TEST(TransferTest, LambdaCaptureByCopy) { 7185 std::string Code = R"( 7186 void target(int Foo, int Bar) { 7187 [Foo]() { 7188 (void)0; 7189 // [[p]] 7190 }(); 7191 } 7192 )"; 7193 runDataflowOnLambda( 7194 Code, 7195 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7196 ASTContext &ASTCtx) { 7197 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 7198 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7199 7200 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 7201 ASSERT_THAT(FooDecl, NotNull()); 7202 7203 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 7204 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 7205 7206 const Value *FooVal = Env.getValue(*FooLoc); 7207 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 7208 7209 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 7210 ASSERT_THAT(BarDecl, NotNull()); 7211 7212 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 7213 EXPECT_THAT(BarLoc, IsNull()); 7214 }); 7215 } 7216 7217 TEST(TransferTest, LambdaCaptureByReference) { 7218 std::string Code = R"( 7219 void target(int Foo, int Bar) { 7220 [&Foo]() { 7221 (void)0; 7222 // [[p]] 7223 }(); 7224 } 7225 )"; 7226 runDataflowOnLambda( 7227 Code, 7228 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7229 ASTContext &ASTCtx) { 7230 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 7231 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7232 7233 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 7234 ASSERT_THAT(FooDecl, NotNull()); 7235 7236 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 7237 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 7238 7239 const Value *FooVal = Env.getValue(*FooLoc); 7240 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 7241 7242 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 7243 ASSERT_THAT(BarDecl, NotNull()); 7244 7245 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 7246 EXPECT_THAT(BarLoc, IsNull()); 7247 }); 7248 } 7249 7250 TEST(TransferTest, LambdaCaptureWithInitializer) { 7251 std::string Code = R"( 7252 void target(int Bar) { 7253 [Foo=Bar]() { 7254 (void)0; 7255 // [[p]] 7256 }(); 7257 } 7258 )"; 7259 runDataflowOnLambda( 7260 Code, 7261 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7262 ASTContext &ASTCtx) { 7263 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 7264 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7265 7266 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 7267 ASSERT_THAT(FooDecl, NotNull()); 7268 7269 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 7270 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 7271 7272 const Value *FooVal = Env.getValue(*FooLoc); 7273 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 7274 7275 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 7276 ASSERT_THAT(BarDecl, NotNull()); 7277 7278 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 7279 EXPECT_THAT(BarLoc, IsNull()); 7280 }); 7281 } 7282 7283 TEST(TransferTest, LambdaCaptureByCopyImplicit) { 7284 std::string Code = R"( 7285 void target(int Foo, int Bar) { 7286 [=]() { 7287 Foo; 7288 // [[p]] 7289 }(); 7290 } 7291 )"; 7292 runDataflowOnLambda( 7293 Code, 7294 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7295 ASTContext &ASTCtx) { 7296 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 7297 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7298 7299 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 7300 ASSERT_THAT(FooDecl, NotNull()); 7301 7302 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 7303 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 7304 7305 const Value *FooVal = Env.getValue(*FooLoc); 7306 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 7307 7308 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 7309 ASSERT_THAT(BarDecl, NotNull()); 7310 7311 // There is no storage location for `Bar` because it isn't used in the 7312 // body of the lambda. 7313 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 7314 EXPECT_THAT(BarLoc, IsNull()); 7315 }); 7316 } 7317 7318 TEST(TransferTest, LambdaCaptureByReferenceImplicit) { 7319 std::string Code = R"( 7320 void target(int Foo, int Bar) { 7321 [&]() { 7322 Foo; 7323 // [[p]] 7324 }(); 7325 } 7326 )"; 7327 runDataflowOnLambda( 7328 Code, 7329 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7330 ASTContext &ASTCtx) { 7331 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 7332 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7333 7334 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 7335 ASSERT_THAT(FooDecl, NotNull()); 7336 7337 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 7338 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 7339 7340 const Value *FooVal = Env.getValue(*FooLoc); 7341 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 7342 7343 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 7344 ASSERT_THAT(BarDecl, NotNull()); 7345 7346 // There is no storage location for `Bar` because it isn't used in the 7347 // body of the lambda. 7348 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 7349 EXPECT_THAT(BarLoc, IsNull()); 7350 }); 7351 } 7352 7353 TEST(TransferTest, LambdaCaptureThis) { 7354 std::string Code = R"( 7355 struct Bar { 7356 int Foo; 7357 7358 void target() { 7359 [this]() { 7360 Foo; 7361 // [[p]] 7362 }(); 7363 } 7364 }; 7365 )"; 7366 runDataflowOnLambda( 7367 Code, 7368 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7369 ASTContext &ASTCtx) { 7370 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 7371 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7372 7373 const RecordStorageLocation *ThisPointeeLoc = 7374 Env.getThisPointeeStorageLocation(); 7375 ASSERT_THAT(ThisPointeeLoc, NotNull()); 7376 7377 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 7378 ASSERT_THAT(FooDecl, NotNull()); 7379 7380 const StorageLocation *FooLoc = ThisPointeeLoc->getChild(*FooDecl); 7381 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 7382 7383 const Value *FooVal = Env.getValue(*FooLoc); 7384 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 7385 }); 7386 } 7387 7388 // This test verifies correct modeling of a relational dependency that goes 7389 // through unmodeled functions (the simple `cond()` in this case). 7390 TEST(TransferTest, ConditionalRelation) { 7391 std::string Code = R"( 7392 bool cond(); 7393 void target() { 7394 bool a = true; 7395 bool b = true; 7396 if (cond()) { 7397 a = false; 7398 if (cond()) { 7399 b = false; 7400 } 7401 } 7402 (void)0; 7403 // [[p]] 7404 } 7405 )"; 7406 runDataflow( 7407 Code, 7408 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7409 ASTContext &ASTCtx) { 7410 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7411 auto &A = Env.arena(); 7412 auto &VarA = getValueForDecl<BoolValue>(ASTCtx, Env, "a").formula(); 7413 auto &VarB = getValueForDecl<BoolValue>(ASTCtx, Env, "b").formula(); 7414 7415 EXPECT_FALSE(Env.allows(A.makeAnd(VarA, A.makeNot(VarB)))); 7416 }); 7417 } 7418 7419 } // namespace 7420