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