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