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