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