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