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