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