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