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, StaticCast) { 3313 std::string Code = R"( 3314 void target(int Foo) { 3315 int Bar = static_cast<int>(Foo); 3316 // [[p]] 3317 } 3318 )"; 3319 runDataflow( 3320 Code, 3321 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3322 ASTContext &ASTCtx) { 3323 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3324 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3325 3326 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3327 ASSERT_THAT(FooDecl, NotNull()); 3328 3329 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3330 ASSERT_THAT(BarDecl, NotNull()); 3331 3332 const auto *FooVal = Env.getValue(*FooDecl); 3333 const auto *BarVal = Env.getValue(*BarDecl); 3334 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 3335 EXPECT_TRUE(isa<IntegerValue>(BarVal)); 3336 EXPECT_EQ(FooVal, BarVal); 3337 }); 3338 } 3339 3340 TEST(TransferTest, IntegralCast) { 3341 std::string Code = R"( 3342 void target(int Foo) { 3343 long Bar = Foo; 3344 // [[p]] 3345 } 3346 )"; 3347 runDataflow( 3348 Code, 3349 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3350 ASTContext &ASTCtx) { 3351 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3352 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3353 3354 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3355 ASSERT_THAT(FooDecl, NotNull()); 3356 3357 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3358 ASSERT_THAT(BarDecl, NotNull()); 3359 3360 const auto *FooVal = Env.getValue(*FooDecl); 3361 const auto *BarVal = Env.getValue(*BarDecl); 3362 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 3363 EXPECT_TRUE(isa<IntegerValue>(BarVal)); 3364 EXPECT_EQ(FooVal, BarVal); 3365 }); 3366 } 3367 3368 TEST(TransferTest, IntegraltoBooleanCast) { 3369 std::string Code = R"( 3370 void target(int Foo) { 3371 bool Bar = Foo; 3372 // [[p]] 3373 } 3374 )"; 3375 runDataflow( 3376 Code, 3377 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3378 ASTContext &ASTCtx) { 3379 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3380 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3381 3382 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3383 ASSERT_THAT(FooDecl, NotNull()); 3384 3385 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3386 ASSERT_THAT(BarDecl, NotNull()); 3387 3388 const auto *FooVal = Env.getValue(*FooDecl); 3389 const auto *BarVal = Env.getValue(*BarDecl); 3390 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 3391 EXPECT_TRUE(isa<BoolValue>(BarVal)); 3392 }); 3393 } 3394 3395 TEST(TransferTest, IntegralToBooleanCastFromBool) { 3396 std::string Code = R"( 3397 void target(bool Foo) { 3398 int Zab = Foo; 3399 bool Bar = Zab; 3400 // [[p]] 3401 } 3402 )"; 3403 runDataflow( 3404 Code, 3405 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3406 ASTContext &ASTCtx) { 3407 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3408 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3409 3410 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3411 ASSERT_THAT(FooDecl, NotNull()); 3412 3413 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3414 ASSERT_THAT(BarDecl, NotNull()); 3415 3416 const auto *FooVal = Env.getValue(*FooDecl); 3417 const auto *BarVal = Env.getValue(*BarDecl); 3418 EXPECT_TRUE(isa<BoolValue>(FooVal)); 3419 EXPECT_TRUE(isa<BoolValue>(BarVal)); 3420 EXPECT_EQ(FooVal, BarVal); 3421 }); 3422 } 3423 3424 TEST(TransferTest, NullToPointerCast) { 3425 std::string Code = R"( 3426 using my_nullptr_t = decltype(nullptr); 3427 struct Baz {}; 3428 void target() { 3429 int *FooX = nullptr; 3430 int *FooY = nullptr; 3431 bool **Bar = nullptr; 3432 Baz *Baz = nullptr; 3433 my_nullptr_t Null = 0; 3434 // [[p]] 3435 } 3436 )"; 3437 runDataflow( 3438 Code, 3439 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3440 ASTContext &ASTCtx) { 3441 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3442 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3443 3444 const ValueDecl *FooXDecl = findValueDecl(ASTCtx, "FooX"); 3445 ASSERT_THAT(FooXDecl, NotNull()); 3446 3447 const ValueDecl *FooYDecl = findValueDecl(ASTCtx, "FooY"); 3448 ASSERT_THAT(FooYDecl, NotNull()); 3449 3450 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3451 ASSERT_THAT(BarDecl, NotNull()); 3452 3453 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3454 ASSERT_THAT(BazDecl, NotNull()); 3455 3456 const ValueDecl *NullDecl = findValueDecl(ASTCtx, "Null"); 3457 ASSERT_THAT(NullDecl, NotNull()); 3458 3459 const auto *FooXVal = cast<PointerValue>(Env.getValue(*FooXDecl)); 3460 const auto *FooYVal = cast<PointerValue>(Env.getValue(*FooYDecl)); 3461 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 3462 const auto *BazVal = cast<PointerValue>(Env.getValue(*BazDecl)); 3463 const auto *NullVal = cast<PointerValue>(Env.getValue(*NullDecl)); 3464 3465 EXPECT_EQ(FooXVal, FooYVal); 3466 EXPECT_NE(FooXVal, BarVal); 3467 EXPECT_NE(FooXVal, BazVal); 3468 EXPECT_NE(BarVal, BazVal); 3469 3470 const StorageLocation &FooPointeeLoc = FooXVal->getPointeeLoc(); 3471 EXPECT_TRUE(isa<ScalarStorageLocation>(FooPointeeLoc)); 3472 EXPECT_THAT(Env.getValue(FooPointeeLoc), IsNull()); 3473 3474 const StorageLocation &BarPointeeLoc = BarVal->getPointeeLoc(); 3475 EXPECT_TRUE(isa<ScalarStorageLocation>(BarPointeeLoc)); 3476 EXPECT_THAT(Env.getValue(BarPointeeLoc), IsNull()); 3477 3478 const StorageLocation &BazPointeeLoc = BazVal->getPointeeLoc(); 3479 EXPECT_TRUE(isa<RecordStorageLocation>(BazPointeeLoc)); 3480 EXPECT_EQ(BazVal, &Env.fork().getOrCreateNullPointerValue( 3481 BazPointeeLoc.getType())); 3482 3483 const StorageLocation &NullPointeeLoc = NullVal->getPointeeLoc(); 3484 EXPECT_TRUE(isa<ScalarStorageLocation>(NullPointeeLoc)); 3485 EXPECT_THAT(Env.getValue(NullPointeeLoc), IsNull()); 3486 }); 3487 } 3488 3489 TEST(TransferTest, PointerToMemberVariable) { 3490 std::string Code = R"( 3491 struct S { 3492 int i; 3493 }; 3494 void target() { 3495 int S::*MemberPointer = &S::i; 3496 // [[p]] 3497 } 3498 )"; 3499 runDataflow( 3500 Code, 3501 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3502 ASTContext &ASTCtx) { 3503 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3504 3505 const ValueDecl *MemberPointerDecl = 3506 findValueDecl(ASTCtx, "MemberPointer"); 3507 ASSERT_THAT(MemberPointerDecl, NotNull()); 3508 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 3509 }); 3510 } 3511 3512 TEST(TransferTest, PointerToMemberFunction) { 3513 std::string Code = R"( 3514 struct S { 3515 void Method(); 3516 }; 3517 void target() { 3518 void (S::*MemberPointer)() = &S::Method; 3519 // [[p]] 3520 } 3521 )"; 3522 runDataflow( 3523 Code, 3524 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3525 ASTContext &ASTCtx) { 3526 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3527 3528 const ValueDecl *MemberPointerDecl = 3529 findValueDecl(ASTCtx, "MemberPointer"); 3530 ASSERT_THAT(MemberPointerDecl, NotNull()); 3531 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 3532 }); 3533 } 3534 3535 TEST(TransferTest, NullToMemberPointerCast) { 3536 std::string Code = R"( 3537 struct Foo {}; 3538 void target() { 3539 int Foo::*MemberPointer = nullptr; 3540 // [[p]] 3541 } 3542 )"; 3543 runDataflow( 3544 Code, 3545 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3546 ASTContext &ASTCtx) { 3547 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3548 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3549 3550 const ValueDecl *MemberPointerDecl = 3551 findValueDecl(ASTCtx, "MemberPointer"); 3552 ASSERT_THAT(MemberPointerDecl, NotNull()); 3553 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 3554 }); 3555 } 3556 3557 TEST(TransferTest, AddrOfValue) { 3558 std::string Code = R"( 3559 void target() { 3560 int Foo; 3561 int *Bar = &Foo; 3562 // [[p]] 3563 } 3564 )"; 3565 runDataflow( 3566 Code, 3567 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3568 ASTContext &ASTCtx) { 3569 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3570 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3571 3572 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3573 ASSERT_THAT(FooDecl, NotNull()); 3574 3575 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3576 ASSERT_THAT(BarDecl, NotNull()); 3577 3578 const auto *FooLoc = 3579 cast<ScalarStorageLocation>(Env.getStorageLocation(*FooDecl)); 3580 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 3581 EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc); 3582 }); 3583 } 3584 3585 TEST(TransferTest, AddrOfReference) { 3586 std::string Code = R"( 3587 void target(int *Foo) { 3588 int *Bar = &(*Foo); 3589 // [[p]] 3590 } 3591 )"; 3592 runDataflow( 3593 Code, 3594 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3595 ASTContext &ASTCtx) { 3596 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3597 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3598 3599 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3600 ASSERT_THAT(FooDecl, NotNull()); 3601 3602 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3603 ASSERT_THAT(BarDecl, NotNull()); 3604 3605 const auto *FooVal = cast<PointerValue>(Env.getValue(*FooDecl)); 3606 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 3607 EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc()); 3608 }); 3609 } 3610 3611 TEST(TransferTest, CannotAnalyzeFunctionTemplate) { 3612 std::string Code = R"( 3613 template <typename T> 3614 void target() {} 3615 )"; 3616 ASSERT_THAT_ERROR( 3617 checkDataflowWithNoopAnalysis(Code), 3618 llvm::FailedWithMessage("Cannot analyze templated declarations")); 3619 } 3620 3621 TEST(TransferTest, CannotAnalyzeMethodOfClassTemplate) { 3622 std::string Code = R"( 3623 template <typename T> 3624 struct A { 3625 void target() {} 3626 }; 3627 )"; 3628 ASSERT_THAT_ERROR( 3629 checkDataflowWithNoopAnalysis(Code), 3630 llvm::FailedWithMessage("Cannot analyze templated declarations")); 3631 } 3632 3633 TEST(TransferTest, VarDeclInitAssignConditionalOperator) { 3634 std::string Code = R"( 3635 struct A { 3636 int i; 3637 }; 3638 3639 void target(A Foo, A Bar, bool Cond) { 3640 A Baz = Cond ? A(Foo) : A(Bar); 3641 // Make sure A::i is modeled. 3642 Baz.i; 3643 /*[[p]]*/ 3644 } 3645 )"; 3646 runDataflow( 3647 Code, 3648 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3649 ASTContext &ASTCtx) { 3650 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3651 3652 auto *FooIVal = cast<IntegerValue>(getFieldValue( 3653 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo"), "i", 3654 ASTCtx, Env)); 3655 auto *BarIVal = cast<IntegerValue>(getFieldValue( 3656 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar"), "i", 3657 ASTCtx, Env)); 3658 auto *BazIVal = cast<IntegerValue>(getFieldValue( 3659 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Baz"), "i", 3660 ASTCtx, Env)); 3661 3662 EXPECT_NE(BazIVal, FooIVal); 3663 EXPECT_NE(BazIVal, BarIVal); 3664 }); 3665 } 3666 3667 TEST(TransferTest, VarDeclInDoWhile) { 3668 std::string Code = R"( 3669 void target(int *Foo) { 3670 do { 3671 int Bar = *Foo; 3672 // [[in_loop]] 3673 } while (false); 3674 (void)0; 3675 // [[after_loop]] 3676 } 3677 )"; 3678 runDataflow( 3679 Code, 3680 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3681 ASTContext &ASTCtx) { 3682 const Environment &EnvInLoop = 3683 getEnvironmentAtAnnotation(Results, "in_loop"); 3684 const Environment &EnvAfterLoop = 3685 getEnvironmentAtAnnotation(Results, "after_loop"); 3686 3687 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3688 ASSERT_THAT(FooDecl, NotNull()); 3689 3690 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3691 ASSERT_THAT(BarDecl, NotNull()); 3692 3693 const auto *FooVal = 3694 cast<PointerValue>(EnvAfterLoop.getValue(*FooDecl)); 3695 const auto *FooPointeeVal = 3696 cast<IntegerValue>(EnvAfterLoop.getValue(FooVal->getPointeeLoc())); 3697 3698 const auto *BarVal = cast<IntegerValue>(EnvInLoop.getValue(*BarDecl)); 3699 EXPECT_EQ(BarVal, FooPointeeVal); 3700 3701 ASSERT_THAT(EnvAfterLoop.getValue(*BarDecl), IsNull()); 3702 }); 3703 } 3704 3705 TEST(TransferTest, UnreachableAfterWhileTrue) { 3706 std::string Code = R"( 3707 void target() { 3708 while (true) {} 3709 (void)0; 3710 /*[[p]]*/ 3711 } 3712 )"; 3713 runDataflow( 3714 Code, 3715 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3716 ASTContext &ASTCtx) { 3717 // The node after the while-true is pruned because it is trivially 3718 // known to be unreachable. 3719 ASSERT_TRUE(Results.empty()); 3720 }); 3721 } 3722 3723 TEST(TransferTest, AggregateInitialization) { 3724 std::string BracesCode = R"( 3725 struct A { 3726 int Foo; 3727 }; 3728 3729 struct B { 3730 int Bar; 3731 A Baz; 3732 int Qux; 3733 }; 3734 3735 void target(int BarArg, int FooArg, int QuxArg) { 3736 B Quux{BarArg, {FooArg}, QuxArg}; 3737 B OtherB; 3738 /*[[p]]*/ 3739 } 3740 )"; 3741 std::string BraceElisionCode = R"( 3742 struct A { 3743 int Foo; 3744 }; 3745 3746 struct B { 3747 int Bar; 3748 A Baz; 3749 int Qux; 3750 }; 3751 3752 void target(int BarArg, int FooArg, int QuxArg) { 3753 B Quux = {BarArg, FooArg, QuxArg}; 3754 B OtherB; 3755 /*[[p]]*/ 3756 } 3757 )"; 3758 for (const std::string &Code : {BracesCode, BraceElisionCode}) { 3759 runDataflow( 3760 Code, 3761 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3762 ASTContext &ASTCtx) { 3763 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3764 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3765 3766 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3767 ASSERT_THAT(FooDecl, NotNull()); 3768 3769 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3770 ASSERT_THAT(BarDecl, NotNull()); 3771 3772 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3773 ASSERT_THAT(BazDecl, NotNull()); 3774 3775 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 3776 ASSERT_THAT(QuxDecl, NotNull()); 3777 3778 const ValueDecl *FooArgDecl = findValueDecl(ASTCtx, "FooArg"); 3779 ASSERT_THAT(FooArgDecl, NotNull()); 3780 3781 const ValueDecl *BarArgDecl = findValueDecl(ASTCtx, "BarArg"); 3782 ASSERT_THAT(BarArgDecl, NotNull()); 3783 3784 const ValueDecl *QuxArgDecl = findValueDecl(ASTCtx, "QuxArg"); 3785 ASSERT_THAT(QuxArgDecl, NotNull()); 3786 3787 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 3788 ASSERT_THAT(QuuxDecl, NotNull()); 3789 3790 const auto *FooArgVal = cast<IntegerValue>(Env.getValue(*FooArgDecl)); 3791 const auto *BarArgVal = cast<IntegerValue>(Env.getValue(*BarArgDecl)); 3792 const auto *QuxArgVal = cast<IntegerValue>(Env.getValue(*QuxArgDecl)); 3793 3794 const auto &QuuxLoc = 3795 *cast<RecordStorageLocation>(Env.getStorageLocation(*QuuxDecl)); 3796 const auto &BazLoc = 3797 *cast<RecordStorageLocation>(QuuxLoc.getChild(*BazDecl)); 3798 3799 EXPECT_EQ(getFieldValue(&QuuxLoc, *BarDecl, Env), BarArgVal); 3800 EXPECT_EQ(getFieldValue(&BazLoc, *FooDecl, Env), FooArgVal); 3801 EXPECT_EQ(getFieldValue(&QuuxLoc, *QuxDecl, Env), QuxArgVal); 3802 3803 // Check that fields initialized in an initializer list are always 3804 // modeled in other instances of the same type. 3805 const auto &OtherBLoc = 3806 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "OtherB"); 3807 EXPECT_THAT(OtherBLoc.getChild(*BarDecl), NotNull()); 3808 EXPECT_THAT(OtherBLoc.getChild(*BazDecl), NotNull()); 3809 EXPECT_THAT(OtherBLoc.getChild(*QuxDecl), NotNull()); 3810 }); 3811 } 3812 } 3813 3814 TEST(TransferTest, AggregateInitializationReferenceField) { 3815 std::string Code = R"( 3816 struct S { 3817 int &RefField; 3818 }; 3819 3820 void target(int i) { 3821 S s = { i }; 3822 /*[[p]]*/ 3823 } 3824 )"; 3825 runDataflow( 3826 Code, 3827 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3828 ASTContext &ASTCtx) { 3829 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3830 3831 const ValueDecl *RefFieldDecl = findValueDecl(ASTCtx, "RefField"); 3832 3833 auto &ILoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "i"); 3834 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"); 3835 3836 EXPECT_EQ(SLoc.getChild(*RefFieldDecl), &ILoc); 3837 }); 3838 } 3839 3840 TEST(TransferTest, AggregateInitialization_NotExplicitlyInitializedField) { 3841 std::string Code = R"( 3842 struct S { 3843 int i1; 3844 int i2; 3845 }; 3846 3847 void target(int i) { 3848 S s = { i }; 3849 /*[[p]]*/ 3850 } 3851 )"; 3852 runDataflow( 3853 Code, 3854 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3855 ASTContext &ASTCtx) { 3856 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3857 3858 const ValueDecl *I1FieldDecl = findValueDecl(ASTCtx, "i1"); 3859 const ValueDecl *I2FieldDecl = findValueDecl(ASTCtx, "i2"); 3860 3861 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"); 3862 3863 auto &IValue = getValueForDecl<IntegerValue>(ASTCtx, Env, "i"); 3864 auto &I1Value = 3865 *cast<IntegerValue>(getFieldValue(&SLoc, *I1FieldDecl, Env)); 3866 EXPECT_EQ(&I1Value, &IValue); 3867 auto &I2Value = 3868 *cast<IntegerValue>(getFieldValue(&SLoc, *I2FieldDecl, Env)); 3869 EXPECT_NE(&I2Value, &IValue); 3870 }); 3871 } 3872 3873 TEST(TransferTest, AggregateInitializationFunctionPointer) { 3874 // This is a repro for an assertion failure. 3875 // nullptr takes on the type of a const function pointer, but its type was 3876 // asserted to be equal to the *unqualified* type of Field, which no longer 3877 // included the const. 3878 std::string Code = R"( 3879 struct S { 3880 void (*const Field)(); 3881 }; 3882 3883 void target() { 3884 S s{nullptr}; 3885 } 3886 )"; 3887 runDataflow( 3888 Code, 3889 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3890 ASTContext &ASTCtx) {}); 3891 } 3892 3893 TEST(TransferTest, AssignToUnionMember) { 3894 std::string Code = R"( 3895 union A { 3896 int Foo; 3897 }; 3898 3899 void target(int Bar) { 3900 A Baz; 3901 Baz.Foo = Bar; 3902 // [[p]] 3903 } 3904 )"; 3905 runDataflow( 3906 Code, 3907 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3908 ASTContext &ASTCtx) { 3909 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3910 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3911 3912 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3913 ASSERT_THAT(BazDecl, NotNull()); 3914 ASSERT_TRUE(BazDecl->getType()->isUnionType()); 3915 3916 auto BazFields = BazDecl->getType()->getAsRecordDecl()->fields(); 3917 FieldDecl *FooDecl = nullptr; 3918 for (FieldDecl *Field : BazFields) { 3919 if (Field->getNameAsString() == "Foo") { 3920 FooDecl = Field; 3921 } else { 3922 FAIL() << "Unexpected field: " << Field->getNameAsString(); 3923 } 3924 } 3925 ASSERT_THAT(FooDecl, NotNull()); 3926 3927 const auto *BazLoc = dyn_cast_or_null<RecordStorageLocation>( 3928 Env.getStorageLocation(*BazDecl)); 3929 ASSERT_THAT(BazLoc, NotNull()); 3930 3931 const auto *FooVal = 3932 cast<IntegerValue>(getFieldValue(BazLoc, *FooDecl, Env)); 3933 3934 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3935 ASSERT_THAT(BarDecl, NotNull()); 3936 const auto *BarLoc = Env.getStorageLocation(*BarDecl); 3937 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 3938 3939 EXPECT_EQ(Env.getValue(*BarLoc), FooVal); 3940 }); 3941 } 3942 3943 TEST(TransferTest, AssignFromBoolLiteral) { 3944 std::string Code = R"( 3945 void target() { 3946 bool Foo = true; 3947 bool Bar = false; 3948 // [[p]] 3949 } 3950 )"; 3951 runDataflow( 3952 Code, 3953 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3954 ASTContext &ASTCtx) { 3955 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3956 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3957 3958 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3959 ASSERT_THAT(FooDecl, NotNull()); 3960 3961 const auto *FooVal = 3962 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3963 ASSERT_THAT(FooVal, NotNull()); 3964 3965 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3966 ASSERT_THAT(BarDecl, NotNull()); 3967 3968 const auto *BarVal = 3969 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 3970 ASSERT_THAT(BarVal, NotNull()); 3971 3972 EXPECT_EQ(FooVal, &Env.getBoolLiteralValue(true)); 3973 EXPECT_EQ(BarVal, &Env.getBoolLiteralValue(false)); 3974 }); 3975 } 3976 3977 TEST(TransferTest, AssignFromCompositeBoolExpression) { 3978 { 3979 std::string Code = R"( 3980 void target(bool Foo, bool Bar, bool Qux) { 3981 bool Baz = (Foo) && (Bar || Qux); 3982 // [[p]] 3983 } 3984 )"; 3985 runDataflow( 3986 Code, 3987 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3988 ASTContext &ASTCtx) { 3989 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3990 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3991 3992 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3993 ASSERT_THAT(FooDecl, NotNull()); 3994 3995 const auto *FooVal = 3996 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3997 ASSERT_THAT(FooVal, NotNull()); 3998 3999 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4000 ASSERT_THAT(BarDecl, NotNull()); 4001 4002 const auto *BarVal = 4003 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 4004 ASSERT_THAT(BarVal, NotNull()); 4005 4006 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4007 ASSERT_THAT(QuxDecl, NotNull()); 4008 4009 const auto *QuxVal = 4010 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl)); 4011 ASSERT_THAT(QuxVal, NotNull()); 4012 4013 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4014 ASSERT_THAT(BazDecl, NotNull()); 4015 4016 const auto *BazVal = 4017 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl)); 4018 ASSERT_THAT(BazVal, NotNull()); 4019 auto &A = Env.arena(); 4020 EXPECT_EQ(&BazVal->formula(), 4021 &A.makeAnd(FooVal->formula(), 4022 A.makeOr(BarVal->formula(), QuxVal->formula()))); 4023 }); 4024 } 4025 4026 { 4027 std::string Code = R"( 4028 void target(bool Foo, bool Bar, bool Qux) { 4029 bool Baz = (Foo && Qux) || (Bar); 4030 // [[p]] 4031 } 4032 )"; 4033 runDataflow( 4034 Code, 4035 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4036 ASTContext &ASTCtx) { 4037 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4038 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4039 4040 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4041 ASSERT_THAT(FooDecl, NotNull()); 4042 4043 const auto *FooVal = 4044 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 4045 ASSERT_THAT(FooVal, NotNull()); 4046 4047 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4048 ASSERT_THAT(BarDecl, NotNull()); 4049 4050 const auto *BarVal = 4051 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 4052 ASSERT_THAT(BarVal, NotNull()); 4053 4054 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4055 ASSERT_THAT(QuxDecl, NotNull()); 4056 4057 const auto *QuxVal = 4058 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl)); 4059 ASSERT_THAT(QuxVal, NotNull()); 4060 4061 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4062 ASSERT_THAT(BazDecl, NotNull()); 4063 4064 const auto *BazVal = 4065 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl)); 4066 ASSERT_THAT(BazVal, NotNull()); 4067 auto &A = Env.arena(); 4068 EXPECT_EQ(&BazVal->formula(), 4069 &A.makeOr(A.makeAnd(FooVal->formula(), QuxVal->formula()), 4070 BarVal->formula())); 4071 }); 4072 } 4073 4074 { 4075 std::string Code = R"( 4076 void target(bool A, bool B, bool C, bool D) { 4077 bool Foo = ((A && B) && C) && D; 4078 // [[p]] 4079 } 4080 )"; 4081 runDataflow( 4082 Code, 4083 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4084 ASTContext &ASTCtx) { 4085 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4086 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4087 4088 const ValueDecl *ADecl = findValueDecl(ASTCtx, "A"); 4089 ASSERT_THAT(ADecl, NotNull()); 4090 4091 const auto *AVal = dyn_cast_or_null<BoolValue>(Env.getValue(*ADecl)); 4092 ASSERT_THAT(AVal, NotNull()); 4093 4094 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B"); 4095 ASSERT_THAT(BDecl, NotNull()); 4096 4097 const auto *BVal = dyn_cast_or_null<BoolValue>(Env.getValue(*BDecl)); 4098 ASSERT_THAT(BVal, NotNull()); 4099 4100 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C"); 4101 ASSERT_THAT(CDecl, NotNull()); 4102 4103 const auto *CVal = dyn_cast_or_null<BoolValue>(Env.getValue(*CDecl)); 4104 ASSERT_THAT(CVal, NotNull()); 4105 4106 const ValueDecl *DDecl = findValueDecl(ASTCtx, "D"); 4107 ASSERT_THAT(DDecl, NotNull()); 4108 4109 const auto *DVal = dyn_cast_or_null<BoolValue>(Env.getValue(*DDecl)); 4110 ASSERT_THAT(DVal, NotNull()); 4111 4112 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4113 ASSERT_THAT(FooDecl, NotNull()); 4114 4115 const auto *FooVal = 4116 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 4117 ASSERT_THAT(FooVal, NotNull()); 4118 auto &A = Env.arena(); 4119 EXPECT_EQ( 4120 &FooVal->formula(), 4121 &A.makeAnd(A.makeAnd(A.makeAnd(AVal->formula(), BVal->formula()), 4122 CVal->formula()), 4123 DVal->formula())); 4124 }); 4125 } 4126 } 4127 4128 TEST(TransferTest, AssignFromBoolNegation) { 4129 std::string Code = R"( 4130 void target() { 4131 bool Foo = true; 4132 bool Bar = !(Foo); 4133 // [[p]] 4134 } 4135 )"; 4136 runDataflow( 4137 Code, 4138 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4139 ASTContext &ASTCtx) { 4140 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4141 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4142 4143 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4144 ASSERT_THAT(FooDecl, NotNull()); 4145 4146 const auto *FooVal = 4147 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 4148 ASSERT_THAT(FooVal, NotNull()); 4149 4150 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4151 ASSERT_THAT(BarDecl, NotNull()); 4152 4153 const auto *BarVal = 4154 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 4155 ASSERT_THAT(BarVal, NotNull()); 4156 auto &A = Env.arena(); 4157 EXPECT_EQ(&BarVal->formula(), &A.makeNot(FooVal->formula())); 4158 }); 4159 } 4160 4161 TEST(TransferTest, BuiltinExpect) { 4162 std::string Code = R"( 4163 void target(long Foo) { 4164 long Bar = __builtin_expect(Foo, true); 4165 /*[[p]]*/ 4166 } 4167 )"; 4168 runDataflow( 4169 Code, 4170 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4171 ASTContext &ASTCtx) { 4172 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4173 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4174 4175 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4176 ASSERT_THAT(FooDecl, NotNull()); 4177 4178 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4179 ASSERT_THAT(BarDecl, NotNull()); 4180 4181 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 4182 }); 4183 } 4184 4185 // `__builtin_expect` takes and returns a `long` argument, so other types 4186 // involve casts. This verifies that we identify the input and output in that 4187 // case. 4188 TEST(TransferTest, BuiltinExpectBoolArg) { 4189 std::string Code = R"( 4190 void target(bool Foo) { 4191 bool Bar = __builtin_expect(Foo, true); 4192 /*[[p]]*/ 4193 } 4194 )"; 4195 runDataflow( 4196 Code, 4197 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4198 ASTContext &ASTCtx) { 4199 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4200 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4201 4202 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4203 ASSERT_THAT(FooDecl, NotNull()); 4204 4205 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4206 ASSERT_THAT(BarDecl, NotNull()); 4207 4208 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 4209 }); 4210 } 4211 4212 TEST(TransferTest, BuiltinUnreachable) { 4213 std::string Code = R"( 4214 void target(bool Foo) { 4215 bool Bar = false; 4216 if (Foo) 4217 Bar = Foo; 4218 else 4219 __builtin_unreachable(); 4220 (void)0; 4221 /*[[p]]*/ 4222 } 4223 )"; 4224 runDataflow( 4225 Code, 4226 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4227 ASTContext &ASTCtx) { 4228 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4229 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4230 4231 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4232 ASSERT_THAT(FooDecl, NotNull()); 4233 4234 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4235 ASSERT_THAT(BarDecl, NotNull()); 4236 4237 // `__builtin_unreachable` promises that the code is 4238 // unreachable, so the compiler treats the "then" branch as the 4239 // only possible predecessor of this statement. 4240 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 4241 }); 4242 } 4243 4244 TEST(TransferTest, BuiltinTrap) { 4245 std::string Code = R"( 4246 void target(bool Foo) { 4247 bool Bar = false; 4248 if (Foo) 4249 Bar = Foo; 4250 else 4251 __builtin_trap(); 4252 (void)0; 4253 /*[[p]]*/ 4254 } 4255 )"; 4256 runDataflow( 4257 Code, 4258 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4259 ASTContext &ASTCtx) { 4260 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4261 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4262 4263 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4264 ASSERT_THAT(FooDecl, NotNull()); 4265 4266 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4267 ASSERT_THAT(BarDecl, NotNull()); 4268 4269 // `__builtin_trap` ensures program termination, so only the 4270 // "then" branch is a predecessor of this statement. 4271 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 4272 }); 4273 } 4274 4275 TEST(TransferTest, BuiltinDebugTrap) { 4276 std::string Code = R"( 4277 void target(bool Foo) { 4278 bool Bar = false; 4279 if (Foo) 4280 Bar = Foo; 4281 else 4282 __builtin_debugtrap(); 4283 (void)0; 4284 /*[[p]]*/ 4285 } 4286 )"; 4287 runDataflow( 4288 Code, 4289 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4290 ASTContext &ASTCtx) { 4291 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4292 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4293 4294 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4295 ASSERT_THAT(FooDecl, NotNull()); 4296 4297 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4298 ASSERT_THAT(BarDecl, NotNull()); 4299 4300 // `__builtin_debugtrap` doesn't ensure program termination. 4301 EXPECT_NE(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 4302 }); 4303 } 4304 4305 TEST(TransferTest, StaticIntSingleVarDecl) { 4306 std::string Code = R"( 4307 void target() { 4308 static int Foo; 4309 // [[p]] 4310 } 4311 )"; 4312 runDataflow( 4313 Code, 4314 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4315 ASTContext &ASTCtx) { 4316 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4317 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4318 4319 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4320 ASSERT_THAT(FooDecl, NotNull()); 4321 4322 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 4323 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 4324 4325 const Value *FooVal = Env.getValue(*FooLoc); 4326 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 4327 }); 4328 } 4329 4330 TEST(TransferTest, StaticIntGroupVarDecl) { 4331 std::string Code = R"( 4332 void target() { 4333 static int Foo, Bar; 4334 (void)0; 4335 // [[p]] 4336 } 4337 )"; 4338 runDataflow( 4339 Code, 4340 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4341 ASTContext &ASTCtx) { 4342 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4343 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4344 4345 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4346 ASSERT_THAT(FooDecl, NotNull()); 4347 4348 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4349 ASSERT_THAT(BarDecl, NotNull()); 4350 4351 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 4352 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 4353 4354 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 4355 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 4356 4357 const Value *FooVal = Env.getValue(*FooLoc); 4358 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 4359 4360 const Value *BarVal = Env.getValue(*BarLoc); 4361 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 4362 4363 EXPECT_NE(FooVal, BarVal); 4364 }); 4365 } 4366 4367 TEST(TransferTest, GlobalIntVarDecl) { 4368 std::string Code = R"( 4369 static int Foo; 4370 4371 void target() { 4372 int Bar = Foo; 4373 int Baz = Foo; 4374 // [[p]] 4375 } 4376 )"; 4377 runDataflow( 4378 Code, 4379 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4380 ASTContext &ASTCtx) { 4381 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4382 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4383 4384 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4385 ASSERT_THAT(BarDecl, NotNull()); 4386 4387 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4388 ASSERT_THAT(BazDecl, NotNull()); 4389 4390 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 4391 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 4392 EXPECT_EQ(BarVal, BazVal); 4393 }); 4394 } 4395 4396 TEST(TransferTest, StaticMemberIntVarDecl) { 4397 std::string Code = R"( 4398 struct A { 4399 static int Foo; 4400 }; 4401 4402 void target(A a) { 4403 int Bar = a.Foo; 4404 int Baz = a.Foo; 4405 // [[p]] 4406 } 4407 )"; 4408 runDataflow( 4409 Code, 4410 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4411 ASTContext &ASTCtx) { 4412 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4413 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4414 4415 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4416 ASSERT_THAT(BarDecl, NotNull()); 4417 4418 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4419 ASSERT_THAT(BazDecl, NotNull()); 4420 4421 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 4422 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 4423 EXPECT_EQ(BarVal, BazVal); 4424 }); 4425 } 4426 4427 TEST(TransferTest, StaticMemberRefVarDecl) { 4428 std::string Code = R"( 4429 struct A { 4430 static int &Foo; 4431 }; 4432 4433 void target(A a) { 4434 int Bar = a.Foo; 4435 int Baz = a.Foo; 4436 // [[p]] 4437 } 4438 )"; 4439 runDataflow( 4440 Code, 4441 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4442 ASTContext &ASTCtx) { 4443 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4444 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4445 4446 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4447 ASSERT_THAT(BarDecl, NotNull()); 4448 4449 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4450 ASSERT_THAT(BazDecl, NotNull()); 4451 4452 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 4453 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 4454 EXPECT_EQ(BarVal, BazVal); 4455 }); 4456 } 4457 4458 TEST(TransferTest, AssignMemberBeforeCopy) { 4459 std::string Code = R"( 4460 struct A { 4461 int Foo; 4462 }; 4463 4464 void target() { 4465 A A1; 4466 A A2; 4467 int Bar; 4468 A1.Foo = Bar; 4469 A2 = A1; 4470 // [[p]] 4471 } 4472 )"; 4473 runDataflow( 4474 Code, 4475 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4476 ASTContext &ASTCtx) { 4477 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4478 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4479 4480 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4481 ASSERT_THAT(FooDecl, NotNull()); 4482 4483 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4484 ASSERT_THAT(BarDecl, NotNull()); 4485 4486 const ValueDecl *A1Decl = findValueDecl(ASTCtx, "A1"); 4487 ASSERT_THAT(A1Decl, NotNull()); 4488 4489 const ValueDecl *A2Decl = findValueDecl(ASTCtx, "A2"); 4490 ASSERT_THAT(A2Decl, NotNull()); 4491 4492 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 4493 4494 const auto &A2Loc = 4495 *cast<RecordStorageLocation>(Env.getStorageLocation(*A2Decl)); 4496 EXPECT_EQ(getFieldValue(&A2Loc, *FooDecl, Env), BarVal); 4497 }); 4498 } 4499 4500 TEST(TransferTest, BooleanEquality) { 4501 std::string Code = R"( 4502 void target(bool Bar) { 4503 bool Foo = true; 4504 if (Bar == Foo) { 4505 (void)0; 4506 /*[[p-then]]*/ 4507 } else { 4508 (void)0; 4509 /*[[p-else]]*/ 4510 } 4511 } 4512 )"; 4513 runDataflow( 4514 Code, 4515 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4516 ASTContext &ASTCtx) { 4517 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else")); 4518 const Environment &EnvThen = 4519 getEnvironmentAtAnnotation(Results, "p-then"); 4520 const Environment &EnvElse = 4521 getEnvironmentAtAnnotation(Results, "p-else"); 4522 4523 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4524 ASSERT_THAT(BarDecl, NotNull()); 4525 4526 auto &BarValThen = getFormula(*BarDecl, EnvThen); 4527 EXPECT_TRUE(EnvThen.proves(BarValThen)); 4528 4529 auto &BarValElse = getFormula(*BarDecl, EnvElse); 4530 EXPECT_TRUE(EnvElse.proves(EnvElse.arena().makeNot(BarValElse))); 4531 }); 4532 } 4533 4534 TEST(TransferTest, BooleanInequality) { 4535 std::string Code = R"( 4536 void target(bool Bar) { 4537 bool Foo = true; 4538 if (Bar != Foo) { 4539 (void)0; 4540 /*[[p-then]]*/ 4541 } else { 4542 (void)0; 4543 /*[[p-else]]*/ 4544 } 4545 } 4546 )"; 4547 runDataflow( 4548 Code, 4549 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4550 ASTContext &ASTCtx) { 4551 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else")); 4552 const Environment &EnvThen = 4553 getEnvironmentAtAnnotation(Results, "p-then"); 4554 const Environment &EnvElse = 4555 getEnvironmentAtAnnotation(Results, "p-else"); 4556 4557 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4558 ASSERT_THAT(BarDecl, NotNull()); 4559 4560 auto &BarValThen = getFormula(*BarDecl, EnvThen); 4561 EXPECT_TRUE(EnvThen.proves(EnvThen.arena().makeNot(BarValThen))); 4562 4563 auto &BarValElse = getFormula(*BarDecl, EnvElse); 4564 EXPECT_TRUE(EnvElse.proves(BarValElse)); 4565 }); 4566 } 4567 4568 TEST(TransferTest, IntegerLiteralEquality) { 4569 std::string Code = R"( 4570 void target() { 4571 bool equal = (42 == 42); 4572 // [[p]] 4573 } 4574 )"; 4575 runDataflow( 4576 Code, 4577 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4578 ASTContext &ASTCtx) { 4579 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4580 4581 auto &Equal = 4582 getValueForDecl<BoolValue>(ASTCtx, Env, "equal").formula(); 4583 EXPECT_TRUE(Env.proves(Equal)); 4584 }); 4585 } 4586 4587 TEST(TransferTest, CorrelatedBranches) { 4588 std::string Code = R"( 4589 void target(bool B, bool C) { 4590 if (B) { 4591 return; 4592 } 4593 (void)0; 4594 /*[[p0]]*/ 4595 if (C) { 4596 B = true; 4597 /*[[p1]]*/ 4598 } 4599 if (B) { 4600 (void)0; 4601 /*[[p2]]*/ 4602 } 4603 } 4604 )"; 4605 runDataflow( 4606 Code, 4607 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4608 ASTContext &ASTCtx) { 4609 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p0", "p1", "p2")); 4610 4611 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C"); 4612 ASSERT_THAT(CDecl, NotNull()); 4613 4614 { 4615 const Environment &Env = getEnvironmentAtAnnotation(Results, "p0"); 4616 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B"); 4617 ASSERT_THAT(BDecl, NotNull()); 4618 auto &BVal = getFormula(*BDecl, Env); 4619 4620 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BVal))); 4621 } 4622 4623 { 4624 const Environment &Env = getEnvironmentAtAnnotation(Results, "p1"); 4625 auto &CVal = getFormula(*CDecl, Env); 4626 EXPECT_TRUE(Env.proves(CVal)); 4627 } 4628 4629 { 4630 const Environment &Env = getEnvironmentAtAnnotation(Results, "p2"); 4631 auto &CVal = getFormula(*CDecl, Env); 4632 EXPECT_TRUE(Env.proves(CVal)); 4633 } 4634 }); 4635 } 4636 4637 TEST(TransferTest, LoopWithAssignmentConverges) { 4638 std::string Code = R"( 4639 bool foo(); 4640 4641 void target() { 4642 do { 4643 bool Bar = foo(); 4644 if (Bar) break; 4645 (void)Bar; 4646 /*[[p]]*/ 4647 } while (true); 4648 } 4649 )"; 4650 // The key property that we are verifying is implicit in `runDataflow` -- 4651 // namely, that the analysis succeeds, rather than hitting the maximum number 4652 // of iterations. 4653 runDataflow( 4654 Code, 4655 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4656 ASTContext &ASTCtx) { 4657 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4658 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4659 4660 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4661 ASSERT_THAT(BarDecl, NotNull()); 4662 4663 auto &BarVal = getFormula(*BarDecl, Env); 4664 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 4665 }); 4666 } 4667 4668 TEST(TransferTest, LoopWithStagedAssignments) { 4669 std::string Code = R"( 4670 bool foo(); 4671 4672 void target() { 4673 bool Bar = false; 4674 bool Err = false; 4675 while (foo()) { 4676 if (Bar) 4677 Err = true; 4678 Bar = true; 4679 /*[[p]]*/ 4680 } 4681 } 4682 )"; 4683 runDataflow( 4684 Code, 4685 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4686 ASTContext &ASTCtx) { 4687 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4688 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4689 4690 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4691 ASSERT_THAT(BarDecl, NotNull()); 4692 const ValueDecl *ErrDecl = findValueDecl(ASTCtx, "Err"); 4693 ASSERT_THAT(ErrDecl, NotNull()); 4694 4695 auto &BarVal = getFormula(*BarDecl, Env); 4696 auto &ErrVal = getFormula(*ErrDecl, Env); 4697 EXPECT_TRUE(Env.proves(BarVal)); 4698 // An unsound analysis, for example only evaluating the loop once, can 4699 // conclude that `Err` is false. So, we test that this conclusion is not 4700 // reached. 4701 EXPECT_FALSE(Env.proves(Env.arena().makeNot(ErrVal))); 4702 }); 4703 } 4704 4705 TEST(TransferTest, LoopWithReferenceAssignmentConverges) { 4706 std::string Code = R"( 4707 bool &foo(); 4708 4709 void target() { 4710 do { 4711 bool& Bar = foo(); 4712 if (Bar) break; 4713 (void)Bar; 4714 /*[[p]]*/ 4715 } while (true); 4716 } 4717 )"; 4718 // The key property that we are verifying is that the analysis succeeds, 4719 // rather than hitting the maximum number of iterations. 4720 runDataflow( 4721 Code, 4722 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4723 ASTContext &ASTCtx) { 4724 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4725 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4726 4727 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4728 ASSERT_THAT(BarDecl, NotNull()); 4729 4730 auto &BarVal = getFormula(*BarDecl, Env); 4731 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 4732 }); 4733 } 4734 4735 TEST(TransferTest, LoopWithStructReferenceAssignmentConverges) { 4736 std::string Code = R"( 4737 struct Lookup { 4738 int x; 4739 }; 4740 4741 void target(Lookup val, bool b) { 4742 const Lookup* l = nullptr; 4743 while (b) { 4744 l = &val; 4745 /*[[p-inner]]*/ 4746 } 4747 (void)0; 4748 /*[[p-outer]]*/ 4749 } 4750 )"; 4751 // The key property that we are verifying is implicit in `runDataflow` -- 4752 // namely, that the analysis succeeds, rather than hitting the maximum number 4753 // of iterations. 4754 runDataflow( 4755 Code, 4756 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4757 ASTContext &ASTCtx) { 4758 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-inner", "p-outer")); 4759 const Environment &InnerEnv = 4760 getEnvironmentAtAnnotation(Results, "p-inner"); 4761 const Environment &OuterEnv = 4762 getEnvironmentAtAnnotation(Results, "p-outer"); 4763 4764 const ValueDecl *ValDecl = findValueDecl(ASTCtx, "val"); 4765 ASSERT_THAT(ValDecl, NotNull()); 4766 4767 const ValueDecl *LDecl = findValueDecl(ASTCtx, "l"); 4768 ASSERT_THAT(LDecl, NotNull()); 4769 4770 // Inner. 4771 auto *LVal = dyn_cast<PointerValue>(InnerEnv.getValue(*LDecl)); 4772 ASSERT_THAT(LVal, NotNull()); 4773 4774 EXPECT_EQ(&LVal->getPointeeLoc(), 4775 InnerEnv.getStorageLocation(*ValDecl)); 4776 4777 // Outer. 4778 LVal = dyn_cast<PointerValue>(OuterEnv.getValue(*LDecl)); 4779 ASSERT_THAT(LVal, NotNull()); 4780 4781 // The loop body may not have been executed, so we should not conclude 4782 // that `l` points to `val`. 4783 EXPECT_NE(&LVal->getPointeeLoc(), 4784 OuterEnv.getStorageLocation(*ValDecl)); 4785 }); 4786 } 4787 4788 TEST(TransferTest, LoopDereferencingChangingPointerConverges) { 4789 std::string Code = R"cc( 4790 bool some_condition(); 4791 4792 void target(int i1, int i2) { 4793 int *p = &i1; 4794 while (true) { 4795 (void)*p; 4796 if (some_condition()) 4797 p = &i1; 4798 else 4799 p = &i2; 4800 } 4801 } 4802 )cc"; 4803 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 4804 } 4805 4806 TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) { 4807 std::string Code = R"cc( 4808 struct Lookup { 4809 int x; 4810 }; 4811 4812 bool some_condition(); 4813 4814 void target(Lookup l1, Lookup l2) { 4815 Lookup *l = &l1; 4816 while (true) { 4817 (void)l->x; 4818 if (some_condition()) 4819 l = &l1; 4820 else 4821 l = &l2; 4822 } 4823 } 4824 )cc"; 4825 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 4826 } 4827 4828 TEST(TransferTest, LoopWithShortCircuitedConditionConverges) { 4829 std::string Code = R"cc( 4830 bool foo(); 4831 4832 void target() { 4833 bool c = false; 4834 while (foo() || foo()) { 4835 c = true; 4836 } 4837 } 4838 )cc"; 4839 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 4840 } 4841 4842 TEST(TransferTest, LoopCanProveInvariantForBoolean) { 4843 // Check that we can prove `b` is always false in the loop. 4844 // This test exercises the logic in `widenDistinctValues()` that preserves 4845 // information if the boolean can be proved to be either true or false in both 4846 // the previous and current iteration. 4847 std::string Code = R"cc( 4848 int return_int(); 4849 void target() { 4850 bool b = return_int() == 0; 4851 if (b) return; 4852 while (true) { 4853 b; 4854 // [[p]] 4855 b = return_int() == 0; 4856 if (b) return; 4857 } 4858 } 4859 )cc"; 4860 runDataflow( 4861 Code, 4862 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4863 ASTContext &ASTCtx) { 4864 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4865 auto &BVal = getValueForDecl<BoolValue>(ASTCtx, Env, "b"); 4866 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BVal.formula()))); 4867 }); 4868 } 4869 4870 TEST(TransferTest, DoesNotCrashOnUnionThisExpr) { 4871 std::string Code = R"cc( 4872 union Union { 4873 int A; 4874 float B; 4875 }; 4876 4877 void foo() { 4878 Union A; 4879 Union B; 4880 A = B; 4881 } 4882 )cc"; 4883 // This is a crash regression test when calling the transfer function on a 4884 // `CXXThisExpr` that refers to a union. 4885 runDataflow( 4886 Code, 4887 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &, 4888 ASTContext &) {}, 4889 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator="); 4890 } 4891 4892 TEST(TransferTest, DoesNotCrashOnNullChildren) { 4893 std::string Code = (CoroutineLibrary + R"cc( 4894 task target() noexcept { 4895 co_return; 4896 } 4897 )cc") 4898 .str(); 4899 // This is a crash regression test when calling `AdornedCFG::build` on a 4900 // statement (in this case, the `CoroutineBodyStmt`) with null children. 4901 runDataflow( 4902 Code, 4903 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &, 4904 ASTContext &) {}, 4905 LangStandard::lang_cxx20, /*ApplyBuiltinTransfer=*/true); 4906 } 4907 4908 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToRefs) { 4909 std::string Code = R"( 4910 struct A { 4911 int Foo; 4912 int Bar; 4913 }; 4914 4915 void target() { 4916 int Qux; 4917 A Baz; 4918 Baz.Foo = Qux; 4919 auto &FooRef = Baz.Foo; 4920 auto &BarRef = Baz.Bar; 4921 auto &[BoundFooRef, BoundBarRef] = Baz; 4922 // [[p]] 4923 } 4924 )"; 4925 runDataflow( 4926 Code, 4927 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4928 ASTContext &ASTCtx) { 4929 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4930 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4931 4932 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 4933 ASSERT_THAT(FooRefDecl, NotNull()); 4934 4935 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 4936 ASSERT_THAT(BarRefDecl, NotNull()); 4937 4938 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4939 ASSERT_THAT(QuxDecl, NotNull()); 4940 4941 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef"); 4942 ASSERT_THAT(BoundFooRefDecl, NotNull()); 4943 4944 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef"); 4945 ASSERT_THAT(BoundBarRefDecl, NotNull()); 4946 4947 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 4948 ASSERT_THAT(FooRefLoc, NotNull()); 4949 4950 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 4951 ASSERT_THAT(BarRefLoc, NotNull()); 4952 4953 const Value *QuxVal = Env.getValue(*QuxDecl); 4954 ASSERT_THAT(QuxVal, NotNull()); 4955 4956 const StorageLocation *BoundFooRefLoc = 4957 Env.getStorageLocation(*BoundFooRefDecl); 4958 EXPECT_EQ(BoundFooRefLoc, FooRefLoc); 4959 4960 const StorageLocation *BoundBarRefLoc = 4961 Env.getStorageLocation(*BoundBarRefDecl); 4962 EXPECT_EQ(BoundBarRefLoc, BarRefLoc); 4963 4964 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal); 4965 }); 4966 } 4967 4968 TEST(TransferTest, StructuredBindingAssignFromStructRefMembersToRefs) { 4969 std::string Code = R"( 4970 struct A { 4971 int &Foo; 4972 int &Bar; 4973 }; 4974 4975 void target(A Baz) { 4976 int Qux; 4977 Baz.Foo = Qux; 4978 auto &FooRef = Baz.Foo; 4979 auto &BarRef = Baz.Bar; 4980 auto &[BoundFooRef, BoundBarRef] = Baz; 4981 // [[p]] 4982 } 4983 )"; 4984 runDataflow( 4985 Code, 4986 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4987 ASTContext &ASTCtx) { 4988 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4989 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4990 4991 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 4992 ASSERT_THAT(FooRefDecl, NotNull()); 4993 4994 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 4995 ASSERT_THAT(BarRefDecl, NotNull()); 4996 4997 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4998 ASSERT_THAT(QuxDecl, NotNull()); 4999 5000 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef"); 5001 ASSERT_THAT(BoundFooRefDecl, NotNull()); 5002 5003 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef"); 5004 ASSERT_THAT(BoundBarRefDecl, NotNull()); 5005 5006 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 5007 ASSERT_THAT(FooRefLoc, NotNull()); 5008 5009 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 5010 ASSERT_THAT(BarRefLoc, NotNull()); 5011 5012 const Value *QuxVal = Env.getValue(*QuxDecl); 5013 ASSERT_THAT(QuxVal, NotNull()); 5014 5015 const StorageLocation *BoundFooRefLoc = 5016 Env.getStorageLocation(*BoundFooRefDecl); 5017 EXPECT_EQ(BoundFooRefLoc, FooRefLoc); 5018 5019 const StorageLocation *BoundBarRefLoc = 5020 Env.getStorageLocation(*BoundBarRefDecl); 5021 EXPECT_EQ(BoundBarRefLoc, BarRefLoc); 5022 5023 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal); 5024 }); 5025 } 5026 5027 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToInts) { 5028 std::string Code = R"( 5029 struct A { 5030 int Foo; 5031 int Bar; 5032 }; 5033 5034 void target() { 5035 int Qux; 5036 A Baz; 5037 Baz.Foo = Qux; 5038 auto &FooRef = Baz.Foo; 5039 auto &BarRef = Baz.Bar; 5040 auto [BoundFoo, BoundBar] = Baz; 5041 // [[p]] 5042 } 5043 )"; 5044 runDataflow( 5045 Code, 5046 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5047 ASTContext &ASTCtx) { 5048 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5049 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5050 5051 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 5052 ASSERT_THAT(FooRefDecl, NotNull()); 5053 5054 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 5055 ASSERT_THAT(BarRefDecl, NotNull()); 5056 5057 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 5058 ASSERT_THAT(BoundFooDecl, NotNull()); 5059 5060 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 5061 ASSERT_THAT(BoundBarDecl, NotNull()); 5062 5063 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 5064 ASSERT_THAT(QuxDecl, NotNull()); 5065 5066 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 5067 ASSERT_THAT(FooRefLoc, NotNull()); 5068 5069 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 5070 ASSERT_THAT(BarRefLoc, NotNull()); 5071 5072 const Value *QuxVal = Env.getValue(*QuxDecl); 5073 ASSERT_THAT(QuxVal, NotNull()); 5074 5075 const StorageLocation *BoundFooLoc = 5076 Env.getStorageLocation(*BoundFooDecl); 5077 EXPECT_NE(BoundFooLoc, FooRefLoc); 5078 5079 const StorageLocation *BoundBarLoc = 5080 Env.getStorageLocation(*BoundBarDecl); 5081 EXPECT_NE(BoundBarLoc, BarRefLoc); 5082 5083 EXPECT_EQ(Env.getValue(*BoundFooDecl), QuxVal); 5084 }); 5085 } 5086 5087 TEST(TransferTest, StructuredBindingAssignFromTupleLikeType) { 5088 std::string Code = R"( 5089 namespace std { 5090 using size_t = int; 5091 template <class> struct tuple_size; 5092 template <std::size_t, class> struct tuple_element; 5093 template <class...> class tuple; 5094 5095 namespace { 5096 template <class T, T v> 5097 struct size_helper { static const T value = v; }; 5098 } // namespace 5099 5100 template <class... T> 5101 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {}; 5102 5103 template <std::size_t I, class... T> 5104 struct tuple_element<I, tuple<T...>> { 5105 using type = __type_pack_element<I, T...>; 5106 }; 5107 5108 template <class...> class tuple {}; 5109 5110 template <std::size_t I, class... T> 5111 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 5112 } // namespace std 5113 5114 std::tuple<bool, int> makeTuple(); 5115 5116 void target(bool B) { 5117 auto [BoundFoo, BoundBar] = makeTuple(); 5118 bool Baz; 5119 // Include if-then-else to test interaction of `BindingDecl` with join. 5120 if (B) { 5121 Baz = BoundFoo; 5122 (void)BoundBar; 5123 // [[p1]] 5124 } else { 5125 Baz = BoundFoo; 5126 } 5127 (void)0; 5128 // [[p2]] 5129 } 5130 )"; 5131 runDataflow( 5132 Code, 5133 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5134 ASTContext &ASTCtx) { 5135 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 5136 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 5137 5138 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 5139 ASSERT_THAT(BoundFooDecl, NotNull()); 5140 5141 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 5142 ASSERT_THAT(BoundBarDecl, NotNull()); 5143 5144 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5145 ASSERT_THAT(BazDecl, NotNull()); 5146 5147 // BindingDecls always map to references -- either lvalue or rvalue, so 5148 // we still need to skip here. 5149 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl); 5150 ASSERT_THAT(BoundFooValue, NotNull()); 5151 EXPECT_TRUE(isa<BoolValue>(BoundFooValue)); 5152 5153 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl); 5154 ASSERT_THAT(BoundBarValue, NotNull()); 5155 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue)); 5156 5157 // Test that a `DeclRefExpr` to a `BindingDecl` works as expected. 5158 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue); 5159 5160 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 5161 5162 // Test that `BoundFooDecl` retains the value we expect, after the join. 5163 BoundFooValue = Env2.getValue(*BoundFooDecl); 5164 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue); 5165 }); 5166 } 5167 5168 TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) { 5169 std::string Code = R"( 5170 namespace std { 5171 using size_t = int; 5172 template <class> struct tuple_size; 5173 template <std::size_t, class> struct tuple_element; 5174 template <class...> class tuple; 5175 5176 namespace { 5177 template <class T, T v> 5178 struct size_helper { static const T value = v; }; 5179 } // namespace 5180 5181 template <class... T> 5182 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {}; 5183 5184 template <std::size_t I, class... T> 5185 struct tuple_element<I, tuple<T...>> { 5186 using type = __type_pack_element<I, T...>; 5187 }; 5188 5189 template <class...> class tuple {}; 5190 5191 template <std::size_t I, class... T> 5192 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 5193 } // namespace std 5194 5195 std::tuple<bool, int> &getTuple(); 5196 5197 void target(bool B) { 5198 auto &[BoundFoo, BoundBar] = getTuple(); 5199 bool Baz; 5200 // Include if-then-else to test interaction of `BindingDecl` with join. 5201 if (B) { 5202 Baz = BoundFoo; 5203 (void)BoundBar; 5204 // [[p1]] 5205 } else { 5206 Baz = BoundFoo; 5207 } 5208 (void)0; 5209 // [[p2]] 5210 } 5211 )"; 5212 runDataflow( 5213 Code, 5214 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5215 ASTContext &ASTCtx) { 5216 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 5217 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 5218 5219 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 5220 ASSERT_THAT(BoundFooDecl, NotNull()); 5221 5222 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 5223 ASSERT_THAT(BoundBarDecl, NotNull()); 5224 5225 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5226 ASSERT_THAT(BazDecl, NotNull()); 5227 5228 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl); 5229 ASSERT_THAT(BoundFooValue, NotNull()); 5230 EXPECT_TRUE(isa<BoolValue>(BoundFooValue)); 5231 5232 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl); 5233 ASSERT_THAT(BoundBarValue, NotNull()); 5234 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue)); 5235 5236 // Test that a `DeclRefExpr` to a `BindingDecl` (with reference type) 5237 // works as expected. We don't test aliasing properties of the 5238 // reference, because we don't model `std::get` and so have no way to 5239 // equate separate references into the tuple. 5240 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue); 5241 5242 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 5243 5244 // Test that `BoundFooDecl` retains the value we expect, after the join. 5245 BoundFooValue = Env2.getValue(*BoundFooDecl); 5246 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue); 5247 }); 5248 } 5249 5250 TEST(TransferTest, BinaryOperatorComma) { 5251 std::string Code = R"( 5252 void target(int Foo, int Bar) { 5253 int &Baz = (Foo, Bar); 5254 // [[p]] 5255 } 5256 )"; 5257 runDataflow( 5258 Code, 5259 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5260 ASTContext &ASTCtx) { 5261 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5262 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5263 5264 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5265 ASSERT_THAT(BarDecl, NotNull()); 5266 5267 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5268 ASSERT_THAT(BazDecl, NotNull()); 5269 5270 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 5271 ASSERT_THAT(BarLoc, NotNull()); 5272 5273 const StorageLocation *BazLoc = Env.getStorageLocation(*BazDecl); 5274 EXPECT_EQ(BazLoc, BarLoc); 5275 }); 5276 } 5277 5278 TEST(TransferTest, ConditionalOperatorValue) { 5279 std::string Code = R"( 5280 void target(bool Cond, bool B1, bool B2) { 5281 bool JoinSame = Cond ? B1 : B1; 5282 bool JoinDifferent = Cond ? B1 : B2; 5283 // [[p]] 5284 } 5285 )"; 5286 runDataflow( 5287 Code, 5288 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5289 ASTContext &ASTCtx) { 5290 Environment Env = getEnvironmentAtAnnotation(Results, "p").fork(); 5291 5292 auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, "B1"); 5293 auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, "B2"); 5294 auto &JoinSame = getValueForDecl<BoolValue>(ASTCtx, Env, "JoinSame"); 5295 auto &JoinDifferent = 5296 getValueForDecl<BoolValue>(ASTCtx, Env, "JoinDifferent"); 5297 5298 EXPECT_EQ(&JoinSame, &B1); 5299 5300 const Formula &JoinDifferentEqB1 = 5301 Env.arena().makeEquals(JoinDifferent.formula(), B1.formula()); 5302 EXPECT_TRUE(Env.allows(JoinDifferentEqB1)); 5303 EXPECT_FALSE(Env.proves(JoinDifferentEqB1)); 5304 5305 const Formula &JoinDifferentEqB2 = 5306 Env.arena().makeEquals(JoinDifferent.formula(), B2.formula()); 5307 EXPECT_TRUE(Env.allows(JoinDifferentEqB2)); 5308 EXPECT_FALSE(Env.proves(JoinDifferentEqB1)); 5309 }); 5310 } 5311 5312 TEST(TransferTest, ConditionalOperatorLocation) { 5313 std::string Code = R"( 5314 void target(bool Cond, int I1, int I2) { 5315 int &JoinSame = Cond ? I1 : I1; 5316 int &JoinDifferent = Cond ? I1 : I2; 5317 // [[p]] 5318 } 5319 )"; 5320 runDataflow( 5321 Code, 5322 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5323 ASTContext &ASTCtx) { 5324 Environment Env = getEnvironmentAtAnnotation(Results, "p").fork(); 5325 5326 StorageLocation &I1 = getLocForDecl(ASTCtx, Env, "I1"); 5327 StorageLocation &I2 = getLocForDecl(ASTCtx, Env, "I2"); 5328 StorageLocation &JoinSame = getLocForDecl(ASTCtx, Env, "JoinSame"); 5329 StorageLocation &JoinDifferent = 5330 getLocForDecl(ASTCtx, Env, "JoinDifferent"); 5331 5332 EXPECT_EQ(&JoinSame, &I1); 5333 5334 EXPECT_NE(&JoinDifferent, &I1); 5335 EXPECT_NE(&JoinDifferent, &I2); 5336 }); 5337 } 5338 5339 TEST(TransferTest, IfStmtBranchExtendsFlowCondition) { 5340 std::string Code = R"( 5341 void target(bool Foo) { 5342 if (Foo) { 5343 (void)0; 5344 // [[if_then]] 5345 } else { 5346 (void)0; 5347 // [[if_else]] 5348 } 5349 } 5350 )"; 5351 runDataflow( 5352 Code, 5353 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5354 ASTContext &ASTCtx) { 5355 ASSERT_THAT(Results.keys(), UnorderedElementsAre("if_then", "if_else")); 5356 const Environment &ThenEnv = 5357 getEnvironmentAtAnnotation(Results, "if_then"); 5358 const Environment &ElseEnv = 5359 getEnvironmentAtAnnotation(Results, "if_else"); 5360 5361 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5362 ASSERT_THAT(FooDecl, NotNull()); 5363 5364 auto &ThenFooVal= getFormula(*FooDecl, ThenEnv); 5365 EXPECT_TRUE(ThenEnv.proves(ThenFooVal)); 5366 5367 auto &ElseFooVal = getFormula(*FooDecl, ElseEnv); 5368 EXPECT_TRUE(ElseEnv.proves(ElseEnv.arena().makeNot(ElseFooVal))); 5369 }); 5370 } 5371 5372 TEST(TransferTest, WhileStmtBranchExtendsFlowCondition) { 5373 std::string Code = R"( 5374 void target(bool Foo) { 5375 while (Foo) { 5376 (void)0; 5377 // [[loop_body]] 5378 } 5379 (void)0; 5380 // [[after_loop]] 5381 } 5382 )"; 5383 runDataflow( 5384 Code, 5385 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5386 ASTContext &ASTCtx) { 5387 ASSERT_THAT(Results.keys(), 5388 UnorderedElementsAre("loop_body", "after_loop")); 5389 const Environment &LoopBodyEnv = 5390 getEnvironmentAtAnnotation(Results, "loop_body"); 5391 const Environment &AfterLoopEnv = 5392 getEnvironmentAtAnnotation(Results, "after_loop"); 5393 5394 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5395 ASSERT_THAT(FooDecl, NotNull()); 5396 5397 auto &LoopBodyFooVal = getFormula(*FooDecl, LoopBodyEnv); 5398 EXPECT_TRUE(LoopBodyEnv.proves(LoopBodyFooVal)); 5399 5400 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 5401 EXPECT_TRUE( 5402 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal))); 5403 }); 5404 } 5405 5406 TEST(TransferTest, DoWhileStmtBranchExtendsFlowCondition) { 5407 std::string Code = R"( 5408 void target(bool Foo) { 5409 bool Bar = true; 5410 do { 5411 (void)0; 5412 // [[loop_body]] 5413 Bar = false; 5414 } while (Foo); 5415 (void)0; 5416 // [[after_loop]] 5417 } 5418 )"; 5419 runDataflow( 5420 Code, 5421 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5422 ASTContext &ASTCtx) { 5423 ASSERT_THAT(Results.keys(), 5424 UnorderedElementsAre("loop_body", "after_loop")); 5425 const Environment &LoopBodyEnv = 5426 getEnvironmentAtAnnotation(Results, "loop_body"); 5427 const Environment &AfterLoopEnv = 5428 getEnvironmentAtAnnotation(Results, "after_loop"); 5429 auto &A = AfterLoopEnv.arena(); 5430 5431 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5432 ASSERT_THAT(FooDecl, NotNull()); 5433 5434 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5435 ASSERT_THAT(BarDecl, NotNull()); 5436 5437 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 5438 auto &LoopBodyBarVal = getFormula(*BarDecl, LoopBodyEnv); 5439 EXPECT_TRUE( 5440 LoopBodyEnv.proves(A.makeOr(LoopBodyBarVal, LoopBodyFooVal))); 5441 5442 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 5443 auto &AfterLoopBarVal = getFormula(*BarDecl, AfterLoopEnv); 5444 EXPECT_TRUE(AfterLoopEnv.proves(A.makeNot(AfterLoopFooVal))); 5445 EXPECT_TRUE(AfterLoopEnv.proves(A.makeNot(AfterLoopBarVal))); 5446 }); 5447 } 5448 5449 TEST(TransferTest, ForStmtBranchExtendsFlowCondition) { 5450 std::string Code = R"( 5451 void target(bool Foo) { 5452 for (; Foo;) { 5453 (void)0; 5454 // [[loop_body]] 5455 } 5456 (void)0; 5457 // [[after_loop]] 5458 } 5459 )"; 5460 runDataflow( 5461 Code, 5462 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5463 ASTContext &ASTCtx) { 5464 ASSERT_THAT(Results.keys(), 5465 UnorderedElementsAre("loop_body", "after_loop")); 5466 const Environment &LoopBodyEnv = 5467 getEnvironmentAtAnnotation(Results, "loop_body"); 5468 const Environment &AfterLoopEnv = 5469 getEnvironmentAtAnnotation(Results, "after_loop"); 5470 5471 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5472 ASSERT_THAT(FooDecl, NotNull()); 5473 5474 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 5475 EXPECT_TRUE(LoopBodyEnv.proves(LoopBodyFooVal)); 5476 5477 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 5478 EXPECT_TRUE( 5479 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal))); 5480 }); 5481 } 5482 5483 TEST(TransferTest, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition) { 5484 std::string Code = R"( 5485 void target(bool Foo) { 5486 for (;;) { 5487 (void)0; 5488 // [[loop_body]] 5489 } 5490 } 5491 )"; 5492 runDataflow( 5493 Code, 5494 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5495 ASTContext &ASTCtx) { 5496 ASSERT_THAT(Results.keys(), UnorderedElementsAre("loop_body")); 5497 const Environment &LoopBodyEnv = 5498 getEnvironmentAtAnnotation(Results, "loop_body"); 5499 5500 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5501 ASSERT_THAT(FooDecl, NotNull()); 5502 5503 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 5504 EXPECT_FALSE(LoopBodyEnv.proves(LoopBodyFooVal)); 5505 }); 5506 } 5507 5508 TEST(TransferTest, ContextSensitiveOptionDisabled) { 5509 std::string Code = R"( 5510 bool GiveBool(); 5511 void SetBool(bool &Var) { Var = true; } 5512 5513 void target() { 5514 bool Foo = GiveBool(); 5515 SetBool(Foo); 5516 // [[p]] 5517 } 5518 )"; 5519 runDataflow( 5520 Code, 5521 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5522 ASTContext &ASTCtx) { 5523 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5524 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5525 5526 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5527 ASSERT_THAT(FooDecl, NotNull()); 5528 5529 auto &FooVal = getFormula(*FooDecl, Env); 5530 EXPECT_FALSE(Env.proves(FooVal)); 5531 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5532 }, 5533 {BuiltinOptions{/*.ContextSensitiveOpts=*/std::nullopt}}); 5534 } 5535 5536 TEST(TransferTest, ContextSensitiveReturnReference) { 5537 std::string Code = R"( 5538 class S {}; 5539 S& target(bool b, S &s) { 5540 return s; 5541 // [[p]] 5542 } 5543 )"; 5544 runDataflow( 5545 Code, 5546 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5547 ASTContext &ASTCtx) { 5548 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5549 5550 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 5551 ASSERT_THAT(SDecl, NotNull()); 5552 5553 auto *SLoc = Env.getStorageLocation(*SDecl); 5554 ASSERT_THAT(SLoc, NotNull()); 5555 5556 ASSERT_THAT(Env.getReturnStorageLocation(), Eq(SLoc)); 5557 }, 5558 {BuiltinOptions{ContextSensitiveOptions{}}}); 5559 } 5560 5561 // This test is a regression test, based on a real crash. 5562 TEST(TransferTest, ContextSensitiveReturnReferenceWithConditionalOperator) { 5563 std::string Code = R"( 5564 class S {}; 5565 S& target(bool b, S &s) { 5566 return b ? s : s; 5567 // [[p]] 5568 } 5569 )"; 5570 runDataflow( 5571 Code, 5572 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5573 ASTContext &ASTCtx) { 5574 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5575 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5576 5577 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 5578 ASSERT_THAT(SDecl, NotNull()); 5579 5580 auto *SLoc = Env.getStorageLocation(*SDecl); 5581 EXPECT_THAT(SLoc, NotNull()); 5582 5583 auto *Loc = Env.getReturnStorageLocation(); 5584 EXPECT_THAT(Loc, NotNull()); 5585 5586 EXPECT_EQ(Loc, SLoc); 5587 }, 5588 {BuiltinOptions{ContextSensitiveOptions{}}}); 5589 } 5590 5591 TEST(TransferTest, ContextSensitiveReturnOneOfTwoReferences) { 5592 std::string Code = R"( 5593 class S {}; 5594 S &callee(bool b, S &s1_parm, S &s2_parm) { 5595 if (b) 5596 return s1_parm; 5597 else 5598 return s2_parm; 5599 } 5600 void target(bool b) { 5601 S s1; 5602 S s2; 5603 S &return_s1 = s1; 5604 S &return_s2 = s2; 5605 S &return_dont_know = callee(b, s1, s2); 5606 // [[p]] 5607 } 5608 )"; 5609 runDataflow( 5610 Code, 5611 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5612 ASTContext &ASTCtx) { 5613 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5614 5615 const ValueDecl *S1 = findValueDecl(ASTCtx, "s1"); 5616 ASSERT_THAT(S1, NotNull()); 5617 const ValueDecl *S2 = findValueDecl(ASTCtx, "s2"); 5618 ASSERT_THAT(S2, NotNull()); 5619 const ValueDecl *ReturnS1 = findValueDecl(ASTCtx, "return_s1"); 5620 ASSERT_THAT(ReturnS1, NotNull()); 5621 const ValueDecl *ReturnS2 = findValueDecl(ASTCtx, "return_s2"); 5622 ASSERT_THAT(ReturnS2, NotNull()); 5623 const ValueDecl *ReturnDontKnow = 5624 findValueDecl(ASTCtx, "return_dont_know"); 5625 ASSERT_THAT(ReturnDontKnow, NotNull()); 5626 5627 StorageLocation *S1Loc = Env.getStorageLocation(*S1); 5628 StorageLocation *S2Loc = Env.getStorageLocation(*S2); 5629 5630 EXPECT_THAT(Env.getStorageLocation(*ReturnS1), Eq(S1Loc)); 5631 EXPECT_THAT(Env.getStorageLocation(*ReturnS2), Eq(S2Loc)); 5632 5633 // In the case where we don't have a consistent storage location for 5634 // the return value, the framework creates a new storage location, which 5635 // should be different from the storage locations of `s1` and `s2`. 5636 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S1Loc)); 5637 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S2Loc)); 5638 }, 5639 {BuiltinOptions{ContextSensitiveOptions{}}}); 5640 } 5641 5642 TEST(TransferTest, ContextSensitiveDepthZero) { 5643 std::string Code = R"( 5644 bool GiveBool(); 5645 void SetBool(bool &Var) { Var = true; } 5646 5647 void target() { 5648 bool Foo = GiveBool(); 5649 SetBool(Foo); 5650 // [[p]] 5651 } 5652 )"; 5653 runDataflow( 5654 Code, 5655 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5656 ASTContext &ASTCtx) { 5657 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5658 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5659 5660 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5661 ASSERT_THAT(FooDecl, NotNull()); 5662 5663 auto &FooVal = getFormula(*FooDecl, Env); 5664 EXPECT_FALSE(Env.proves(FooVal)); 5665 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5666 }, 5667 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/0}}}); 5668 } 5669 5670 TEST(TransferTest, ContextSensitiveSetTrue) { 5671 std::string Code = R"( 5672 bool GiveBool(); 5673 void SetBool(bool &Var) { Var = true; } 5674 5675 void target() { 5676 bool Foo = GiveBool(); 5677 SetBool(Foo); 5678 // [[p]] 5679 } 5680 )"; 5681 runDataflow( 5682 Code, 5683 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5684 ASTContext &ASTCtx) { 5685 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5686 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5687 5688 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5689 ASSERT_THAT(FooDecl, NotNull()); 5690 5691 auto &FooVal = getFormula(*FooDecl, Env); 5692 EXPECT_TRUE(Env.proves(FooVal)); 5693 }, 5694 {BuiltinOptions{ContextSensitiveOptions{}}}); 5695 } 5696 5697 TEST(TransferTest, ContextSensitiveSetFalse) { 5698 std::string Code = R"( 5699 bool GiveBool(); 5700 void SetBool(bool &Var) { Var = false; } 5701 5702 void target() { 5703 bool Foo = GiveBool(); 5704 SetBool(Foo); 5705 // [[p]] 5706 } 5707 )"; 5708 runDataflow( 5709 Code, 5710 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5711 ASTContext &ASTCtx) { 5712 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5713 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5714 5715 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5716 ASSERT_THAT(FooDecl, NotNull()); 5717 5718 auto &FooVal = getFormula(*FooDecl, Env); 5719 EXPECT_TRUE(Env.proves(Env.arena().makeNot(FooVal))); 5720 }, 5721 {BuiltinOptions{ContextSensitiveOptions{}}}); 5722 } 5723 5724 TEST(TransferTest, ContextSensitiveSetBothTrueAndFalse) { 5725 std::string Code = R"( 5726 bool GiveBool(); 5727 void SetBool(bool &Var, bool Val) { Var = Val; } 5728 5729 void target() { 5730 bool Foo = GiveBool(); 5731 bool Bar = GiveBool(); 5732 SetBool(Foo, true); 5733 SetBool(Bar, false); 5734 // [[p]] 5735 } 5736 )"; 5737 runDataflow( 5738 Code, 5739 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5740 ASTContext &ASTCtx) { 5741 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5742 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5743 auto &A = Env.arena(); 5744 5745 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5746 ASSERT_THAT(FooDecl, NotNull()); 5747 5748 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5749 ASSERT_THAT(BarDecl, NotNull()); 5750 5751 auto &FooVal = getFormula(*FooDecl, Env); 5752 EXPECT_TRUE(Env.proves(FooVal)); 5753 EXPECT_FALSE(Env.proves(A.makeNot(FooVal))); 5754 5755 auto &BarVal = getFormula(*BarDecl, Env); 5756 EXPECT_FALSE(Env.proves(BarVal)); 5757 EXPECT_TRUE(Env.proves(A.makeNot(BarVal))); 5758 }, 5759 {BuiltinOptions{ContextSensitiveOptions{}}}); 5760 } 5761 5762 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthOne) { 5763 std::string Code = R"( 5764 bool GiveBool(); 5765 void SetBool1(bool &Var) { Var = true; } 5766 void SetBool2(bool &Var) { SetBool1(Var); } 5767 5768 void target() { 5769 bool Foo = GiveBool(); 5770 SetBool2(Foo); 5771 // [[p]] 5772 } 5773 )"; 5774 runDataflow( 5775 Code, 5776 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5777 ASTContext &ASTCtx) { 5778 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5779 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5780 5781 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5782 ASSERT_THAT(FooDecl, NotNull()); 5783 5784 auto &FooVal = getFormula(*FooDecl, Env); 5785 EXPECT_FALSE(Env.proves(FooVal)); 5786 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5787 }, 5788 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/1}}}); 5789 } 5790 5791 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthTwo) { 5792 std::string Code = R"( 5793 bool GiveBool(); 5794 void SetBool1(bool &Var) { Var = true; } 5795 void SetBool2(bool &Var) { SetBool1(Var); } 5796 5797 void target() { 5798 bool Foo = GiveBool(); 5799 SetBool2(Foo); 5800 // [[p]] 5801 } 5802 )"; 5803 runDataflow( 5804 Code, 5805 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5806 ASTContext &ASTCtx) { 5807 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5808 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5809 5810 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5811 ASSERT_THAT(FooDecl, NotNull()); 5812 5813 auto &FooVal = getFormula(*FooDecl, Env); 5814 EXPECT_TRUE(Env.proves(FooVal)); 5815 }, 5816 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}}); 5817 } 5818 5819 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthTwo) { 5820 std::string Code = R"( 5821 bool GiveBool(); 5822 void SetBool1(bool &Var) { Var = true; } 5823 void SetBool2(bool &Var) { SetBool1(Var); } 5824 void SetBool3(bool &Var) { SetBool2(Var); } 5825 5826 void target() { 5827 bool Foo = GiveBool(); 5828 SetBool3(Foo); 5829 // [[p]] 5830 } 5831 )"; 5832 runDataflow( 5833 Code, 5834 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5835 ASTContext &ASTCtx) { 5836 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5837 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5838 5839 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5840 ASSERT_THAT(FooDecl, NotNull()); 5841 5842 auto &FooVal = getFormula(*FooDecl, Env); 5843 EXPECT_FALSE(Env.proves(FooVal)); 5844 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5845 }, 5846 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}}); 5847 } 5848 5849 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthThree) { 5850 std::string Code = R"( 5851 bool GiveBool(); 5852 void SetBool1(bool &Var) { Var = true; } 5853 void SetBool2(bool &Var) { SetBool1(Var); } 5854 void SetBool3(bool &Var) { SetBool2(Var); } 5855 5856 void target() { 5857 bool Foo = GiveBool(); 5858 SetBool3(Foo); 5859 // [[p]] 5860 } 5861 )"; 5862 runDataflow( 5863 Code, 5864 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5865 ASTContext &ASTCtx) { 5866 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5867 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5868 5869 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5870 ASSERT_THAT(FooDecl, NotNull()); 5871 5872 auto &FooVal = getFormula(*FooDecl, Env); 5873 EXPECT_TRUE(Env.proves(FooVal)); 5874 }, 5875 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/3}}}); 5876 } 5877 5878 TEST(TransferTest, ContextSensitiveMutualRecursion) { 5879 std::string Code = R"( 5880 bool Pong(bool X, bool Y); 5881 5882 bool Ping(bool X, bool Y) { 5883 if (X) { 5884 return Y; 5885 } else { 5886 return Pong(!X, Y); 5887 } 5888 } 5889 5890 bool Pong(bool X, bool Y) { 5891 if (Y) { 5892 return X; 5893 } else { 5894 return Ping(X, !Y); 5895 } 5896 } 5897 5898 void target() { 5899 bool Foo = Ping(false, false); 5900 // [[p]] 5901 } 5902 )"; 5903 runDataflow( 5904 Code, 5905 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5906 ASTContext &ASTCtx) { 5907 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5908 // The analysis doesn't crash... 5909 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5910 5911 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5912 ASSERT_THAT(FooDecl, NotNull()); 5913 5914 auto &FooVal = getFormula(*FooDecl, Env); 5915 // ... but it also can't prove anything here. 5916 EXPECT_FALSE(Env.proves(FooVal)); 5917 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5918 }, 5919 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/4}}}); 5920 } 5921 5922 TEST(TransferTest, ContextSensitiveSetMultipleLines) { 5923 std::string Code = R"( 5924 void SetBools(bool &Var1, bool &Var2) { 5925 Var1 = true; 5926 Var2 = false; 5927 } 5928 5929 void target() { 5930 bool Foo = false; 5931 bool Bar = true; 5932 SetBools(Foo, Bar); 5933 // [[p]] 5934 } 5935 )"; 5936 runDataflow( 5937 Code, 5938 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5939 ASTContext &ASTCtx) { 5940 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5941 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5942 5943 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5944 ASSERT_THAT(FooDecl, NotNull()); 5945 5946 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5947 ASSERT_THAT(BarDecl, NotNull()); 5948 5949 auto &FooVal = getFormula(*FooDecl, Env); 5950 EXPECT_TRUE(Env.proves(FooVal)); 5951 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5952 5953 auto &BarVal = getFormula(*BarDecl, Env); 5954 EXPECT_FALSE(Env.proves(BarVal)); 5955 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 5956 }, 5957 {BuiltinOptions{ContextSensitiveOptions{}}}); 5958 } 5959 5960 TEST(TransferTest, ContextSensitiveSetMultipleBlocks) { 5961 std::string Code = R"( 5962 void IfCond(bool Cond, bool &Then, bool &Else) { 5963 if (Cond) { 5964 Then = true; 5965 } else { 5966 Else = true; 5967 } 5968 } 5969 5970 void target() { 5971 bool Foo = false; 5972 bool Bar = false; 5973 bool Baz = false; 5974 IfCond(Foo, Bar, Baz); 5975 // [[p]] 5976 } 5977 )"; 5978 runDataflow( 5979 Code, 5980 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5981 ASTContext &ASTCtx) { 5982 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5983 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5984 5985 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5986 ASSERT_THAT(BarDecl, NotNull()); 5987 5988 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5989 ASSERT_THAT(BazDecl, NotNull()); 5990 5991 auto &BarVal = getFormula(*BarDecl, Env); 5992 EXPECT_FALSE(Env.proves(BarVal)); 5993 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 5994 5995 auto &BazVal = getFormula(*BazDecl, Env); 5996 EXPECT_TRUE(Env.proves(BazVal)); 5997 EXPECT_FALSE(Env.proves(Env.arena().makeNot(BazVal))); 5998 }, 5999 {BuiltinOptions{ContextSensitiveOptions{}}}); 6000 } 6001 6002 TEST(TransferTest, ContextSensitiveReturnVoid) { 6003 std::string Code = R"( 6004 void Noop() { return; } 6005 6006 void target() { 6007 Noop(); 6008 // [[p]] 6009 } 6010 )"; 6011 runDataflow( 6012 Code, 6013 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6014 ASTContext &ASTCtx) { 6015 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6016 // This just tests that the analysis doesn't crash. 6017 }, 6018 {BuiltinOptions{ContextSensitiveOptions{}}}); 6019 } 6020 6021 TEST(TransferTest, ContextSensitiveReturnTrue) { 6022 std::string Code = R"( 6023 bool GiveBool() { return true; } 6024 6025 void target() { 6026 bool Foo = GiveBool(); 6027 // [[p]] 6028 } 6029 )"; 6030 runDataflow( 6031 Code, 6032 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6033 ASTContext &ASTCtx) { 6034 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6035 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6036 6037 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6038 ASSERT_THAT(FooDecl, NotNull()); 6039 6040 auto &FooVal = getFormula(*FooDecl, Env); 6041 EXPECT_TRUE(Env.proves(FooVal)); 6042 }, 6043 {BuiltinOptions{ContextSensitiveOptions{}}}); 6044 } 6045 6046 TEST(TransferTest, ContextSensitiveReturnFalse) { 6047 std::string Code = R"( 6048 bool GiveBool() { return false; } 6049 6050 void target() { 6051 bool Foo = GiveBool(); 6052 // [[p]] 6053 } 6054 )"; 6055 runDataflow( 6056 Code, 6057 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6058 ASTContext &ASTCtx) { 6059 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6060 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6061 6062 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6063 ASSERT_THAT(FooDecl, NotNull()); 6064 6065 auto &FooVal = getFormula(*FooDecl, Env); 6066 EXPECT_TRUE(Env.proves(Env.arena().makeNot(FooVal))); 6067 }, 6068 {BuiltinOptions{ContextSensitiveOptions{}}}); 6069 } 6070 6071 TEST(TransferTest, ContextSensitiveReturnArg) { 6072 std::string Code = R"( 6073 bool GiveBool(); 6074 bool GiveBack(bool Arg) { return Arg; } 6075 6076 void target() { 6077 bool Foo = GiveBool(); 6078 bool Bar = GiveBack(Foo); 6079 bool Baz = Foo == Bar; 6080 // [[p]] 6081 } 6082 )"; 6083 runDataflow( 6084 Code, 6085 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6086 ASTContext &ASTCtx) { 6087 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6088 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6089 6090 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 6091 ASSERT_THAT(BazDecl, NotNull()); 6092 6093 auto &BazVal = getFormula(*BazDecl, Env); 6094 EXPECT_TRUE(Env.proves(BazVal)); 6095 }, 6096 {BuiltinOptions{ContextSensitiveOptions{}}}); 6097 } 6098 6099 TEST(TransferTest, ContextSensitiveReturnInt) { 6100 std::string Code = R"( 6101 int identity(int x) { return x; } 6102 6103 void target() { 6104 int y = identity(42); 6105 // [[p]] 6106 } 6107 )"; 6108 runDataflow( 6109 Code, 6110 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6111 ASTContext &ASTCtx) { 6112 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6113 // This just tests that the analysis doesn't crash. 6114 }, 6115 {BuiltinOptions{ContextSensitiveOptions{}}}); 6116 } 6117 6118 TEST(TransferTest, ContextSensitiveReturnRecord) { 6119 std::string Code = R"( 6120 struct S { 6121 bool B; 6122 }; 6123 6124 S makeS(bool BVal) { return {BVal}; } 6125 6126 void target() { 6127 S FalseS = makeS(false); 6128 S TrueS = makeS(true); 6129 // [[p]] 6130 } 6131 )"; 6132 runDataflow( 6133 Code, 6134 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6135 ASTContext &ASTCtx) { 6136 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6137 6138 auto &FalseSLoc = 6139 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "FalseS"); 6140 auto &TrueSLoc = 6141 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "TrueS"); 6142 6143 EXPECT_EQ(getFieldValue(&FalseSLoc, "B", ASTCtx, Env), 6144 &Env.getBoolLiteralValue(false)); 6145 EXPECT_EQ(getFieldValue(&TrueSLoc, "B", ASTCtx, Env), 6146 &Env.getBoolLiteralValue(true)); 6147 }, 6148 {BuiltinOptions{ContextSensitiveOptions{}}}); 6149 } 6150 6151 TEST(TransferTest, ContextSensitiveReturnSelfReferentialRecord) { 6152 std::string Code = R"( 6153 struct S { 6154 S() { self = this; } 6155 S *self; 6156 }; 6157 6158 S makeS() { 6159 // RVO guarantees that this will be constructed directly into `MyS`. 6160 return S(); 6161 } 6162 6163 void target() { 6164 S MyS = makeS(); 6165 // [[p]] 6166 } 6167 )"; 6168 runDataflow( 6169 Code, 6170 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6171 ASTContext &ASTCtx) { 6172 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6173 6174 auto &MySLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "MyS"); 6175 6176 auto *SelfVal = 6177 cast<PointerValue>(getFieldValue(&MySLoc, "self", ASTCtx, Env)); 6178 EXPECT_EQ(&SelfVal->getPointeeLoc(), &MySLoc); 6179 }, 6180 {BuiltinOptions{ContextSensitiveOptions{}}}); 6181 } 6182 6183 TEST(TransferTest, ContextSensitiveMethodLiteral) { 6184 std::string Code = R"( 6185 class MyClass { 6186 public: 6187 bool giveBool() { return true; } 6188 }; 6189 6190 void target() { 6191 MyClass MyObj; 6192 bool Foo = MyObj.giveBool(); 6193 // [[p]] 6194 } 6195 )"; 6196 runDataflow( 6197 Code, 6198 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6199 ASTContext &ASTCtx) { 6200 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6201 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6202 6203 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6204 ASSERT_THAT(FooDecl, NotNull()); 6205 6206 auto &FooVal = getFormula(*FooDecl, Env); 6207 EXPECT_TRUE(Env.proves(FooVal)); 6208 }, 6209 {BuiltinOptions{ContextSensitiveOptions{}}}); 6210 } 6211 6212 TEST(TransferTest, ContextSensitiveMethodGetter) { 6213 std::string Code = R"( 6214 class MyClass { 6215 public: 6216 bool getField() { return Field; } 6217 6218 bool Field; 6219 }; 6220 6221 void target() { 6222 MyClass MyObj; 6223 MyObj.Field = true; 6224 bool Foo = MyObj.getField(); 6225 // [[p]] 6226 } 6227 )"; 6228 runDataflow( 6229 Code, 6230 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6231 ASTContext &ASTCtx) { 6232 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6233 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6234 6235 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6236 ASSERT_THAT(FooDecl, NotNull()); 6237 6238 auto &FooVal = getFormula(*FooDecl, Env); 6239 EXPECT_TRUE(Env.proves(FooVal)); 6240 }, 6241 {BuiltinOptions{ContextSensitiveOptions{}}}); 6242 } 6243 6244 TEST(TransferTest, ContextSensitiveMethodSetter) { 6245 std::string Code = R"( 6246 class MyClass { 6247 public: 6248 void setField(bool Val) { Field = Val; } 6249 6250 bool Field; 6251 }; 6252 6253 void target() { 6254 MyClass MyObj; 6255 MyObj.setField(true); 6256 bool Foo = MyObj.Field; 6257 // [[p]] 6258 } 6259 )"; 6260 runDataflow( 6261 Code, 6262 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6263 ASTContext &ASTCtx) { 6264 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6265 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6266 6267 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6268 ASSERT_THAT(FooDecl, NotNull()); 6269 6270 auto &FooVal = getFormula(*FooDecl, Env); 6271 EXPECT_TRUE(Env.proves(FooVal)); 6272 }, 6273 {BuiltinOptions{ContextSensitiveOptions{}}}); 6274 } 6275 6276 TEST(TransferTest, ContextSensitiveMethodGetterAndSetter) { 6277 std::string Code = R"( 6278 class MyClass { 6279 public: 6280 bool getField() { return Field; } 6281 void setField(bool Val) { Field = Val; } 6282 6283 private: 6284 bool Field; 6285 }; 6286 6287 void target() { 6288 MyClass MyObj; 6289 MyObj.setField(true); 6290 bool Foo = MyObj.getField(); 6291 // [[p]] 6292 } 6293 )"; 6294 runDataflow( 6295 Code, 6296 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6297 ASTContext &ASTCtx) { 6298 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6299 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6300 6301 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6302 ASSERT_THAT(FooDecl, NotNull()); 6303 6304 auto &FooVal = getFormula(*FooDecl, Env); 6305 EXPECT_TRUE(Env.proves(FooVal)); 6306 }, 6307 {BuiltinOptions{ContextSensitiveOptions{}}}); 6308 } 6309 6310 6311 TEST(TransferTest, ContextSensitiveMethodTwoLayersVoid) { 6312 std::string Code = R"( 6313 class MyClass { 6314 public: 6315 void Inner() { MyField = true; } 6316 void Outer() { Inner(); } 6317 6318 bool MyField; 6319 }; 6320 6321 void target() { 6322 MyClass MyObj; 6323 MyObj.Outer(); 6324 bool Foo = MyObj.MyField; 6325 // [[p]] 6326 } 6327 )"; 6328 runDataflow( 6329 Code, 6330 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6331 ASTContext &ASTCtx) { 6332 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6333 ; 6334 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6335 6336 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6337 ASSERT_THAT(FooDecl, NotNull()); 6338 6339 auto &FooVal = getFormula(*FooDecl, Env); 6340 EXPECT_TRUE(Env.proves(FooVal)); 6341 }, 6342 {BuiltinOptions{ContextSensitiveOptions{}}}); 6343 } 6344 6345 TEST(TransferTest, ContextSensitiveMethodTwoLayersReturn) { 6346 std::string Code = R"( 6347 class MyClass { 6348 public: 6349 bool Inner() { return MyField; } 6350 bool Outer() { return Inner(); } 6351 6352 bool MyField; 6353 }; 6354 6355 void target() { 6356 MyClass MyObj; 6357 MyObj.MyField = true; 6358 bool Foo = MyObj.Outer(); 6359 // [[p]] 6360 } 6361 )"; 6362 runDataflow( 6363 Code, 6364 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6365 ASTContext &ASTCtx) { 6366 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6367 ; 6368 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6369 6370 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6371 ASSERT_THAT(FooDecl, NotNull()); 6372 6373 auto &FooVal = getFormula(*FooDecl, Env); 6374 EXPECT_TRUE(Env.proves(FooVal)); 6375 }, 6376 {BuiltinOptions{ContextSensitiveOptions{}}}); 6377 } 6378 6379 TEST(TransferTest, ContextSensitiveConstructorBody) { 6380 std::string Code = R"( 6381 class MyClass { 6382 public: 6383 MyClass() { MyField = true; } 6384 6385 bool MyField; 6386 }; 6387 6388 void target() { 6389 MyClass MyObj; 6390 bool Foo = MyObj.MyField; 6391 // [[p]] 6392 } 6393 )"; 6394 runDataflow( 6395 Code, 6396 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6397 ASTContext &ASTCtx) { 6398 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6399 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6400 6401 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6402 ASSERT_THAT(FooDecl, NotNull()); 6403 6404 auto &FooVal = getFormula(*FooDecl, Env); 6405 EXPECT_TRUE(Env.proves(FooVal)); 6406 }, 6407 {BuiltinOptions{ContextSensitiveOptions{}}}); 6408 } 6409 6410 TEST(TransferTest, ContextSensitiveConstructorInitializer) { 6411 std::string Code = R"( 6412 class MyClass { 6413 public: 6414 MyClass() : MyField(true) {} 6415 6416 bool MyField; 6417 }; 6418 6419 void target() { 6420 MyClass MyObj; 6421 bool Foo = MyObj.MyField; 6422 // [[p]] 6423 } 6424 )"; 6425 runDataflow( 6426 Code, 6427 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6428 ASTContext &ASTCtx) { 6429 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6430 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6431 6432 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6433 ASSERT_THAT(FooDecl, NotNull()); 6434 6435 auto &FooVal = getFormula(*FooDecl, Env); 6436 EXPECT_TRUE(Env.proves(FooVal)); 6437 }, 6438 {BuiltinOptions{ContextSensitiveOptions{}}}); 6439 } 6440 6441 TEST(TransferTest, ContextSensitiveConstructorDefault) { 6442 std::string Code = R"( 6443 class MyClass { 6444 public: 6445 MyClass() = default; 6446 6447 bool MyField = true; 6448 }; 6449 6450 void target() { 6451 MyClass MyObj; 6452 bool Foo = MyObj.MyField; 6453 // [[p]] 6454 } 6455 )"; 6456 runDataflow( 6457 Code, 6458 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6459 ASTContext &ASTCtx) { 6460 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6461 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6462 6463 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6464 ASSERT_THAT(FooDecl, NotNull()); 6465 6466 auto &FooVal = getFormula(*FooDecl, Env); 6467 EXPECT_TRUE(Env.proves(FooVal)); 6468 }, 6469 {BuiltinOptions{ContextSensitiveOptions{}}}); 6470 } 6471 6472 TEST(TransferTest, ContextSensitiveSelfReferentialClass) { 6473 // Test that the `this` pointer seen in the constructor has the same value 6474 // as the address of the variable the object is constructed into. 6475 std::string Code = R"( 6476 class MyClass { 6477 public: 6478 MyClass() : Self(this) {} 6479 MyClass *Self; 6480 }; 6481 6482 void target() { 6483 MyClass MyObj; 6484 MyClass *SelfPtr = MyObj.Self; 6485 // [[p]] 6486 } 6487 )"; 6488 runDataflow( 6489 Code, 6490 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6491 ASTContext &ASTCtx) { 6492 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6493 6494 const ValueDecl *MyObjDecl = findValueDecl(ASTCtx, "MyObj"); 6495 ASSERT_THAT(MyObjDecl, NotNull()); 6496 6497 const ValueDecl *SelfDecl = findValueDecl(ASTCtx, "SelfPtr"); 6498 ASSERT_THAT(SelfDecl, NotNull()); 6499 6500 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6501 auto &SelfVal = *cast<PointerValue>(Env.getValue(*SelfDecl)); 6502 EXPECT_EQ(Env.getStorageLocation(*MyObjDecl), &SelfVal.getPointeeLoc()); 6503 }, 6504 {BuiltinOptions{ContextSensitiveOptions{}}}); 6505 } 6506 6507 TEST(TransferTest, UnnamedBitfieldInitializer) { 6508 std::string Code = R"( 6509 struct B {}; 6510 struct A { 6511 unsigned a; 6512 unsigned : 4; 6513 unsigned c; 6514 B b; 6515 }; 6516 void target() { 6517 A a = {}; 6518 A test = a; 6519 (void)test.c; 6520 } 6521 )"; 6522 runDataflow( 6523 Code, 6524 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6525 ASTContext &ASTCtx) { 6526 // This doesn't need a body because this test was crashing the framework 6527 // before handling correctly Unnamed bitfields in `InitListExpr`. 6528 }); 6529 } 6530 6531 // Repro for a crash that used to occur with chained short-circuiting logical 6532 // operators. 6533 TEST(TransferTest, ChainedLogicalOps) { 6534 std::string Code = R"( 6535 bool target() { 6536 bool b = true || false || false || false; 6537 // [[p]] 6538 return b; 6539 } 6540 )"; 6541 runDataflow( 6542 Code, 6543 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6544 ASTContext &ASTCtx) { 6545 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6546 auto &B = getValueForDecl<BoolValue>(ASTCtx, Env, "b").formula(); 6547 EXPECT_TRUE(Env.proves(B)); 6548 }); 6549 } 6550 6551 // Repro for a crash that used to occur when we call a `noreturn` function 6552 // within one of the operands of a `&&` or `||` operator. 6553 TEST(TransferTest, NoReturnFunctionInsideShortCircuitedBooleanOp) { 6554 std::string Code = R"( 6555 __attribute__((noreturn)) int doesnt_return(); 6556 bool some_condition(); 6557 void target(bool b1, bool b2) { 6558 // Neither of these should crash. In addition, if we don't terminate the 6559 // program, we know that the operators need to trigger the short-circuit 6560 // logic, so `NoreturnOnRhsOfAnd` will be false and `NoreturnOnRhsOfOr` 6561 // will be true. 6562 bool NoreturnOnRhsOfAnd = b1 && doesnt_return() > 0; 6563 bool NoreturnOnRhsOfOr = b2 || doesnt_return() > 0; 6564 6565 // Calling a `noreturn` function on the LHS of an `&&` or `||` makes the 6566 // entire expression unreachable. So we know that in both of the following 6567 // cases, if `target()` terminates, the `else` branch was taken. 6568 bool NoreturnOnLhsMakesAndUnreachable = false; 6569 if (some_condition()) 6570 doesnt_return() > 0 && some_condition(); 6571 else 6572 NoreturnOnLhsMakesAndUnreachable = true; 6573 6574 bool NoreturnOnLhsMakesOrUnreachable = false; 6575 if (some_condition()) 6576 doesnt_return() > 0 || some_condition(); 6577 else 6578 NoreturnOnLhsMakesOrUnreachable = true; 6579 6580 // [[p]] 6581 } 6582 )"; 6583 runDataflow( 6584 Code, 6585 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6586 ASTContext &ASTCtx) { 6587 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6588 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6589 auto &A = Env.arena(); 6590 6591 // Check that [[p]] is reachable with a non-false flow condition. 6592 EXPECT_FALSE(Env.proves(A.makeLiteral(false))); 6593 6594 auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, "b1").formula(); 6595 EXPECT_TRUE(Env.proves(A.makeNot(B1))); 6596 6597 auto &NoreturnOnRhsOfAnd = 6598 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfAnd").formula(); 6599 EXPECT_TRUE(Env.proves(A.makeNot(NoreturnOnRhsOfAnd))); 6600 6601 auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, "b2").formula(); 6602 EXPECT_TRUE(Env.proves(B2)); 6603 6604 auto &NoreturnOnRhsOfOr = 6605 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfOr") 6606 .formula(); 6607 EXPECT_TRUE(Env.proves(NoreturnOnRhsOfOr)); 6608 6609 auto &NoreturnOnLhsMakesAndUnreachable = getValueForDecl<BoolValue>( 6610 ASTCtx, Env, "NoreturnOnLhsMakesAndUnreachable").formula(); 6611 EXPECT_TRUE(Env.proves(NoreturnOnLhsMakesAndUnreachable)); 6612 6613 auto &NoreturnOnLhsMakesOrUnreachable = getValueForDecl<BoolValue>( 6614 ASTCtx, Env, "NoreturnOnLhsMakesOrUnreachable").formula(); 6615 EXPECT_TRUE(Env.proves(NoreturnOnLhsMakesOrUnreachable)); 6616 }); 6617 } 6618 6619 TEST(TransferTest, NewExpressions) { 6620 std::string Code = R"( 6621 void target() { 6622 int *p = new int(42); 6623 // [[after_new]] 6624 } 6625 )"; 6626 runDataflow( 6627 Code, 6628 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6629 ASTContext &ASTCtx) { 6630 const Environment &Env = 6631 getEnvironmentAtAnnotation(Results, "after_new"); 6632 6633 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p"); 6634 6635 EXPECT_THAT(Env.getValue(P.getPointeeLoc()), NotNull()); 6636 }); 6637 } 6638 6639 TEST(TransferTest, NewExpressions_Structs) { 6640 std::string Code = R"( 6641 struct Inner { 6642 int InnerField; 6643 }; 6644 6645 struct Outer { 6646 Inner OuterField; 6647 }; 6648 6649 void target() { 6650 Outer *p = new Outer; 6651 // Access the fields to make sure the analysis actually generates children 6652 // for them in the `RecordStorageLocation`. 6653 p->OuterField.InnerField; 6654 // [[after_new]] 6655 } 6656 )"; 6657 runDataflow( 6658 Code, 6659 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6660 ASTContext &ASTCtx) { 6661 const Environment &Env = 6662 getEnvironmentAtAnnotation(Results, "after_new"); 6663 6664 const ValueDecl *OuterField = findValueDecl(ASTCtx, "OuterField"); 6665 const ValueDecl *InnerField = findValueDecl(ASTCtx, "InnerField"); 6666 6667 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p"); 6668 6669 auto &OuterLoc = cast<RecordStorageLocation>(P.getPointeeLoc()); 6670 auto &OuterFieldLoc = 6671 *cast<RecordStorageLocation>(OuterLoc.getChild(*OuterField)); 6672 auto &InnerFieldLoc = *OuterFieldLoc.getChild(*InnerField); 6673 6674 EXPECT_THAT(Env.getValue(InnerFieldLoc), NotNull()); 6675 }); 6676 } 6677 6678 TEST(TransferTest, FunctionToPointerDecayHasValue) { 6679 std::string Code = R"( 6680 struct A { static void static_member_func(); }; 6681 void target() { 6682 // To check that we're treating function-to-pointer decay correctly, 6683 // create two pointers, then verify they refer to the same storage 6684 // location. 6685 // We need to do the test this way because even if an initializer (in this 6686 // case, the function-to-pointer decay) does not create a value, we still 6687 // create a value for the variable. 6688 void (*non_member_p1)() = target; 6689 void (*non_member_p2)() = target; 6690 6691 // Do the same thing but for a static member function. 6692 void (*member_p1)() = A::static_member_func; 6693 void (*member_p2)() = A::static_member_func; 6694 // [[p]] 6695 } 6696 )"; 6697 runDataflow( 6698 Code, 6699 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6700 ASTContext &ASTCtx) { 6701 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6702 6703 auto &NonMemberP1 = 6704 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p1"); 6705 auto &NonMemberP2 = 6706 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p2"); 6707 EXPECT_EQ(&NonMemberP1.getPointeeLoc(), &NonMemberP2.getPointeeLoc()); 6708 6709 auto &MemberP1 = 6710 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p1"); 6711 auto &MemberP2 = 6712 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p2"); 6713 EXPECT_EQ(&MemberP1.getPointeeLoc(), &MemberP2.getPointeeLoc()); 6714 }); 6715 } 6716 6717 // Check that a builtin function is not associated with a value. (It's only 6718 // possible to call builtin functions directly, not take their address.) 6719 TEST(TransferTest, BuiltinFunctionModeled) { 6720 std::string Code = R"( 6721 void target() { 6722 __builtin_expect(0, 0); 6723 // [[p]] 6724 } 6725 )"; 6726 runDataflow( 6727 Code, 6728 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6729 ASTContext &ASTCtx) { 6730 using ast_matchers::selectFirst; 6731 using ast_matchers::match; 6732 using ast_matchers::traverse; 6733 using ast_matchers::implicitCastExpr; 6734 using ast_matchers::hasCastKind; 6735 6736 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6737 6738 auto *ImplicitCast = selectFirst<ImplicitCastExpr>( 6739 "implicit_cast", 6740 match(traverse(TK_AsIs, 6741 implicitCastExpr(hasCastKind(CK_BuiltinFnToFnPtr)) 6742 .bind("implicit_cast")), 6743 ASTCtx)); 6744 6745 ASSERT_THAT(ImplicitCast, NotNull()); 6746 EXPECT_THAT(Env.getValue(*ImplicitCast), IsNull()); 6747 }); 6748 } 6749 6750 // Check that a callee of a member operator call is modeled as a `PointerValue`. 6751 // Member operator calls are unusual in that their callee is a pointer that 6752 // stems from a `FunctionToPointerDecay`. In calls to non-operator non-static 6753 // member functions, the callee is a `MemberExpr` (which does not have pointer 6754 // type). 6755 // We want to make sure that we produce a pointer value for the callee in this 6756 // specific scenario and that its storage location is durable (for convergence). 6757 TEST(TransferTest, MemberOperatorCallModelsPointerForCallee) { 6758 std::string Code = R"( 6759 struct S { 6760 bool operator!=(S s); 6761 }; 6762 void target() { 6763 S s; 6764 (void)(s != s); 6765 (void)(s != s); 6766 // [[p]] 6767 } 6768 )"; 6769 runDataflow( 6770 Code, 6771 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6772 ASTContext &ASTCtx) { 6773 using ast_matchers::selectFirst; 6774 using ast_matchers::match; 6775 using ast_matchers::traverse; 6776 using ast_matchers::cxxOperatorCallExpr; 6777 6778 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6779 6780 auto Matches = match( 6781 traverse(TK_AsIs, cxxOperatorCallExpr().bind("call")), ASTCtx); 6782 6783 ASSERT_EQ(Matches.size(), 2UL); 6784 6785 auto *Call1 = Matches[0].getNodeAs<CXXOperatorCallExpr>("call"); 6786 auto *Call2 = Matches[1].getNodeAs<CXXOperatorCallExpr>("call"); 6787 6788 ASSERT_THAT(Call1, NotNull()); 6789 ASSERT_THAT(Call2, NotNull()); 6790 6791 EXPECT_EQ(cast<ImplicitCastExpr>(Call1->getCallee())->getCastKind(), 6792 CK_FunctionToPointerDecay); 6793 EXPECT_EQ(cast<ImplicitCastExpr>(Call2->getCallee())->getCastKind(), 6794 CK_FunctionToPointerDecay); 6795 6796 auto *Ptr1 = cast<PointerValue>(Env.getValue(*Call1->getCallee())); 6797 auto *Ptr2 = cast<PointerValue>(Env.getValue(*Call2->getCallee())); 6798 6799 ASSERT_EQ(&Ptr1->getPointeeLoc(), &Ptr2->getPointeeLoc()); 6800 }); 6801 } 6802 6803 // Check that fields of anonymous records are modeled. 6804 TEST(TransferTest, AnonymousStruct) { 6805 std::string Code = R"( 6806 struct S { 6807 struct { 6808 bool b; 6809 }; 6810 }; 6811 void target() { 6812 S s; 6813 s.b = true; 6814 // [[p]] 6815 } 6816 )"; 6817 runDataflow( 6818 Code, 6819 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6820 ASTContext &ASTCtx) { 6821 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6822 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 6823 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b"); 6824 const IndirectFieldDecl *IndirectField = 6825 findIndirectFieldDecl(ASTCtx, "b"); 6826 6827 auto *S = cast<RecordStorageLocation>(Env.getStorageLocation(*SDecl)); 6828 auto &AnonStruct = *cast<RecordStorageLocation>( 6829 S->getChild(*cast<ValueDecl>(IndirectField->chain().front()))); 6830 6831 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env)); 6832 ASSERT_TRUE(Env.proves(B->formula())); 6833 }); 6834 } 6835 6836 TEST(TransferTest, AnonymousStructWithInitializer) { 6837 std::string Code = R"( 6838 struct target { 6839 target() { 6840 (void)0; 6841 // [[p]] 6842 } 6843 struct { 6844 bool b = true; 6845 }; 6846 }; 6847 )"; 6848 runDataflow( 6849 Code, 6850 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6851 ASTContext &ASTCtx) { 6852 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6853 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b"); 6854 const IndirectFieldDecl *IndirectField = 6855 findIndirectFieldDecl(ASTCtx, "b"); 6856 6857 auto *ThisLoc = 6858 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation()); 6859 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild( 6860 *cast<ValueDecl>(IndirectField->chain().front()))); 6861 6862 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env)); 6863 ASSERT_TRUE(Env.proves(B->formula())); 6864 }); 6865 } 6866 6867 TEST(TransferTest, AnonymousStructWithReferenceField) { 6868 std::string Code = R"( 6869 int global_i = 0; 6870 struct target { 6871 target() { 6872 (void)0; 6873 // [[p]] 6874 } 6875 struct { 6876 int &i = global_i; 6877 }; 6878 }; 6879 )"; 6880 runDataflow( 6881 Code, 6882 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6883 ASTContext &ASTCtx) { 6884 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6885 const ValueDecl *GlobalIDecl = findValueDecl(ASTCtx, "global_i"); 6886 const ValueDecl *IDecl = findValueDecl(ASTCtx, "i"); 6887 const IndirectFieldDecl *IndirectField = 6888 findIndirectFieldDecl(ASTCtx, "i"); 6889 6890 auto *ThisLoc = 6891 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation()); 6892 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild( 6893 *cast<ValueDecl>(IndirectField->chain().front()))); 6894 6895 ASSERT_EQ(AnonStruct.getChild(*IDecl), 6896 Env.getStorageLocation(*GlobalIDecl)); 6897 }); 6898 } 6899 6900 TEST(TransferTest, EvaluateBlockWithUnreachablePreds) { 6901 // This is a crash repro. 6902 // `false` block may not have been processed when we try to evaluate the `||` 6903 // after visiting `true`, because it is not necessary (and therefore the edge 6904 // is marked unreachable). Trying to get the analysis state via 6905 // `getEnvironment` for the subexpression still should not crash. 6906 std::string Code = R"( 6907 int target(int i) { 6908 if ((i < 0 && true) || false) { 6909 return 0; 6910 } 6911 return 0; 6912 } 6913 )"; 6914 runDataflow( 6915 Code, 6916 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6917 ASTContext &ASTCtx) {}); 6918 } 6919 6920 TEST(TransferTest, LambdaCaptureByCopy) { 6921 std::string Code = R"( 6922 void target(int Foo, int Bar) { 6923 [Foo]() { 6924 (void)0; 6925 // [[p]] 6926 }(); 6927 } 6928 )"; 6929 runDataflowOnLambda( 6930 Code, 6931 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6932 ASTContext &ASTCtx) { 6933 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6934 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6935 6936 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6937 ASSERT_THAT(FooDecl, NotNull()); 6938 6939 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6940 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6941 6942 const Value *FooVal = Env.getValue(*FooLoc); 6943 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6944 6945 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6946 ASSERT_THAT(BarDecl, NotNull()); 6947 6948 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6949 EXPECT_THAT(BarLoc, IsNull()); 6950 }); 6951 } 6952 6953 TEST(TransferTest, LambdaCaptureByReference) { 6954 std::string Code = R"( 6955 void target(int Foo, int Bar) { 6956 [&Foo]() { 6957 (void)0; 6958 // [[p]] 6959 }(); 6960 } 6961 )"; 6962 runDataflowOnLambda( 6963 Code, 6964 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6965 ASTContext &ASTCtx) { 6966 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6967 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6968 6969 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6970 ASSERT_THAT(FooDecl, NotNull()); 6971 6972 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6973 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6974 6975 const Value *FooVal = Env.getValue(*FooLoc); 6976 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6977 6978 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6979 ASSERT_THAT(BarDecl, NotNull()); 6980 6981 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6982 EXPECT_THAT(BarLoc, IsNull()); 6983 }); 6984 } 6985 6986 TEST(TransferTest, LambdaCaptureWithInitializer) { 6987 std::string Code = R"( 6988 void target(int Bar) { 6989 [Foo=Bar]() { 6990 (void)0; 6991 // [[p]] 6992 }(); 6993 } 6994 )"; 6995 runDataflowOnLambda( 6996 Code, 6997 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6998 ASTContext &ASTCtx) { 6999 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 7000 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7001 7002 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 7003 ASSERT_THAT(FooDecl, NotNull()); 7004 7005 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 7006 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 7007 7008 const Value *FooVal = Env.getValue(*FooLoc); 7009 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 7010 7011 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 7012 ASSERT_THAT(BarDecl, NotNull()); 7013 7014 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 7015 EXPECT_THAT(BarLoc, IsNull()); 7016 }); 7017 } 7018 7019 TEST(TransferTest, LambdaCaptureByCopyImplicit) { 7020 std::string Code = R"( 7021 void target(int Foo, int Bar) { 7022 [=]() { 7023 Foo; 7024 // [[p]] 7025 }(); 7026 } 7027 )"; 7028 runDataflowOnLambda( 7029 Code, 7030 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7031 ASTContext &ASTCtx) { 7032 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 7033 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7034 7035 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 7036 ASSERT_THAT(FooDecl, NotNull()); 7037 7038 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 7039 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 7040 7041 const Value *FooVal = Env.getValue(*FooLoc); 7042 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 7043 7044 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 7045 ASSERT_THAT(BarDecl, NotNull()); 7046 7047 // There is no storage location for `Bar` because it isn't used in the 7048 // body of the lambda. 7049 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 7050 EXPECT_THAT(BarLoc, IsNull()); 7051 }); 7052 } 7053 7054 TEST(TransferTest, LambdaCaptureByReferenceImplicit) { 7055 std::string Code = R"( 7056 void target(int Foo, int Bar) { 7057 [&]() { 7058 Foo; 7059 // [[p]] 7060 }(); 7061 } 7062 )"; 7063 runDataflowOnLambda( 7064 Code, 7065 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7066 ASTContext &ASTCtx) { 7067 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 7068 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7069 7070 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 7071 ASSERT_THAT(FooDecl, NotNull()); 7072 7073 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 7074 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 7075 7076 const Value *FooVal = Env.getValue(*FooLoc); 7077 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 7078 7079 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 7080 ASSERT_THAT(BarDecl, NotNull()); 7081 7082 // There is no storage location for `Bar` because it isn't used in the 7083 // body of the lambda. 7084 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 7085 EXPECT_THAT(BarLoc, IsNull()); 7086 }); 7087 } 7088 7089 TEST(TransferTest, LambdaCaptureThis) { 7090 std::string Code = R"( 7091 struct Bar { 7092 int Foo; 7093 7094 void target() { 7095 [this]() { 7096 Foo; 7097 // [[p]] 7098 }(); 7099 } 7100 }; 7101 )"; 7102 runDataflowOnLambda( 7103 Code, 7104 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7105 ASTContext &ASTCtx) { 7106 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 7107 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7108 7109 const RecordStorageLocation *ThisPointeeLoc = 7110 Env.getThisPointeeStorageLocation(); 7111 ASSERT_THAT(ThisPointeeLoc, NotNull()); 7112 7113 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 7114 ASSERT_THAT(FooDecl, NotNull()); 7115 7116 const StorageLocation *FooLoc = ThisPointeeLoc->getChild(*FooDecl); 7117 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 7118 7119 const Value *FooVal = Env.getValue(*FooLoc); 7120 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 7121 }); 7122 } 7123 7124 // This test verifies correct modeling of a relational dependency that goes 7125 // through unmodeled functions (the simple `cond()` in this case). 7126 TEST(TransferTest, ConditionalRelation) { 7127 std::string Code = R"( 7128 bool cond(); 7129 void target() { 7130 bool a = true; 7131 bool b = true; 7132 if (cond()) { 7133 a = false; 7134 if (cond()) { 7135 b = false; 7136 } 7137 } 7138 (void)0; 7139 // [[p]] 7140 } 7141 )"; 7142 runDataflow( 7143 Code, 7144 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7145 ASTContext &ASTCtx) { 7146 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7147 auto &A = Env.arena(); 7148 auto &VarA = getValueForDecl<BoolValue>(ASTCtx, Env, "a").formula(); 7149 auto &VarB = getValueForDecl<BoolValue>(ASTCtx, Env, "b").formula(); 7150 7151 EXPECT_FALSE(Env.allows(A.makeAnd(VarA, A.makeNot(VarB)))); 7152 }); 7153 } 7154 7155 } // namespace 7156