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