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 // The field of the base class should already have been initialized with 1586 // a value by the base constructor. 1587 EXPECT_NE(getFieldValue(Env.getThisPointeeStorageLocation(), "BaseVal", 1588 ASTCtx, Env), 1589 nullptr); 1590 EXPECT_EQ(getFieldValue(Env.getThisPointeeStorageLocation(), "Val", 1591 ASTCtx, Env), 1592 nullptr); 1593 }); 1594 } 1595 1596 TEST(TransferTest, StructModeledFieldsWithAccessor) { 1597 std::string Code = R"( 1598 class S { 1599 int *Ptr; 1600 int *PtrNonConst; 1601 int Int; 1602 int IntWithInc; 1603 int IntNotAccessed; 1604 int IntRef; 1605 public: 1606 int *getPtr() const { return Ptr; } 1607 int *getPtrNonConst() { return PtrNonConst; } 1608 int getInt(int i) const { return Int; } 1609 int getWithInc(int i) { IntWithInc += i; return IntWithInc; } 1610 int getIntNotAccessed() const { return IntNotAccessed; } 1611 int getIntNoDefinition() const; 1612 int &getIntRef() { return IntRef; } 1613 void returnVoid() const { return; } 1614 }; 1615 1616 void target() { 1617 S s; 1618 int *p1 = s.getPtr(); 1619 int *p2 = s.getPtrNonConst(); 1620 int i1 = s.getInt(1); 1621 int i2 = s.getWithInc(1); 1622 int i3 = s.getIntNoDefinition(); 1623 int &iref = s.getIntRef(); 1624 1625 // Regression test: Don't crash on an indirect call (which doesn't have 1626 // an associated `CXXMethodDecl`). 1627 auto ptr_to_member_fn = &S::getPtr; 1628 p1 = (s.*ptr_to_member_fn)(); 1629 1630 // Regression test: Don't crash on a return statement without a value. 1631 s.returnVoid(); 1632 // [[p]] 1633 } 1634 )"; 1635 runDataflow( 1636 Code, 1637 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1638 ASTContext &ASTCtx) { 1639 const Environment &Env = 1640 getEnvironmentAtAnnotation(Results, "p"); 1641 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"); 1642 std::vector<const ValueDecl*> Fields; 1643 for (auto [Field, _] : SLoc.children()) 1644 Fields.push_back(Field); 1645 // Only the fields that have simple accessor methods (that have a 1646 // single statement body that returns the member variable) should be 1647 // modeled. 1648 ASSERT_THAT(Fields, UnorderedElementsAre( 1649 findValueDecl(ASTCtx, "Ptr"), findValueDecl(ASTCtx, "PtrNonConst"), 1650 findValueDecl(ASTCtx, "Int"), findValueDecl(ASTCtx, "IntRef"))); 1651 }); 1652 } 1653 1654 TEST(TransferTest, StructModeledFieldsWithComplicatedInheritance) { 1655 std::string Code = R"( 1656 struct Base1 { 1657 int base1_1; 1658 int base1_2; 1659 }; 1660 struct Intermediate : Base1 { 1661 int intermediate_1; 1662 int intermediate_2; 1663 }; 1664 struct Base2 { 1665 int base2_1; 1666 int base2_2; 1667 }; 1668 struct MostDerived : public Intermediate, Base2 { 1669 int most_derived_1; 1670 int most_derived_2; 1671 }; 1672 1673 void target() { 1674 MostDerived MD; 1675 MD.base1_2 = 1; 1676 MD.intermediate_2 = 1; 1677 MD.base2_2 = 1; 1678 MD.most_derived_2 = 1; 1679 // [[p]] 1680 } 1681 )"; 1682 runDataflow( 1683 Code, 1684 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1685 ASTContext &ASTCtx) { 1686 const Environment &Env = 1687 getEnvironmentAtAnnotation(Results, "p"); 1688 1689 // Only the accessed fields should exist in the model. 1690 auto &MDLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "MD"); 1691 std::vector<const ValueDecl*> Fields; 1692 for (auto [Field, _] : MDLoc.children()) 1693 Fields.push_back(Field); 1694 ASSERT_THAT(Fields, UnorderedElementsAre( 1695 findValueDecl(ASTCtx, "base1_2"), 1696 findValueDecl(ASTCtx, "intermediate_2"), 1697 findValueDecl(ASTCtx, "base2_2"), 1698 findValueDecl(ASTCtx, "most_derived_2"))); 1699 }); 1700 } 1701 1702 TEST(TransferTest, StructInitializerListWithComplicatedInheritance) { 1703 std::string Code = R"( 1704 struct Base1 { 1705 int base1; 1706 }; 1707 struct Intermediate : Base1 { 1708 int intermediate; 1709 }; 1710 struct Base2 { 1711 int base2; 1712 }; 1713 struct MostDerived : public Intermediate, Base2 { 1714 int most_derived; 1715 }; 1716 1717 void target() { 1718 MostDerived MD = {}; 1719 // [[p]] 1720 } 1721 )"; 1722 runDataflow( 1723 Code, 1724 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1725 ASTContext &ASTCtx) { 1726 const Environment &Env = 1727 getEnvironmentAtAnnotation(Results, "p"); 1728 1729 // When a struct is initialized with a initializer list, all the 1730 // fields are considered "accessed", and therefore do exist. 1731 auto &MD = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "MD"); 1732 ASSERT_THAT(cast<IntegerValue>( 1733 getFieldValue(&MD, *findValueDecl(ASTCtx, "base1"), Env)), 1734 NotNull()); 1735 ASSERT_THAT(cast<IntegerValue>( 1736 getFieldValue(&MD, *findValueDecl(ASTCtx, "intermediate"), Env)), 1737 NotNull()); 1738 ASSERT_THAT(cast<IntegerValue>( 1739 getFieldValue(&MD, *findValueDecl(ASTCtx, "base2"), Env)), 1740 NotNull()); 1741 ASSERT_THAT(cast<IntegerValue>( 1742 getFieldValue(&MD, *findValueDecl(ASTCtx, "most_derived"), Env)), 1743 NotNull()); 1744 }); 1745 } 1746 1747 TEST(TransferTest, ReferenceMember) { 1748 std::string Code = R"( 1749 struct A { 1750 int &Bar; 1751 }; 1752 1753 void target(A Foo) { 1754 int Baz = Foo.Bar; 1755 // [[p]] 1756 } 1757 )"; 1758 runDataflow( 1759 Code, 1760 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1761 ASTContext &ASTCtx) { 1762 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1763 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1764 1765 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1766 ASSERT_THAT(FooDecl, NotNull()); 1767 1768 ASSERT_TRUE(FooDecl->getType()->isStructureType()); 1769 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 1770 1771 FieldDecl *BarDecl = nullptr; 1772 for (FieldDecl *Field : FooFields) { 1773 if (Field->getNameAsString() == "Bar") { 1774 BarDecl = Field; 1775 } else { 1776 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1777 } 1778 } 1779 ASSERT_THAT(BarDecl, NotNull()); 1780 1781 const auto *FooLoc = 1782 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 1783 const auto *BarReferentVal = 1784 cast<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)); 1785 1786 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 1787 ASSERT_THAT(BazDecl, NotNull()); 1788 1789 EXPECT_EQ(Env.getValue(*BazDecl), BarReferentVal); 1790 }); 1791 } 1792 1793 TEST(TransferTest, StructThisMember) { 1794 std::string Code = R"( 1795 struct A { 1796 int Bar; 1797 1798 struct B { 1799 int Baz; 1800 }; 1801 1802 B Qux; 1803 1804 void target() { 1805 int Foo = Bar; 1806 int Quux = Qux.Baz; 1807 // [[p]] 1808 } 1809 }; 1810 )"; 1811 runDataflow( 1812 Code, 1813 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1814 ASTContext &ASTCtx) { 1815 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1816 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1817 1818 const auto *ThisLoc = Env.getThisPointeeStorageLocation(); 1819 ASSERT_THAT(ThisLoc, NotNull()); 1820 1821 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1822 ASSERT_THAT(BarDecl, NotNull()); 1823 1824 const auto *BarLoc = 1825 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl)); 1826 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 1827 1828 const Value *BarVal = Env.getValue(*BarLoc); 1829 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 1830 1831 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1832 ASSERT_THAT(FooDecl, NotNull()); 1833 EXPECT_EQ(Env.getValue(*FooDecl), BarVal); 1834 1835 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 1836 ASSERT_THAT(QuxDecl, NotNull()); 1837 1838 ASSERT_TRUE(QuxDecl->getType()->isStructureType()); 1839 auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields(); 1840 1841 FieldDecl *BazDecl = nullptr; 1842 for (FieldDecl *Field : QuxFields) { 1843 if (Field->getNameAsString() == "Baz") { 1844 BazDecl = Field; 1845 } else { 1846 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1847 } 1848 } 1849 ASSERT_THAT(BazDecl, NotNull()); 1850 1851 const auto *QuxLoc = 1852 cast<RecordStorageLocation>(ThisLoc->getChild(*QuxDecl)); 1853 EXPECT_THAT(dyn_cast<RecordValue>(Env.getValue(*QuxLoc)), NotNull()); 1854 1855 const auto *BazVal = 1856 cast<IntegerValue>(getFieldValue(QuxLoc, *BazDecl, Env)); 1857 1858 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 1859 ASSERT_THAT(QuuxDecl, NotNull()); 1860 EXPECT_EQ(Env.getValue(*QuuxDecl), BazVal); 1861 }); 1862 } 1863 1864 TEST(TransferTest, ClassThisMember) { 1865 std::string Code = R"( 1866 class A { 1867 int Bar; 1868 1869 class B { 1870 public: 1871 int Baz; 1872 }; 1873 1874 B Qux; 1875 1876 void target() { 1877 int Foo = Bar; 1878 int Quux = Qux.Baz; 1879 // [[p]] 1880 } 1881 }; 1882 )"; 1883 runDataflow( 1884 Code, 1885 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1886 ASTContext &ASTCtx) { 1887 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1888 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1889 1890 const auto *ThisLoc = Env.getThisPointeeStorageLocation(); 1891 1892 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1893 ASSERT_THAT(BarDecl, NotNull()); 1894 1895 const auto *BarLoc = 1896 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl)); 1897 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 1898 1899 const Value *BarVal = Env.getValue(*BarLoc); 1900 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 1901 1902 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1903 ASSERT_THAT(FooDecl, NotNull()); 1904 EXPECT_EQ(Env.getValue(*FooDecl), BarVal); 1905 1906 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 1907 ASSERT_THAT(QuxDecl, NotNull()); 1908 1909 ASSERT_TRUE(QuxDecl->getType()->isClassType()); 1910 auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields(); 1911 1912 FieldDecl *BazDecl = nullptr; 1913 for (FieldDecl *Field : QuxFields) { 1914 if (Field->getNameAsString() == "Baz") { 1915 BazDecl = Field; 1916 } else { 1917 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1918 } 1919 } 1920 ASSERT_THAT(BazDecl, NotNull()); 1921 1922 const auto *QuxLoc = 1923 cast<RecordStorageLocation>(ThisLoc->getChild(*QuxDecl)); 1924 EXPECT_THAT(dyn_cast<RecordValue>(Env.getValue(*QuxLoc)), NotNull()); 1925 1926 const auto *BazVal = 1927 cast<IntegerValue>(getFieldValue(QuxLoc, *BazDecl, Env)); 1928 1929 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 1930 ASSERT_THAT(QuuxDecl, NotNull()); 1931 EXPECT_EQ(Env.getValue(*QuuxDecl), BazVal); 1932 }); 1933 } 1934 1935 TEST(TransferTest, UnionThisMember) { 1936 std::string Code = R"( 1937 union A { 1938 int Foo; 1939 int Bar; 1940 1941 void target() { 1942 A a; 1943 // Mention the fields to ensure they're included in the analysis. 1944 (void)a.Foo; 1945 (void)a.Bar; 1946 // [[p]] 1947 } 1948 }; 1949 )"; 1950 runDataflow( 1951 Code, 1952 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1953 ASTContext &ASTCtx) { 1954 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1955 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1956 1957 const auto *ThisLoc = Env.getThisPointeeStorageLocation(); 1958 ASSERT_THAT(ThisLoc, NotNull()); 1959 1960 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1961 ASSERT_THAT(FooDecl, NotNull()); 1962 1963 const auto *FooLoc = 1964 cast<ScalarStorageLocation>(ThisLoc->getChild(*FooDecl)); 1965 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 1966 1967 const Value *FooVal = Env.getValue(*FooLoc); 1968 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 1969 1970 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1971 ASSERT_THAT(BarDecl, NotNull()); 1972 1973 const auto *BarLoc = 1974 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl)); 1975 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 1976 1977 const Value *BarVal = Env.getValue(*BarLoc); 1978 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 1979 }); 1980 } 1981 1982 TEST(TransferTest, StructThisInLambda) { 1983 std::string ThisCaptureCode = R"( 1984 struct A { 1985 void frob() { 1986 [this]() { 1987 int Foo = Bar; 1988 // [[p1]] 1989 }(); 1990 } 1991 1992 int Bar; 1993 }; 1994 )"; 1995 runDataflow( 1996 ThisCaptureCode, 1997 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1998 ASTContext &ASTCtx) { 1999 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1")); 2000 const Environment &Env = getEnvironmentAtAnnotation(Results, "p1"); 2001 2002 const auto *ThisLoc = Env.getThisPointeeStorageLocation(); 2003 ASSERT_THAT(ThisLoc, NotNull()); 2004 2005 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2006 ASSERT_THAT(BarDecl, NotNull()); 2007 2008 const auto *BarLoc = 2009 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl)); 2010 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 2011 2012 const Value *BarVal = Env.getValue(*BarLoc); 2013 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 2014 2015 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2016 ASSERT_THAT(FooDecl, NotNull()); 2017 EXPECT_EQ(Env.getValue(*FooDecl), BarVal); 2018 }, 2019 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()"); 2020 2021 std::string RefCaptureDefaultCode = R"( 2022 struct A { 2023 void frob() { 2024 [&]() { 2025 int Foo = Bar; 2026 // [[p2]] 2027 }(); 2028 } 2029 2030 int Bar; 2031 }; 2032 )"; 2033 runDataflow( 2034 RefCaptureDefaultCode, 2035 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2036 ASTContext &ASTCtx) { 2037 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p2")); 2038 const Environment &Env = getEnvironmentAtAnnotation(Results, "p2"); 2039 2040 const auto *ThisLoc = Env.getThisPointeeStorageLocation(); 2041 ASSERT_THAT(ThisLoc, NotNull()); 2042 2043 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2044 ASSERT_THAT(BarDecl, NotNull()); 2045 2046 const auto *BarLoc = 2047 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl)); 2048 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 2049 2050 const Value *BarVal = Env.getValue(*BarLoc); 2051 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 2052 2053 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2054 ASSERT_THAT(FooDecl, NotNull()); 2055 EXPECT_EQ(Env.getValue(*FooDecl), BarVal); 2056 }, 2057 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()"); 2058 2059 std::string FreeFunctionLambdaCode = R"( 2060 void foo() { 2061 int Bar; 2062 [&]() { 2063 int Foo = Bar; 2064 // [[p3]] 2065 }(); 2066 } 2067 )"; 2068 runDataflow( 2069 FreeFunctionLambdaCode, 2070 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2071 ASTContext &ASTCtx) { 2072 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p3")); 2073 const Environment &Env = getEnvironmentAtAnnotation(Results, "p3"); 2074 2075 EXPECT_THAT(Env.getThisPointeeStorageLocation(), IsNull()); 2076 }, 2077 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()"); 2078 } 2079 2080 TEST(TransferTest, ConstructorInitializer) { 2081 std::string Code = R"( 2082 struct target { 2083 int Bar; 2084 2085 target(int Foo) : Bar(Foo) { 2086 int Qux = Bar; 2087 // [[p]] 2088 } 2089 }; 2090 )"; 2091 runDataflow( 2092 Code, 2093 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2094 ASTContext &ASTCtx) { 2095 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2096 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2097 2098 const auto *ThisLoc = Env.getThisPointeeStorageLocation(); 2099 ASSERT_THAT(ThisLoc, NotNull()); 2100 2101 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2102 ASSERT_THAT(FooDecl, NotNull()); 2103 2104 const auto *FooVal = cast<IntegerValue>(Env.getValue(*FooDecl)); 2105 2106 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 2107 ASSERT_THAT(QuxDecl, NotNull()); 2108 EXPECT_EQ(Env.getValue(*QuxDecl), FooVal); 2109 }); 2110 } 2111 2112 TEST(TransferTest, DefaultInitializer) { 2113 std::string Code = R"( 2114 struct target { 2115 int Bar; 2116 int Baz = Bar; 2117 2118 target(int Foo) : Bar(Foo) { 2119 int Qux = Baz; 2120 // [[p]] 2121 } 2122 }; 2123 )"; 2124 runDataflow( 2125 Code, 2126 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2127 ASTContext &ASTCtx) { 2128 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2129 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2130 2131 const auto *ThisLoc = Env.getThisPointeeStorageLocation(); 2132 ASSERT_THAT(ThisLoc, NotNull()); 2133 2134 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2135 ASSERT_THAT(FooDecl, NotNull()); 2136 2137 const auto *FooVal = cast<IntegerValue>(Env.getValue(*FooDecl)); 2138 2139 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 2140 ASSERT_THAT(QuxDecl, NotNull()); 2141 EXPECT_EQ(Env.getValue(*QuxDecl), FooVal); 2142 }); 2143 } 2144 2145 TEST(TransferTest, DefaultInitializerReference) { 2146 std::string Code = R"( 2147 struct target { 2148 int &Bar; 2149 int &Baz = Bar; 2150 2151 target(int &Foo) : Bar(Foo) { 2152 int &Qux = Baz; 2153 // [[p]] 2154 } 2155 }; 2156 )"; 2157 runDataflow( 2158 Code, 2159 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2160 ASTContext &ASTCtx) { 2161 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2162 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2163 2164 const auto *ThisLoc = Env.getThisPointeeStorageLocation(); 2165 ASSERT_THAT(ThisLoc, NotNull()); 2166 2167 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2168 ASSERT_THAT(FooDecl, NotNull()); 2169 2170 const auto *FooLoc = Env.getStorageLocation(*FooDecl); 2171 2172 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 2173 ASSERT_THAT(QuxDecl, NotNull()); 2174 2175 const auto *QuxLoc = Env.getStorageLocation(*QuxDecl); 2176 EXPECT_EQ(QuxLoc, FooLoc); 2177 }); 2178 } 2179 2180 TEST(TransferTest, TemporaryObject) { 2181 std::string Code = R"( 2182 struct A { 2183 int Bar; 2184 }; 2185 2186 void target() { 2187 A Foo = A(); 2188 (void)Foo.Bar; 2189 // [[p]] 2190 } 2191 )"; 2192 runDataflow( 2193 Code, 2194 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2195 ASTContext &ASTCtx) { 2196 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2197 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2198 2199 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2200 ASSERT_THAT(FooDecl, NotNull()); 2201 2202 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2203 ASSERT_THAT(BarDecl, NotNull()); 2204 2205 const auto *FooLoc = 2206 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2207 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env))); 2208 }); 2209 } 2210 2211 TEST(TransferTest, ElidableConstructor) { 2212 // This test is effectively the same as TransferTest.TemporaryObject, but 2213 // the code is compiled as C++14. 2214 std::string Code = R"( 2215 struct A { 2216 int Bar; 2217 }; 2218 2219 void target() { 2220 A Foo = A(); 2221 (void)Foo.Bar; 2222 // [[p]] 2223 } 2224 )"; 2225 runDataflow( 2226 Code, 2227 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2228 ASTContext &ASTCtx) { 2229 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2230 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2231 2232 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2233 ASSERT_THAT(FooDecl, NotNull()); 2234 2235 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2236 ASSERT_THAT(BarDecl, NotNull()); 2237 2238 const auto *FooLoc = 2239 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2240 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env))); 2241 }, 2242 LangStandard::lang_cxx14); 2243 } 2244 2245 TEST(TransferTest, AssignmentOperator) { 2246 std::string Code = R"( 2247 struct A { 2248 int Baz; 2249 }; 2250 2251 void target() { 2252 A Foo = { 1 }; 2253 A Bar = { 2 }; 2254 // [[p1]] 2255 Foo = Bar; 2256 // [[p2]] 2257 Foo.Baz = 3; 2258 // [[p3]] 2259 } 2260 )"; 2261 runDataflow( 2262 Code, 2263 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2264 ASTContext &ASTCtx) { 2265 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2266 ASSERT_THAT(FooDecl, NotNull()); 2267 2268 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2269 ASSERT_THAT(BarDecl, NotNull()); 2270 2271 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2272 ASSERT_THAT(BazDecl, NotNull()); 2273 2274 // Before copy assignment. 2275 { 2276 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 2277 2278 const auto *FooLoc1 = 2279 cast<RecordStorageLocation>(Env1.getStorageLocation(*FooDecl)); 2280 const auto *BarLoc1 = 2281 cast<RecordStorageLocation>(Env1.getStorageLocation(*BarDecl)); 2282 EXPECT_FALSE(recordsEqual(*FooLoc1, *BarLoc1, Env1)); 2283 2284 const auto *FooBazVal1 = 2285 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env1)); 2286 const auto *BarBazVal1 = 2287 cast<IntegerValue>(getFieldValue(BarLoc1, *BazDecl, Env1)); 2288 EXPECT_NE(FooBazVal1, BarBazVal1); 2289 } 2290 2291 // After copy assignment. 2292 { 2293 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 2294 2295 const auto *FooLoc2 = 2296 cast<RecordStorageLocation>(Env2.getStorageLocation(*FooDecl)); 2297 const auto *BarLoc2 = 2298 cast<RecordStorageLocation>(Env2.getStorageLocation(*BarDecl)); 2299 2300 const auto *FooVal2 = cast<RecordValue>(Env2.getValue(*FooLoc2)); 2301 const auto *BarVal2 = cast<RecordValue>(Env2.getValue(*BarLoc2)); 2302 EXPECT_NE(FooVal2, BarVal2); 2303 2304 EXPECT_TRUE(recordsEqual(*FooLoc2, *BarLoc2, Env2)); 2305 2306 const auto *FooBazVal2 = 2307 cast<IntegerValue>(getFieldValue(FooLoc2, *BazDecl, Env2)); 2308 const auto *BarBazVal2 = 2309 cast<IntegerValue>(getFieldValue(BarLoc2, *BazDecl, Env2)); 2310 EXPECT_EQ(FooBazVal2, BarBazVal2); 2311 } 2312 2313 // After value update. 2314 { 2315 const Environment &Env3 = getEnvironmentAtAnnotation(Results, "p3"); 2316 2317 const auto *FooLoc3 = 2318 cast<RecordStorageLocation>(Env3.getStorageLocation(*FooDecl)); 2319 const auto *BarLoc3 = 2320 cast<RecordStorageLocation>(Env3.getStorageLocation(*BarDecl)); 2321 EXPECT_FALSE(recordsEqual(*FooLoc3, *BarLoc3, Env3)); 2322 2323 const auto *FooBazVal3 = 2324 cast<IntegerValue>(getFieldValue(FooLoc3, *BazDecl, Env3)); 2325 const auto *BarBazVal3 = 2326 cast<IntegerValue>(getFieldValue(BarLoc3, *BazDecl, Env3)); 2327 EXPECT_NE(FooBazVal3, BarBazVal3); 2328 } 2329 }); 2330 } 2331 2332 // It's legal for the assignment operator to take its source parameter by value. 2333 // Check that we handle this correctly. (This is a repro -- we used to 2334 // assert-fail on this.) 2335 TEST(TransferTest, AssignmentOperator_ArgByValue) { 2336 std::string Code = R"( 2337 struct A { 2338 int Baz; 2339 A &operator=(A); 2340 }; 2341 2342 void target() { 2343 A Foo = { 1 }; 2344 A Bar = { 2 }; 2345 Foo = Bar; 2346 // [[p]] 2347 } 2348 )"; 2349 runDataflow( 2350 Code, 2351 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2352 ASTContext &ASTCtx) { 2353 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2354 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2355 2356 const auto &FooLoc = 2357 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo"); 2358 const auto &BarLoc = 2359 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar"); 2360 2361 const auto *FooBazVal = 2362 cast<IntegerValue>(getFieldValue(&FooLoc, *BazDecl, Env)); 2363 const auto *BarBazVal = 2364 cast<IntegerValue>(getFieldValue(&BarLoc, *BazDecl, Env)); 2365 EXPECT_EQ(FooBazVal, BarBazVal); 2366 }); 2367 } 2368 2369 TEST(TransferTest, AssignmentOperatorFromBase) { 2370 std::string Code = R"( 2371 struct Base { 2372 int base; 2373 }; 2374 struct Derived : public Base { 2375 using Base::operator=; 2376 int derived; 2377 }; 2378 void target(Base B, Derived D) { 2379 D.base = 1; 2380 D.derived = 1; 2381 // [[before]] 2382 D = B; 2383 // [[after]] 2384 } 2385 )"; 2386 runDataflow( 2387 Code, 2388 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2389 ASTContext &ASTCtx) { 2390 const Environment &EnvBefore = 2391 getEnvironmentAtAnnotation(Results, "before"); 2392 const Environment &EnvAfter = 2393 getEnvironmentAtAnnotation(Results, "after"); 2394 2395 auto &BLoc = 2396 getLocForDecl<RecordStorageLocation>(ASTCtx, EnvBefore, "B"); 2397 auto &DLoc = 2398 getLocForDecl<RecordStorageLocation>(ASTCtx, EnvBefore, "D"); 2399 2400 EXPECT_NE(getFieldValue(&BLoc, "base", ASTCtx, EnvBefore), 2401 getFieldValue(&DLoc, "base", ASTCtx, EnvBefore)); 2402 EXPECT_EQ(getFieldValue(&BLoc, "base", ASTCtx, EnvAfter), 2403 getFieldValue(&DLoc, "base", ASTCtx, EnvAfter)); 2404 2405 EXPECT_EQ(getFieldValue(&DLoc, "derived", ASTCtx, EnvBefore), 2406 getFieldValue(&DLoc, "derived", ASTCtx, EnvAfter)); 2407 }); 2408 } 2409 2410 TEST(TransferTest, AssignmentOperatorFromCallResult) { 2411 std::string Code = R"( 2412 struct A {}; 2413 A ReturnA(); 2414 2415 void target() { 2416 A MyA; 2417 MyA = ReturnA(); 2418 } 2419 )"; 2420 runDataflow( 2421 Code, 2422 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2423 ASTContext &ASTCtx) { 2424 // As of this writing, we don't produce a `Value` for the call 2425 // `ReturnA()`. The only condition we're testing for is that the 2426 // analysis should not crash in this case. 2427 }); 2428 } 2429 2430 TEST(TransferTest, AssignmentOperatorWithInitAndInheritance) { 2431 // This is a crash repro. 2432 std::string Code = R"( 2433 struct B { int Foo; }; 2434 struct S : public B {}; 2435 void target() { 2436 S S1 = { 1 }; 2437 S S2; 2438 S S3; 2439 S1 = S2; // Only Dst has InitListExpr. 2440 S3 = S1; // Only Src has InitListExpr. 2441 // [[p]] 2442 } 2443 )"; 2444 runDataflow( 2445 Code, 2446 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2447 ASTContext &ASTCtx) {}); 2448 } 2449 2450 TEST(TransferTest, AssignmentOperatorReturnsVoid) { 2451 // This is a crash repro. 2452 std::string Code = R"( 2453 struct S { 2454 void operator=(S&& other); 2455 }; 2456 void target() { 2457 S s; 2458 s = S(); 2459 // [[p]] 2460 } 2461 )"; 2462 runDataflow( 2463 Code, 2464 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2465 ASTContext &ASTCtx) {}); 2466 } 2467 2468 TEST(TransferTest, AssignmentOperatorReturnsByValue) { 2469 // This is a crash repro. 2470 std::string Code = R"( 2471 struct S { 2472 S operator=(S&& other); 2473 }; 2474 void target() { 2475 S s; 2476 s = S(); 2477 // [[p]] 2478 } 2479 )"; 2480 runDataflow( 2481 Code, 2482 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2483 ASTContext &ASTCtx) {}); 2484 } 2485 2486 TEST(TransferTest, InitListExprAsXValue) { 2487 // This is a crash repro. 2488 std::string Code = R"( 2489 void target() { 2490 bool&& Foo{false}; 2491 // [[p]] 2492 } 2493 )"; 2494 runDataflow( 2495 Code, 2496 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2497 ASTContext &ASTCtx) { 2498 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2499 const auto &FooVal = getValueForDecl<BoolValue>(ASTCtx, Env, "Foo"); 2500 ASSERT_TRUE(FooVal.formula().isLiteral(false)); 2501 }); 2502 } 2503 2504 TEST(TransferTest, ArrayInitListExprOneRecordElement) { 2505 // This is a crash repro. 2506 std::string Code = R"cc( 2507 struct S {}; 2508 2509 void target() { S foo[] = {S()}; } 2510 )cc"; 2511 runDataflow( 2512 Code, 2513 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2514 ASTContext &ASTCtx) { 2515 // Just verify that it doesn't crash. 2516 }); 2517 } 2518 2519 TEST(TransferTest, InitListExprAsUnion) { 2520 // This is a crash repro. 2521 std::string Code = R"cc( 2522 class target { 2523 union { 2524 int *a; 2525 bool *b; 2526 } F; 2527 2528 public: 2529 constexpr target() : F{nullptr} { 2530 int *null = nullptr; 2531 F.b; // Make sure we reference 'b' so it is modeled. 2532 // [[p]] 2533 } 2534 }; 2535 )cc"; 2536 runDataflow( 2537 Code, 2538 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2539 ASTContext &ASTCtx) { 2540 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2541 2542 auto &FLoc = getFieldLoc<RecordStorageLocation>( 2543 *Env.getThisPointeeStorageLocation(), "F", ASTCtx); 2544 auto *AVal = cast<PointerValue>(getFieldValue(&FLoc, "a", ASTCtx, Env)); 2545 EXPECT_EQ(AVal, &getValueForDecl<PointerValue>(ASTCtx, Env, "null")); 2546 EXPECT_EQ(getFieldValue(&FLoc, "b", ASTCtx, Env), nullptr); 2547 }); 2548 } 2549 2550 TEST(TransferTest, EmptyInitListExprForUnion) { 2551 // This is a crash repro. 2552 std::string Code = R"cc( 2553 class target { 2554 union { 2555 int *a; 2556 bool *b; 2557 } F; 2558 2559 public: 2560 // Empty initializer list means that `F` is aggregate-initialized. 2561 // For a union, this has the effect that the first member of the union 2562 // is copy-initialized from an empty initializer list; in this specific 2563 // case, this has the effect of initializing `a` with null. 2564 constexpr target() : F{} { 2565 int *null = nullptr; 2566 F.b; // Make sure we reference 'b' so it is modeled. 2567 // [[p]] 2568 } 2569 }; 2570 )cc"; 2571 runDataflow( 2572 Code, 2573 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2574 ASTContext &ASTCtx) { 2575 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2576 2577 auto &FLoc = getFieldLoc<RecordStorageLocation>( 2578 *Env.getThisPointeeStorageLocation(), "F", ASTCtx); 2579 auto *AVal = cast<PointerValue>(getFieldValue(&FLoc, "a", ASTCtx, Env)); 2580 EXPECT_EQ(AVal, &getValueForDecl<PointerValue>(ASTCtx, Env, "null")); 2581 EXPECT_EQ(getFieldValue(&FLoc, "b", ASTCtx, Env), nullptr); 2582 }); 2583 } 2584 2585 TEST(TransferTest, EmptyInitListExprForStruct) { 2586 std::string Code = R"cc( 2587 class target { 2588 struct { 2589 int *a; 2590 bool *b; 2591 } F; 2592 2593 public: 2594 constexpr target() : F{} { 2595 int *NullIntPtr = nullptr; 2596 bool *NullBoolPtr = nullptr; 2597 // [[p]] 2598 } 2599 }; 2600 )cc"; 2601 runDataflow( 2602 Code, 2603 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2604 ASTContext &ASTCtx) { 2605 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2606 2607 auto &FLoc = getFieldLoc<RecordStorageLocation>( 2608 *Env.getThisPointeeStorageLocation(), "F", ASTCtx); 2609 auto *AVal = cast<PointerValue>(getFieldValue(&FLoc, "a", ASTCtx, Env)); 2610 EXPECT_EQ(AVal, 2611 &getValueForDecl<PointerValue>(ASTCtx, Env, "NullIntPtr")); 2612 auto *BVal = cast<PointerValue>(getFieldValue(&FLoc, "b", ASTCtx, Env)); 2613 EXPECT_EQ(BVal, 2614 &getValueForDecl<PointerValue>(ASTCtx, Env, "NullBoolPtr")); 2615 }); 2616 } 2617 2618 TEST(TransferTest, CopyConstructor) { 2619 std::string Code = R"( 2620 struct A { 2621 int Baz; 2622 }; 2623 2624 void target() { 2625 A Foo = { 1 }; 2626 A Bar = Foo; 2627 // [[after_copy]] 2628 Foo.Baz = 2; 2629 // [[after_update]] 2630 } 2631 )"; 2632 runDataflow( 2633 Code, 2634 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2635 ASTContext &ASTCtx) { 2636 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2637 ASSERT_THAT(FooDecl, NotNull()); 2638 2639 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2640 ASSERT_THAT(BarDecl, NotNull()); 2641 2642 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2643 ASSERT_THAT(BazDecl, NotNull()); 2644 2645 // after_copy 2646 { 2647 const Environment &Env = 2648 getEnvironmentAtAnnotation(Results, "after_copy"); 2649 2650 const auto *FooLoc = 2651 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2652 const auto *BarLoc = 2653 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2654 2655 // `Foo` and `Bar` have different `RecordValue`s associated with them. 2656 const auto *FooVal = cast<RecordValue>(Env.getValue(*FooLoc)); 2657 const auto *BarVal = cast<RecordValue>(Env.getValue(*BarLoc)); 2658 EXPECT_NE(FooVal, BarVal); 2659 2660 // But the records compare equal. 2661 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env)); 2662 2663 // In particular, the value of `Baz` in both records is the same. 2664 const auto *FooBazVal = 2665 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2666 const auto *BarBazVal = 2667 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2668 EXPECT_EQ(FooBazVal, BarBazVal); 2669 } 2670 2671 // after_update 2672 { 2673 const Environment &Env = 2674 getEnvironmentAtAnnotation(Results, "after_update"); 2675 2676 const auto *FooLoc = 2677 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2678 const auto *BarLoc = 2679 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2680 2681 EXPECT_FALSE(recordsEqual(*FooLoc, *BarLoc, Env)); 2682 2683 const auto *FooBazVal = 2684 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2685 const auto *BarBazVal = 2686 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2687 EXPECT_NE(FooBazVal, BarBazVal); 2688 } 2689 }); 2690 } 2691 2692 TEST(TransferTest, CopyConstructorWithDefaultArgument) { 2693 std::string Code = R"( 2694 struct A { 2695 int Baz; 2696 A() = default; 2697 A(const A& a, bool def = true) { Baz = a.Baz; } 2698 }; 2699 2700 void target() { 2701 A Foo; 2702 (void)Foo.Baz; 2703 A Bar = Foo; 2704 // [[p]] 2705 } 2706 )"; 2707 runDataflow( 2708 Code, 2709 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2710 ASTContext &ASTCtx) { 2711 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2712 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2713 2714 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2715 ASSERT_THAT(FooDecl, NotNull()); 2716 2717 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2718 ASSERT_THAT(BarDecl, NotNull()); 2719 2720 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2721 ASSERT_THAT(BazDecl, NotNull()); 2722 2723 const auto *FooLoc = 2724 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2725 const auto *BarLoc = 2726 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2727 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env)); 2728 2729 const auto *FooBazVal = 2730 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2731 const auto *BarBazVal = 2732 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2733 EXPECT_EQ(FooBazVal, BarBazVal); 2734 }); 2735 } 2736 2737 TEST(TransferTest, CopyConstructorWithParens) { 2738 std::string Code = R"( 2739 struct A { 2740 int Baz; 2741 }; 2742 2743 void target() { 2744 A Foo; 2745 (void)Foo.Baz; 2746 A Bar((A(Foo))); 2747 // [[p]] 2748 } 2749 )"; 2750 runDataflow( 2751 Code, 2752 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2753 ASTContext &ASTCtx) { 2754 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2755 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2756 2757 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2758 ASSERT_THAT(FooDecl, NotNull()); 2759 2760 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2761 ASSERT_THAT(BarDecl, NotNull()); 2762 2763 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2764 ASSERT_THAT(BazDecl, NotNull()); 2765 2766 const auto *FooLoc = 2767 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2768 const auto *BarLoc = 2769 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2770 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env)); 2771 2772 const auto *FooBazVal = 2773 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2774 const auto *BarBazVal = 2775 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2776 EXPECT_EQ(FooBazVal, BarBazVal); 2777 }); 2778 } 2779 2780 TEST(TransferTest, CopyConstructorWithInitializerListAsSyntacticSugar) { 2781 std::string Code = R"( 2782 struct A { 2783 int Baz; 2784 }; 2785 void target() { 2786 A Foo = {3}; 2787 (void)Foo.Baz; 2788 A Bar = {A(Foo)}; 2789 // [[p]] 2790 } 2791 )"; 2792 runDataflow( 2793 Code, 2794 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2795 ASTContext &ASTCtx) { 2796 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2797 2798 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2799 2800 const auto &FooLoc = 2801 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo"); 2802 const auto &BarLoc = 2803 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar"); 2804 2805 const auto *FooBazVal = 2806 cast<IntegerValue>(getFieldValue(&FooLoc, *BazDecl, Env)); 2807 const auto *BarBazVal = 2808 cast<IntegerValue>(getFieldValue(&BarLoc, *BazDecl, Env)); 2809 EXPECT_EQ(FooBazVal, BarBazVal); 2810 }); 2811 } 2812 2813 TEST(TransferTest, CopyConstructorArgIsRefReturnedByFunction) { 2814 // This is a crash repro. 2815 std::string Code = R"( 2816 struct S {}; 2817 const S &returnsSRef(); 2818 void target() { 2819 S s(returnsSRef()); 2820 } 2821 )"; 2822 runDataflow( 2823 Code, 2824 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2825 ASTContext &ASTCtx) {}); 2826 } 2827 2828 TEST(TransferTest, MoveConstructor) { 2829 std::string Code = R"( 2830 namespace std { 2831 2832 template <typename T> struct remove_reference { using type = T; }; 2833 template <typename T> struct remove_reference<T&> { using type = T; }; 2834 template <typename T> struct remove_reference<T&&> { using type = T; }; 2835 2836 template <typename T> 2837 using remove_reference_t = typename remove_reference<T>::type; 2838 2839 template <typename T> 2840 std::remove_reference_t<T>&& move(T&& x); 2841 2842 } // namespace std 2843 2844 struct A { 2845 int Baz; 2846 }; 2847 2848 void target() { 2849 A Foo; 2850 A Bar; 2851 (void)Foo.Baz; 2852 // [[p1]] 2853 Foo = std::move(Bar); 2854 // [[p2]] 2855 } 2856 )"; 2857 runDataflow( 2858 Code, 2859 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2860 ASTContext &ASTCtx) { 2861 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 2862 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 2863 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 2864 2865 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2866 ASSERT_THAT(FooDecl, NotNull()); 2867 2868 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2869 ASSERT_THAT(BarDecl, NotNull()); 2870 2871 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2872 ASSERT_THAT(BazDecl, NotNull()); 2873 2874 const auto *FooLoc1 = 2875 cast<RecordStorageLocation>(Env1.getStorageLocation(*FooDecl)); 2876 const auto *BarLoc1 = 2877 cast<RecordStorageLocation>(Env1.getStorageLocation(*BarDecl)); 2878 2879 EXPECT_FALSE(recordsEqual(*FooLoc1, *BarLoc1, Env1)); 2880 2881 const auto *FooVal1 = cast<RecordValue>(Env1.getValue(*FooLoc1)); 2882 const auto *BarVal1 = cast<RecordValue>(Env1.getValue(*BarLoc1)); 2883 EXPECT_NE(FooVal1, BarVal1); 2884 2885 const auto *FooBazVal1 = 2886 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env1)); 2887 const auto *BarBazVal1 = 2888 cast<IntegerValue>(getFieldValue(BarLoc1, *BazDecl, Env1)); 2889 EXPECT_NE(FooBazVal1, BarBazVal1); 2890 2891 const auto *FooLoc2 = 2892 cast<RecordStorageLocation>(Env2.getStorageLocation(*FooDecl)); 2893 const auto *FooVal2 = cast<RecordValue>(Env2.getValue(*FooLoc2)); 2894 EXPECT_NE(FooVal2, BarVal1); 2895 EXPECT_TRUE(recordsEqual(*FooLoc2, Env2, *BarLoc1, Env1)); 2896 2897 const auto *FooBazVal2 = 2898 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env2)); 2899 EXPECT_EQ(FooBazVal2, BarBazVal1); 2900 }); 2901 } 2902 2903 TEST(TransferTest, BindTemporary) { 2904 std::string Code = R"( 2905 struct A { 2906 virtual ~A() = default; 2907 2908 int Baz; 2909 }; 2910 2911 void target(A Foo) { 2912 int Bar = A(Foo).Baz; 2913 // [[p]] 2914 } 2915 )"; 2916 runDataflow( 2917 Code, 2918 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2919 ASTContext &ASTCtx) { 2920 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2921 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2922 2923 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2924 ASSERT_THAT(FooDecl, NotNull()); 2925 2926 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2927 ASSERT_THAT(BarDecl, NotNull()); 2928 2929 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2930 ASSERT_THAT(BazDecl, NotNull()); 2931 2932 const auto &FooLoc = 2933 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2934 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 2935 EXPECT_EQ(BarVal, getFieldValue(&FooLoc, *BazDecl, Env)); 2936 }); 2937 } 2938 2939 TEST(TransferTest, ResultObjectLocation) { 2940 std::string Code = R"( 2941 struct A { 2942 virtual ~A() = default; 2943 }; 2944 2945 void target() { 2946 0, A(); 2947 (void)0; // [[p]] 2948 } 2949 )"; 2950 using ast_matchers::binaryOperator; 2951 using ast_matchers::cxxBindTemporaryExpr; 2952 using ast_matchers::cxxTemporaryObjectExpr; 2953 using ast_matchers::exprWithCleanups; 2954 using ast_matchers::has; 2955 using ast_matchers::hasOperatorName; 2956 using ast_matchers::hasRHS; 2957 using ast_matchers::match; 2958 using ast_matchers::selectFirst; 2959 using ast_matchers::traverse; 2960 runDataflow( 2961 Code, 2962 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2963 ASTContext &ASTCtx) { 2964 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2965 2966 // The expression `0, A()` in the code above produces the following 2967 // structure, consisting of four prvalues of record type. 2968 // `Env.getResultObjectLocation()` should return the same location for 2969 // all of these. 2970 auto MatchResult = match( 2971 traverse(TK_AsIs, 2972 exprWithCleanups( 2973 has(binaryOperator( 2974 hasOperatorName(","), 2975 hasRHS(cxxBindTemporaryExpr( 2976 has(cxxTemporaryObjectExpr().bind( 2977 "toe"))) 2978 .bind("bte"))) 2979 .bind("comma"))) 2980 .bind("ewc")), 2981 ASTCtx); 2982 auto *TOE = selectFirst<CXXTemporaryObjectExpr>("toe", MatchResult); 2983 ASSERT_NE(TOE, nullptr); 2984 auto *Comma = selectFirst<BinaryOperator>("comma", MatchResult); 2985 ASSERT_NE(Comma, nullptr); 2986 auto *EWC = selectFirst<ExprWithCleanups>("ewc", MatchResult); 2987 ASSERT_NE(EWC, nullptr); 2988 auto *BTE = selectFirst<CXXBindTemporaryExpr>("bte", MatchResult); 2989 ASSERT_NE(BTE, nullptr); 2990 2991 RecordStorageLocation &Loc = Env.getResultObjectLocation(*TOE); 2992 EXPECT_EQ(&Loc, &Env.getResultObjectLocation(*Comma)); 2993 EXPECT_EQ(&Loc, &Env.getResultObjectLocation(*EWC)); 2994 EXPECT_EQ(&Loc, &Env.getResultObjectLocation(*BTE)); 2995 }); 2996 } 2997 2998 TEST(TransferTest, ResultObjectLocationForDefaultArgExpr) { 2999 std::string Code = R"( 3000 struct Inner {}; 3001 struct Outer { 3002 Inner I = {}; 3003 }; 3004 3005 void funcWithDefaultArg(Outer O = {}); 3006 void target() { 3007 funcWithDefaultArg(); 3008 // [[p]] 3009 } 3010 )"; 3011 3012 using ast_matchers::cxxDefaultArgExpr; 3013 using ast_matchers::match; 3014 using ast_matchers::selectFirst; 3015 runDataflow( 3016 Code, 3017 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3018 ASTContext &ASTCtx) { 3019 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3020 3021 auto *DefaultArg = selectFirst<CXXDefaultArgExpr>( 3022 "default_arg", 3023 match(cxxDefaultArgExpr().bind("default_arg"), ASTCtx)); 3024 ASSERT_NE(DefaultArg, nullptr); 3025 3026 // The values for default arguments aren't modeled; we merely verify 3027 // that we can get a result object location for a default arg. 3028 Env.getResultObjectLocation(*DefaultArg); 3029 }); 3030 } 3031 3032 TEST(TransferTest, ResultObjectLocationForDefaultInitExpr) { 3033 std::string Code = R"( 3034 struct S {}; 3035 struct target { 3036 target () { 3037 (void)0; 3038 // [[p]] 3039 } 3040 S s = {}; 3041 }; 3042 )"; 3043 3044 using ast_matchers::cxxCtorInitializer; 3045 using ast_matchers::match; 3046 using ast_matchers::selectFirst; 3047 runDataflow( 3048 Code, 3049 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3050 ASTContext &ASTCtx) { 3051 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3052 3053 const ValueDecl *SField = findValueDecl(ASTCtx, "s"); 3054 3055 auto *CtorInit = selectFirst<CXXCtorInitializer>( 3056 "ctor_initializer", 3057 match(cxxCtorInitializer().bind("ctor_initializer"), ASTCtx)); 3058 ASSERT_NE(CtorInit, nullptr); 3059 3060 auto *DefaultInit = cast<CXXDefaultInitExpr>(CtorInit->getInit()); 3061 3062 RecordStorageLocation &Loc = Env.getResultObjectLocation(*DefaultInit); 3063 3064 EXPECT_EQ(&Loc, Env.getThisPointeeStorageLocation()->getChild(*SField)); 3065 }); 3066 } 3067 3068 // This test ensures that CXXOperatorCallExpr returning prvalues are correctly 3069 // handled by the transfer functions, especially that `getResultObjectLocation` 3070 // correctly returns a storage location for those. 3071 TEST(TransferTest, ResultObjectLocationForCXXOperatorCallExpr) { 3072 std::string Code = R"( 3073 struct A { 3074 A operator+(int); 3075 }; 3076 3077 void target() { 3078 A a; 3079 a + 3; 3080 (void)0; // [[p]] 3081 } 3082 )"; 3083 using ast_matchers::cxxOperatorCallExpr; 3084 using ast_matchers::match; 3085 using ast_matchers::selectFirst; 3086 using ast_matchers::traverse; 3087 runDataflow( 3088 Code, 3089 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3090 ASTContext &ASTCtx) { 3091 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3092 3093 auto *CallExpr = selectFirst<CXXOperatorCallExpr>( 3094 "call_expr", 3095 match(cxxOperatorCallExpr().bind("call_expr"), ASTCtx)); 3096 3097 EXPECT_NE(&Env.getResultObjectLocation(*CallExpr), nullptr); 3098 }); 3099 } 3100 3101 TEST(TransferTest, ResultObjectLocationForInitListExpr) { 3102 std::string Code = R"cc( 3103 struct Inner {}; 3104 3105 struct Outer { Inner I; }; 3106 3107 void target() { 3108 Outer O = { Inner() }; 3109 // [[p]] 3110 } 3111 )cc"; 3112 using ast_matchers::asString; 3113 using ast_matchers::cxxConstructExpr; 3114 using ast_matchers::hasType; 3115 using ast_matchers::match; 3116 using ast_matchers::selectFirst; 3117 using ast_matchers::traverse; 3118 runDataflow( 3119 Code, 3120 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3121 ASTContext &ASTCtx) { 3122 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3123 3124 auto *Construct = selectFirst<CXXConstructExpr>( 3125 "construct", 3126 match( 3127 cxxConstructExpr(hasType(asString("Inner"))).bind("construct"), 3128 ASTCtx)); 3129 3130 EXPECT_EQ( 3131 &Env.getResultObjectLocation(*Construct), 3132 &getFieldLoc(getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "O"), 3133 "I", ASTCtx)); 3134 }); 3135 } 3136 3137 TEST(TransferTest, ResultObjectLocationForParenInitListExpr) { 3138 std::string Code = R"cc( 3139 struct Inner {}; 3140 3141 struct Outer { Inner I; }; 3142 3143 void target() { 3144 Outer O((Inner())); 3145 // [[p]] 3146 } 3147 )cc"; 3148 using ast_matchers::asString; 3149 using ast_matchers::cxxConstructExpr; 3150 using ast_matchers::hasType; 3151 using ast_matchers::match; 3152 using ast_matchers::selectFirst; 3153 using ast_matchers::traverse; 3154 runDataflow( 3155 Code, 3156 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3157 ASTContext &ASTCtx) { 3158 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3159 3160 auto *Construct = selectFirst<CXXConstructExpr>( 3161 "construct", 3162 match( 3163 cxxConstructExpr(hasType(asString("Inner"))).bind("construct"), 3164 ASTCtx)); 3165 3166 EXPECT_EQ( 3167 &Env.getResultObjectLocation(*Construct), 3168 &getFieldLoc(getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "O"), 3169 "I", ASTCtx)); 3170 }, 3171 LangStandard::lang_cxx20); 3172 } 3173 3174 // Check that the `std::strong_ordering` object returned by builtin `<=>` has a 3175 // correctly modeled result object location. 3176 TEST(TransferTest, ResultObjectLocationForBuiltinSpaceshipOperator) { 3177 std::string Code = R"( 3178 namespace std { 3179 // This is the minimal definition required to get 3180 // `Sema::CheckComparisonCategoryType()` to accept this fake. 3181 struct strong_ordering { 3182 enum class ordering { less, equal, greater }; 3183 ordering o; 3184 static const strong_ordering less; 3185 static const strong_ordering equivalent; 3186 static const strong_ordering equal; 3187 static const strong_ordering greater; 3188 }; 3189 3190 inline constexpr strong_ordering strong_ordering::less = 3191 { strong_ordering::ordering::less }; 3192 inline constexpr strong_ordering strong_ordering::equal = 3193 { strong_ordering::ordering::equal }; 3194 inline constexpr strong_ordering strong_ordering::equivalent = 3195 { strong_ordering::ordering::equal }; 3196 inline constexpr strong_ordering strong_ordering::greater = 3197 { strong_ordering::ordering::greater }; 3198 } 3199 void target(int i, int j) { 3200 auto ordering = i <=> j; 3201 // [[p]] 3202 } 3203 )"; 3204 using ast_matchers::binaryOperator; 3205 using ast_matchers::hasOperatorName; 3206 using ast_matchers::match; 3207 using ast_matchers::selectFirst; 3208 using ast_matchers::traverse; 3209 runDataflow( 3210 Code, 3211 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3212 ASTContext &ASTCtx) { 3213 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3214 3215 auto *Spaceship = selectFirst<BinaryOperator>( 3216 "op", 3217 match(binaryOperator(hasOperatorName("<=>")).bind("op"), ASTCtx)); 3218 3219 EXPECT_EQ( 3220 &Env.getResultObjectLocation(*Spaceship), 3221 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "ordering")); 3222 }, 3223 LangStandard::lang_cxx20); 3224 } 3225 3226 TEST(TransferTest, ResultObjectLocationForStdInitializerListExpr) { 3227 std::string Code = R"( 3228 namespace std { 3229 template <typename T> 3230 struct initializer_list {}; 3231 } // namespace std 3232 3233 void target() { 3234 std::initializer_list<int> list = {1}; 3235 // [[p]] 3236 } 3237 )"; 3238 3239 using ast_matchers::cxxStdInitializerListExpr; 3240 using ast_matchers::match; 3241 using ast_matchers::selectFirst; 3242 runDataflow( 3243 Code, 3244 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3245 ASTContext &ASTCtx) { 3246 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3247 3248 auto *StdInitList = selectFirst<CXXStdInitializerListExpr>( 3249 "std_init_list", 3250 match(cxxStdInitializerListExpr().bind("std_init_list"), ASTCtx)); 3251 ASSERT_NE(StdInitList, nullptr); 3252 3253 EXPECT_EQ(&Env.getResultObjectLocation(*StdInitList), 3254 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "list")); 3255 }); 3256 } 3257 3258 TEST(TransferTest, ResultObjectLocationForStmtExpr) { 3259 std::string Code = R"( 3260 struct S {}; 3261 void target() { 3262 S s = ({ S(); }); 3263 // [[p]] 3264 } 3265 )"; 3266 using ast_matchers::cxxConstructExpr; 3267 using ast_matchers::match; 3268 using ast_matchers::selectFirst; 3269 using ast_matchers::traverse; 3270 runDataflow( 3271 Code, 3272 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3273 ASTContext &ASTCtx) { 3274 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3275 3276 auto *Construct = selectFirst<CXXConstructExpr>( 3277 "construct", match(cxxConstructExpr().bind("construct"), ASTCtx)); 3278 3279 EXPECT_EQ(&Env.getResultObjectLocation(*Construct), 3280 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s")); 3281 }); 3282 } 3283 3284 TEST(TransferTest, ResultObjectLocationForBuiltinBitCastExpr) { 3285 std::string Code = R"( 3286 struct S { int i; }; 3287 void target(int i) { 3288 S s = __builtin_bit_cast(S, i); 3289 // [[p]] 3290 } 3291 )"; 3292 using ast_matchers::explicitCastExpr; 3293 using ast_matchers::match; 3294 using ast_matchers::selectFirst; 3295 using ast_matchers::traverse; 3296 runDataflow( 3297 Code, 3298 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3299 ASTContext &ASTCtx) { 3300 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3301 3302 auto *BuiltinBitCast = selectFirst<BuiltinBitCastExpr>( 3303 "cast", match(explicitCastExpr().bind("cast"), ASTCtx)); 3304 3305 EXPECT_EQ(&Env.getResultObjectLocation(*BuiltinBitCast), 3306 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s")); 3307 }); 3308 } 3309 3310 TEST(TransferTest, ResultObjectLocationPropagatesThroughConditionalOperator) { 3311 std::string Code = R"( 3312 struct A { 3313 A(int); 3314 }; 3315 3316 void target(bool b) { 3317 A a = b ? A(0) : A(1); 3318 (void)0; // [[p]] 3319 } 3320 )"; 3321 using ast_matchers::cxxConstructExpr; 3322 using ast_matchers::equals; 3323 using ast_matchers::hasArgument; 3324 using ast_matchers::integerLiteral; 3325 using ast_matchers::match; 3326 using ast_matchers::selectFirst; 3327 using ast_matchers::traverse; 3328 runDataflow( 3329 Code, 3330 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3331 ASTContext &ASTCtx) { 3332 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3333 3334 auto *ConstructExpr0 = selectFirst<CXXConstructExpr>( 3335 "construct", 3336 match(cxxConstructExpr(hasArgument(0, integerLiteral(equals(0)))) 3337 .bind("construct"), 3338 ASTCtx)); 3339 auto *ConstructExpr1 = selectFirst<CXXConstructExpr>( 3340 "construct", 3341 match(cxxConstructExpr(hasArgument(0, integerLiteral(equals(1)))) 3342 .bind("construct"), 3343 ASTCtx)); 3344 3345 auto &ALoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "a"); 3346 EXPECT_EQ(&Env.getResultObjectLocation(*ConstructExpr0), &ALoc); 3347 EXPECT_EQ(&Env.getResultObjectLocation(*ConstructExpr1), &ALoc); 3348 }); 3349 } 3350 3351 TEST(TransferTest, StaticCast) { 3352 std::string Code = R"( 3353 void target(int Foo) { 3354 int Bar = static_cast<int>(Foo); 3355 // [[p]] 3356 } 3357 )"; 3358 runDataflow( 3359 Code, 3360 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3361 ASTContext &ASTCtx) { 3362 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3363 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3364 3365 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3366 ASSERT_THAT(FooDecl, NotNull()); 3367 3368 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3369 ASSERT_THAT(BarDecl, NotNull()); 3370 3371 const auto *FooVal = Env.getValue(*FooDecl); 3372 const auto *BarVal = Env.getValue(*BarDecl); 3373 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 3374 EXPECT_TRUE(isa<IntegerValue>(BarVal)); 3375 EXPECT_EQ(FooVal, BarVal); 3376 }); 3377 } 3378 3379 TEST(TransferTest, IntegralCast) { 3380 std::string Code = R"( 3381 void target(int Foo) { 3382 long Bar = Foo; 3383 // [[p]] 3384 } 3385 )"; 3386 runDataflow( 3387 Code, 3388 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3389 ASTContext &ASTCtx) { 3390 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3391 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3392 3393 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3394 ASSERT_THAT(FooDecl, NotNull()); 3395 3396 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3397 ASSERT_THAT(BarDecl, NotNull()); 3398 3399 const auto *FooVal = Env.getValue(*FooDecl); 3400 const auto *BarVal = Env.getValue(*BarDecl); 3401 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 3402 EXPECT_TRUE(isa<IntegerValue>(BarVal)); 3403 EXPECT_EQ(FooVal, BarVal); 3404 }); 3405 } 3406 3407 TEST(TransferTest, IntegraltoBooleanCast) { 3408 std::string Code = R"( 3409 void target(int Foo) { 3410 bool Bar = Foo; 3411 // [[p]] 3412 } 3413 )"; 3414 runDataflow( 3415 Code, 3416 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3417 ASTContext &ASTCtx) { 3418 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3419 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3420 3421 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3422 ASSERT_THAT(FooDecl, NotNull()); 3423 3424 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3425 ASSERT_THAT(BarDecl, NotNull()); 3426 3427 const auto *FooVal = Env.getValue(*FooDecl); 3428 const auto *BarVal = Env.getValue(*BarDecl); 3429 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 3430 EXPECT_TRUE(isa<BoolValue>(BarVal)); 3431 }); 3432 } 3433 3434 TEST(TransferTest, IntegralToBooleanCastFromBool) { 3435 std::string Code = R"( 3436 void target(bool Foo) { 3437 int Zab = Foo; 3438 bool Bar = Zab; 3439 // [[p]] 3440 } 3441 )"; 3442 runDataflow( 3443 Code, 3444 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3445 ASTContext &ASTCtx) { 3446 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3447 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3448 3449 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3450 ASSERT_THAT(FooDecl, NotNull()); 3451 3452 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3453 ASSERT_THAT(BarDecl, NotNull()); 3454 3455 const auto *FooVal = Env.getValue(*FooDecl); 3456 const auto *BarVal = Env.getValue(*BarDecl); 3457 EXPECT_TRUE(isa<BoolValue>(FooVal)); 3458 EXPECT_TRUE(isa<BoolValue>(BarVal)); 3459 EXPECT_EQ(FooVal, BarVal); 3460 }); 3461 } 3462 3463 TEST(TransferTest, NullToPointerCast) { 3464 std::string Code = R"( 3465 using my_nullptr_t = decltype(nullptr); 3466 struct Baz {}; 3467 void target() { 3468 int *FooX = nullptr; 3469 int *FooY = nullptr; 3470 bool **Bar = nullptr; 3471 Baz *Baz = nullptr; 3472 my_nullptr_t Null = 0; 3473 // [[p]] 3474 } 3475 )"; 3476 runDataflow( 3477 Code, 3478 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3479 ASTContext &ASTCtx) { 3480 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3481 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3482 3483 const ValueDecl *FooXDecl = findValueDecl(ASTCtx, "FooX"); 3484 ASSERT_THAT(FooXDecl, NotNull()); 3485 3486 const ValueDecl *FooYDecl = findValueDecl(ASTCtx, "FooY"); 3487 ASSERT_THAT(FooYDecl, NotNull()); 3488 3489 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3490 ASSERT_THAT(BarDecl, NotNull()); 3491 3492 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3493 ASSERT_THAT(BazDecl, NotNull()); 3494 3495 const ValueDecl *NullDecl = findValueDecl(ASTCtx, "Null"); 3496 ASSERT_THAT(NullDecl, NotNull()); 3497 3498 const auto *FooXVal = cast<PointerValue>(Env.getValue(*FooXDecl)); 3499 const auto *FooYVal = cast<PointerValue>(Env.getValue(*FooYDecl)); 3500 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 3501 const auto *BazVal = cast<PointerValue>(Env.getValue(*BazDecl)); 3502 const auto *NullVal = cast<PointerValue>(Env.getValue(*NullDecl)); 3503 3504 EXPECT_EQ(FooXVal, FooYVal); 3505 EXPECT_NE(FooXVal, BarVal); 3506 EXPECT_NE(FooXVal, BazVal); 3507 EXPECT_NE(BarVal, BazVal); 3508 3509 const StorageLocation &FooPointeeLoc = FooXVal->getPointeeLoc(); 3510 EXPECT_TRUE(isa<ScalarStorageLocation>(FooPointeeLoc)); 3511 EXPECT_THAT(Env.getValue(FooPointeeLoc), IsNull()); 3512 3513 const StorageLocation &BarPointeeLoc = BarVal->getPointeeLoc(); 3514 EXPECT_TRUE(isa<ScalarStorageLocation>(BarPointeeLoc)); 3515 EXPECT_THAT(Env.getValue(BarPointeeLoc), IsNull()); 3516 3517 const StorageLocation &BazPointeeLoc = BazVal->getPointeeLoc(); 3518 EXPECT_TRUE(isa<RecordStorageLocation>(BazPointeeLoc)); 3519 EXPECT_THAT(Env.getValue(BazPointeeLoc), IsNull()); 3520 3521 const StorageLocation &NullPointeeLoc = NullVal->getPointeeLoc(); 3522 EXPECT_TRUE(isa<ScalarStorageLocation>(NullPointeeLoc)); 3523 EXPECT_THAT(Env.getValue(NullPointeeLoc), IsNull()); 3524 }); 3525 } 3526 3527 TEST(TransferTest, PointerToMemberVariable) { 3528 std::string Code = R"( 3529 struct S { 3530 int i; 3531 }; 3532 void target() { 3533 int S::*MemberPointer = &S::i; 3534 // [[p]] 3535 } 3536 )"; 3537 runDataflow( 3538 Code, 3539 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3540 ASTContext &ASTCtx) { 3541 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3542 3543 const ValueDecl *MemberPointerDecl = 3544 findValueDecl(ASTCtx, "MemberPointer"); 3545 ASSERT_THAT(MemberPointerDecl, NotNull()); 3546 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 3547 }); 3548 } 3549 3550 TEST(TransferTest, PointerToMemberFunction) { 3551 std::string Code = R"( 3552 struct S { 3553 void Method(); 3554 }; 3555 void target() { 3556 void (S::*MemberPointer)() = &S::Method; 3557 // [[p]] 3558 } 3559 )"; 3560 runDataflow( 3561 Code, 3562 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3563 ASTContext &ASTCtx) { 3564 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3565 3566 const ValueDecl *MemberPointerDecl = 3567 findValueDecl(ASTCtx, "MemberPointer"); 3568 ASSERT_THAT(MemberPointerDecl, NotNull()); 3569 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 3570 }); 3571 } 3572 3573 TEST(TransferTest, NullToMemberPointerCast) { 3574 std::string Code = R"( 3575 struct Foo {}; 3576 void target() { 3577 int Foo::*MemberPointer = nullptr; 3578 // [[p]] 3579 } 3580 )"; 3581 runDataflow( 3582 Code, 3583 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3584 ASTContext &ASTCtx) { 3585 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3586 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3587 3588 const ValueDecl *MemberPointerDecl = 3589 findValueDecl(ASTCtx, "MemberPointer"); 3590 ASSERT_THAT(MemberPointerDecl, NotNull()); 3591 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 3592 }); 3593 } 3594 3595 TEST(TransferTest, AddrOfValue) { 3596 std::string Code = R"( 3597 void target() { 3598 int Foo; 3599 int *Bar = &Foo; 3600 // [[p]] 3601 } 3602 )"; 3603 runDataflow( 3604 Code, 3605 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3606 ASTContext &ASTCtx) { 3607 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3608 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3609 3610 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3611 ASSERT_THAT(FooDecl, NotNull()); 3612 3613 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3614 ASSERT_THAT(BarDecl, NotNull()); 3615 3616 const auto *FooLoc = 3617 cast<ScalarStorageLocation>(Env.getStorageLocation(*FooDecl)); 3618 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 3619 EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc); 3620 }); 3621 } 3622 3623 TEST(TransferTest, AddrOfReference) { 3624 std::string Code = R"( 3625 void target(int *Foo) { 3626 int *Bar = &(*Foo); 3627 // [[p]] 3628 } 3629 )"; 3630 runDataflow( 3631 Code, 3632 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3633 ASTContext &ASTCtx) { 3634 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3635 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3636 3637 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3638 ASSERT_THAT(FooDecl, NotNull()); 3639 3640 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3641 ASSERT_THAT(BarDecl, NotNull()); 3642 3643 const auto *FooVal = cast<PointerValue>(Env.getValue(*FooDecl)); 3644 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 3645 EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc()); 3646 }); 3647 } 3648 3649 TEST(TransferTest, CannotAnalyzeFunctionTemplate) { 3650 std::string Code = R"( 3651 template <typename T> 3652 void target() {} 3653 )"; 3654 ASSERT_THAT_ERROR( 3655 checkDataflowWithNoopAnalysis(Code), 3656 llvm::FailedWithMessage("Cannot analyze templated declarations")); 3657 } 3658 3659 TEST(TransferTest, CannotAnalyzeMethodOfClassTemplate) { 3660 std::string Code = R"( 3661 template <typename T> 3662 struct A { 3663 void target() {} 3664 }; 3665 )"; 3666 ASSERT_THAT_ERROR( 3667 checkDataflowWithNoopAnalysis(Code), 3668 llvm::FailedWithMessage("Cannot analyze templated declarations")); 3669 } 3670 3671 TEST(TransferTest, VarDeclInitAssignConditionalOperator) { 3672 std::string Code = R"( 3673 struct A {}; 3674 3675 void target(A Foo, A Bar, bool Cond) { 3676 A Baz = Cond ? Foo : Bar; 3677 /*[[p]]*/ 3678 } 3679 )"; 3680 runDataflow( 3681 Code, 3682 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3683 ASTContext &ASTCtx) { 3684 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3685 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3686 3687 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3688 ASSERT_THAT(FooDecl, NotNull()); 3689 3690 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3691 ASSERT_THAT(BarDecl, NotNull()); 3692 3693 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3694 ASSERT_THAT(BazDecl, NotNull()); 3695 3696 const auto *FooVal = cast<RecordValue>(Env.getValue(*FooDecl)); 3697 const auto *BarVal = cast<RecordValue>(Env.getValue(*BarDecl)); 3698 3699 const auto *BazVal = dyn_cast<RecordValue>(Env.getValue(*BazDecl)); 3700 ASSERT_THAT(BazVal, NotNull()); 3701 3702 EXPECT_NE(BazVal, FooVal); 3703 EXPECT_NE(BazVal, BarVal); 3704 }); 3705 } 3706 3707 TEST(TransferTest, VarDeclInDoWhile) { 3708 std::string Code = R"( 3709 void target(int *Foo) { 3710 do { 3711 int Bar = *Foo; 3712 // [[in_loop]] 3713 } while (false); 3714 (void)0; 3715 // [[after_loop]] 3716 } 3717 )"; 3718 runDataflow( 3719 Code, 3720 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3721 ASTContext &ASTCtx) { 3722 const Environment &EnvInLoop = 3723 getEnvironmentAtAnnotation(Results, "in_loop"); 3724 const Environment &EnvAfterLoop = 3725 getEnvironmentAtAnnotation(Results, "after_loop"); 3726 3727 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3728 ASSERT_THAT(FooDecl, NotNull()); 3729 3730 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3731 ASSERT_THAT(BarDecl, NotNull()); 3732 3733 const auto *FooVal = 3734 cast<PointerValue>(EnvAfterLoop.getValue(*FooDecl)); 3735 const auto *FooPointeeVal = 3736 cast<IntegerValue>(EnvAfterLoop.getValue(FooVal->getPointeeLoc())); 3737 3738 const auto *BarVal = cast<IntegerValue>(EnvInLoop.getValue(*BarDecl)); 3739 EXPECT_EQ(BarVal, FooPointeeVal); 3740 3741 ASSERT_THAT(EnvAfterLoop.getValue(*BarDecl), IsNull()); 3742 }); 3743 } 3744 3745 TEST(TransferTest, UnreachableAfterWhileTrue) { 3746 std::string Code = R"( 3747 void target() { 3748 while (true) {} 3749 (void)0; 3750 /*[[p]]*/ 3751 } 3752 )"; 3753 runDataflow( 3754 Code, 3755 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3756 ASTContext &ASTCtx) { 3757 // The node after the while-true is pruned because it is trivially 3758 // known to be unreachable. 3759 ASSERT_TRUE(Results.empty()); 3760 }); 3761 } 3762 3763 TEST(TransferTest, AggregateInitialization) { 3764 std::string BracesCode = R"( 3765 struct A { 3766 int Foo; 3767 }; 3768 3769 struct B { 3770 int Bar; 3771 A Baz; 3772 int Qux; 3773 }; 3774 3775 void target(int BarArg, int FooArg, int QuxArg) { 3776 B Quux{BarArg, {FooArg}, QuxArg}; 3777 B OtherB; 3778 /*[[p]]*/ 3779 } 3780 )"; 3781 std::string BraceElisionCode = R"( 3782 struct A { 3783 int Foo; 3784 }; 3785 3786 struct B { 3787 int Bar; 3788 A Baz; 3789 int Qux; 3790 }; 3791 3792 void target(int BarArg, int FooArg, int QuxArg) { 3793 B Quux = {BarArg, FooArg, QuxArg}; 3794 B OtherB; 3795 /*[[p]]*/ 3796 } 3797 )"; 3798 for (const std::string &Code : {BracesCode, BraceElisionCode}) { 3799 runDataflow( 3800 Code, 3801 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3802 ASTContext &ASTCtx) { 3803 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3804 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3805 3806 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3807 ASSERT_THAT(FooDecl, NotNull()); 3808 3809 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3810 ASSERT_THAT(BarDecl, NotNull()); 3811 3812 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3813 ASSERT_THAT(BazDecl, NotNull()); 3814 3815 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 3816 ASSERT_THAT(QuxDecl, NotNull()); 3817 3818 const ValueDecl *FooArgDecl = findValueDecl(ASTCtx, "FooArg"); 3819 ASSERT_THAT(FooArgDecl, NotNull()); 3820 3821 const ValueDecl *BarArgDecl = findValueDecl(ASTCtx, "BarArg"); 3822 ASSERT_THAT(BarArgDecl, NotNull()); 3823 3824 const ValueDecl *QuxArgDecl = findValueDecl(ASTCtx, "QuxArg"); 3825 ASSERT_THAT(QuxArgDecl, NotNull()); 3826 3827 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 3828 ASSERT_THAT(QuuxDecl, NotNull()); 3829 3830 const auto *FooArgVal = cast<IntegerValue>(Env.getValue(*FooArgDecl)); 3831 const auto *BarArgVal = cast<IntegerValue>(Env.getValue(*BarArgDecl)); 3832 const auto *QuxArgVal = cast<IntegerValue>(Env.getValue(*QuxArgDecl)); 3833 3834 const auto &QuuxLoc = 3835 *cast<RecordStorageLocation>(Env.getStorageLocation(*QuuxDecl)); 3836 const auto &BazLoc = 3837 *cast<RecordStorageLocation>(QuuxLoc.getChild(*BazDecl)); 3838 3839 EXPECT_EQ(getFieldValue(&QuuxLoc, *BarDecl, Env), BarArgVal); 3840 EXPECT_EQ(getFieldValue(&BazLoc, *FooDecl, Env), FooArgVal); 3841 EXPECT_EQ(getFieldValue(&QuuxLoc, *QuxDecl, Env), QuxArgVal); 3842 3843 // Check that fields initialized in an initializer list are always 3844 // modeled in other instances of the same type. 3845 const auto &OtherBLoc = 3846 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "OtherB"); 3847 EXPECT_THAT(OtherBLoc.getChild(*BarDecl), NotNull()); 3848 EXPECT_THAT(OtherBLoc.getChild(*BazDecl), NotNull()); 3849 EXPECT_THAT(OtherBLoc.getChild(*QuxDecl), NotNull()); 3850 }); 3851 } 3852 } 3853 3854 TEST(TransferTest, AggregateInitializationReferenceField) { 3855 std::string Code = R"( 3856 struct S { 3857 int &RefField; 3858 }; 3859 3860 void target(int i) { 3861 S s = { i }; 3862 /*[[p]]*/ 3863 } 3864 )"; 3865 runDataflow( 3866 Code, 3867 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3868 ASTContext &ASTCtx) { 3869 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3870 3871 const ValueDecl *RefFieldDecl = findValueDecl(ASTCtx, "RefField"); 3872 3873 auto &ILoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "i"); 3874 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"); 3875 3876 EXPECT_EQ(SLoc.getChild(*RefFieldDecl), &ILoc); 3877 }); 3878 } 3879 3880 TEST(TransferTest, AggregateInitialization_NotExplicitlyInitializedField) { 3881 std::string Code = R"( 3882 struct S { 3883 int i1; 3884 int i2; 3885 }; 3886 3887 void target(int i) { 3888 S s = { i }; 3889 /*[[p]]*/ 3890 } 3891 )"; 3892 runDataflow( 3893 Code, 3894 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3895 ASTContext &ASTCtx) { 3896 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3897 3898 const ValueDecl *I1FieldDecl = findValueDecl(ASTCtx, "i1"); 3899 const ValueDecl *I2FieldDecl = findValueDecl(ASTCtx, "i2"); 3900 3901 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"); 3902 3903 auto &IValue = getValueForDecl<IntegerValue>(ASTCtx, Env, "i"); 3904 auto &I1Value = 3905 *cast<IntegerValue>(getFieldValue(&SLoc, *I1FieldDecl, Env)); 3906 EXPECT_EQ(&I1Value, &IValue); 3907 auto &I2Value = 3908 *cast<IntegerValue>(getFieldValue(&SLoc, *I2FieldDecl, Env)); 3909 EXPECT_NE(&I2Value, &IValue); 3910 }); 3911 } 3912 3913 TEST(TransferTest, AggregateInitializationFunctionPointer) { 3914 // This is a repro for an assertion failure. 3915 // nullptr takes on the type of a const function pointer, but its type was 3916 // asserted to be equal to the *unqualified* type of Field, which no longer 3917 // included the const. 3918 std::string Code = R"( 3919 struct S { 3920 void (*const Field)(); 3921 }; 3922 3923 void target() { 3924 S s{nullptr}; 3925 } 3926 )"; 3927 runDataflow( 3928 Code, 3929 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3930 ASTContext &ASTCtx) {}); 3931 } 3932 3933 TEST(TransferTest, AssignToUnionMember) { 3934 std::string Code = R"( 3935 union A { 3936 int Foo; 3937 }; 3938 3939 void target(int Bar) { 3940 A Baz; 3941 Baz.Foo = Bar; 3942 // [[p]] 3943 } 3944 )"; 3945 runDataflow( 3946 Code, 3947 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3948 ASTContext &ASTCtx) { 3949 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3950 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3951 3952 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3953 ASSERT_THAT(BazDecl, NotNull()); 3954 ASSERT_TRUE(BazDecl->getType()->isUnionType()); 3955 3956 auto BazFields = BazDecl->getType()->getAsRecordDecl()->fields(); 3957 FieldDecl *FooDecl = nullptr; 3958 for (FieldDecl *Field : BazFields) { 3959 if (Field->getNameAsString() == "Foo") { 3960 FooDecl = Field; 3961 } else { 3962 FAIL() << "Unexpected field: " << Field->getNameAsString(); 3963 } 3964 } 3965 ASSERT_THAT(FooDecl, NotNull()); 3966 3967 const auto *BazLoc = dyn_cast_or_null<RecordStorageLocation>( 3968 Env.getStorageLocation(*BazDecl)); 3969 ASSERT_THAT(BazLoc, NotNull()); 3970 ASSERT_THAT(Env.getValue(*BazLoc), NotNull()); 3971 3972 const auto *FooVal = 3973 cast<IntegerValue>(getFieldValue(BazLoc, *FooDecl, Env)); 3974 3975 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3976 ASSERT_THAT(BarDecl, NotNull()); 3977 const auto *BarLoc = Env.getStorageLocation(*BarDecl); 3978 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 3979 3980 EXPECT_EQ(Env.getValue(*BarLoc), FooVal); 3981 }); 3982 } 3983 3984 TEST(TransferTest, AssignFromBoolLiteral) { 3985 std::string Code = R"( 3986 void target() { 3987 bool Foo = true; 3988 bool Bar = false; 3989 // [[p]] 3990 } 3991 )"; 3992 runDataflow( 3993 Code, 3994 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3995 ASTContext &ASTCtx) { 3996 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3997 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3998 3999 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4000 ASSERT_THAT(FooDecl, NotNull()); 4001 4002 const auto *FooVal = 4003 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 4004 ASSERT_THAT(FooVal, NotNull()); 4005 4006 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4007 ASSERT_THAT(BarDecl, NotNull()); 4008 4009 const auto *BarVal = 4010 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 4011 ASSERT_THAT(BarVal, NotNull()); 4012 4013 EXPECT_EQ(FooVal, &Env.getBoolLiteralValue(true)); 4014 EXPECT_EQ(BarVal, &Env.getBoolLiteralValue(false)); 4015 }); 4016 } 4017 4018 TEST(TransferTest, AssignFromCompositeBoolExpression) { 4019 { 4020 std::string Code = R"( 4021 void target(bool Foo, bool Bar, bool Qux) { 4022 bool Baz = (Foo) && (Bar || Qux); 4023 // [[p]] 4024 } 4025 )"; 4026 runDataflow( 4027 Code, 4028 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4029 ASTContext &ASTCtx) { 4030 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4031 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4032 4033 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4034 ASSERT_THAT(FooDecl, NotNull()); 4035 4036 const auto *FooVal = 4037 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 4038 ASSERT_THAT(FooVal, NotNull()); 4039 4040 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4041 ASSERT_THAT(BarDecl, NotNull()); 4042 4043 const auto *BarVal = 4044 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 4045 ASSERT_THAT(BarVal, NotNull()); 4046 4047 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4048 ASSERT_THAT(QuxDecl, NotNull()); 4049 4050 const auto *QuxVal = 4051 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl)); 4052 ASSERT_THAT(QuxVal, NotNull()); 4053 4054 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4055 ASSERT_THAT(BazDecl, NotNull()); 4056 4057 const auto *BazVal = 4058 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl)); 4059 ASSERT_THAT(BazVal, NotNull()); 4060 auto &A = Env.arena(); 4061 EXPECT_EQ(&BazVal->formula(), 4062 &A.makeAnd(FooVal->formula(), 4063 A.makeOr(BarVal->formula(), QuxVal->formula()))); 4064 }); 4065 } 4066 4067 { 4068 std::string Code = R"( 4069 void target(bool Foo, bool Bar, bool Qux) { 4070 bool Baz = (Foo && Qux) || (Bar); 4071 // [[p]] 4072 } 4073 )"; 4074 runDataflow( 4075 Code, 4076 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4077 ASTContext &ASTCtx) { 4078 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4079 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4080 4081 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4082 ASSERT_THAT(FooDecl, NotNull()); 4083 4084 const auto *FooVal = 4085 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 4086 ASSERT_THAT(FooVal, NotNull()); 4087 4088 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4089 ASSERT_THAT(BarDecl, NotNull()); 4090 4091 const auto *BarVal = 4092 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 4093 ASSERT_THAT(BarVal, NotNull()); 4094 4095 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4096 ASSERT_THAT(QuxDecl, NotNull()); 4097 4098 const auto *QuxVal = 4099 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl)); 4100 ASSERT_THAT(QuxVal, NotNull()); 4101 4102 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4103 ASSERT_THAT(BazDecl, NotNull()); 4104 4105 const auto *BazVal = 4106 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl)); 4107 ASSERT_THAT(BazVal, NotNull()); 4108 auto &A = Env.arena(); 4109 EXPECT_EQ(&BazVal->formula(), 4110 &A.makeOr(A.makeAnd(FooVal->formula(), QuxVal->formula()), 4111 BarVal->formula())); 4112 }); 4113 } 4114 4115 { 4116 std::string Code = R"( 4117 void target(bool A, bool B, bool C, bool D) { 4118 bool Foo = ((A && B) && C) && D; 4119 // [[p]] 4120 } 4121 )"; 4122 runDataflow( 4123 Code, 4124 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4125 ASTContext &ASTCtx) { 4126 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4127 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4128 4129 const ValueDecl *ADecl = findValueDecl(ASTCtx, "A"); 4130 ASSERT_THAT(ADecl, NotNull()); 4131 4132 const auto *AVal = dyn_cast_or_null<BoolValue>(Env.getValue(*ADecl)); 4133 ASSERT_THAT(AVal, NotNull()); 4134 4135 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B"); 4136 ASSERT_THAT(BDecl, NotNull()); 4137 4138 const auto *BVal = dyn_cast_or_null<BoolValue>(Env.getValue(*BDecl)); 4139 ASSERT_THAT(BVal, NotNull()); 4140 4141 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C"); 4142 ASSERT_THAT(CDecl, NotNull()); 4143 4144 const auto *CVal = dyn_cast_or_null<BoolValue>(Env.getValue(*CDecl)); 4145 ASSERT_THAT(CVal, NotNull()); 4146 4147 const ValueDecl *DDecl = findValueDecl(ASTCtx, "D"); 4148 ASSERT_THAT(DDecl, NotNull()); 4149 4150 const auto *DVal = dyn_cast_or_null<BoolValue>(Env.getValue(*DDecl)); 4151 ASSERT_THAT(DVal, NotNull()); 4152 4153 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4154 ASSERT_THAT(FooDecl, NotNull()); 4155 4156 const auto *FooVal = 4157 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 4158 ASSERT_THAT(FooVal, NotNull()); 4159 auto &A = Env.arena(); 4160 EXPECT_EQ( 4161 &FooVal->formula(), 4162 &A.makeAnd(A.makeAnd(A.makeAnd(AVal->formula(), BVal->formula()), 4163 CVal->formula()), 4164 DVal->formula())); 4165 }); 4166 } 4167 } 4168 4169 TEST(TransferTest, AssignFromBoolNegation) { 4170 std::string Code = R"( 4171 void target() { 4172 bool Foo = true; 4173 bool Bar = !(Foo); 4174 // [[p]] 4175 } 4176 )"; 4177 runDataflow( 4178 Code, 4179 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4180 ASTContext &ASTCtx) { 4181 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4182 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4183 4184 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4185 ASSERT_THAT(FooDecl, NotNull()); 4186 4187 const auto *FooVal = 4188 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 4189 ASSERT_THAT(FooVal, NotNull()); 4190 4191 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4192 ASSERT_THAT(BarDecl, NotNull()); 4193 4194 const auto *BarVal = 4195 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 4196 ASSERT_THAT(BarVal, NotNull()); 4197 auto &A = Env.arena(); 4198 EXPECT_EQ(&BarVal->formula(), &A.makeNot(FooVal->formula())); 4199 }); 4200 } 4201 4202 TEST(TransferTest, BuiltinExpect) { 4203 std::string Code = R"( 4204 void target(long Foo) { 4205 long Bar = __builtin_expect(Foo, true); 4206 /*[[p]]*/ 4207 } 4208 )"; 4209 runDataflow( 4210 Code, 4211 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4212 ASTContext &ASTCtx) { 4213 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4214 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4215 4216 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4217 ASSERT_THAT(FooDecl, NotNull()); 4218 4219 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4220 ASSERT_THAT(BarDecl, NotNull()); 4221 4222 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 4223 }); 4224 } 4225 4226 // `__builtin_expect` takes and returns a `long` argument, so other types 4227 // involve casts. This verifies that we identify the input and output in that 4228 // case. 4229 TEST(TransferTest, BuiltinExpectBoolArg) { 4230 std::string Code = R"( 4231 void target(bool Foo) { 4232 bool Bar = __builtin_expect(Foo, true); 4233 /*[[p]]*/ 4234 } 4235 )"; 4236 runDataflow( 4237 Code, 4238 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4239 ASTContext &ASTCtx) { 4240 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4241 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4242 4243 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4244 ASSERT_THAT(FooDecl, NotNull()); 4245 4246 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4247 ASSERT_THAT(BarDecl, NotNull()); 4248 4249 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 4250 }); 4251 } 4252 4253 TEST(TransferTest, BuiltinUnreachable) { 4254 std::string Code = R"( 4255 void target(bool Foo) { 4256 bool Bar = false; 4257 if (Foo) 4258 Bar = Foo; 4259 else 4260 __builtin_unreachable(); 4261 (void)0; 4262 /*[[p]]*/ 4263 } 4264 )"; 4265 runDataflow( 4266 Code, 4267 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4268 ASTContext &ASTCtx) { 4269 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4270 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4271 4272 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4273 ASSERT_THAT(FooDecl, NotNull()); 4274 4275 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4276 ASSERT_THAT(BarDecl, NotNull()); 4277 4278 // `__builtin_unreachable` promises that the code is 4279 // unreachable, so the compiler treats the "then" branch as the 4280 // only possible predecessor of this statement. 4281 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 4282 }); 4283 } 4284 4285 TEST(TransferTest, BuiltinTrap) { 4286 std::string Code = R"( 4287 void target(bool Foo) { 4288 bool Bar = false; 4289 if (Foo) 4290 Bar = Foo; 4291 else 4292 __builtin_trap(); 4293 (void)0; 4294 /*[[p]]*/ 4295 } 4296 )"; 4297 runDataflow( 4298 Code, 4299 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4300 ASTContext &ASTCtx) { 4301 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4302 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4303 4304 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4305 ASSERT_THAT(FooDecl, NotNull()); 4306 4307 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4308 ASSERT_THAT(BarDecl, NotNull()); 4309 4310 // `__builtin_trap` ensures program termination, so only the 4311 // "then" branch is a predecessor of this statement. 4312 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 4313 }); 4314 } 4315 4316 TEST(TransferTest, BuiltinDebugTrap) { 4317 std::string Code = R"( 4318 void target(bool Foo) { 4319 bool Bar = false; 4320 if (Foo) 4321 Bar = Foo; 4322 else 4323 __builtin_debugtrap(); 4324 (void)0; 4325 /*[[p]]*/ 4326 } 4327 )"; 4328 runDataflow( 4329 Code, 4330 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4331 ASTContext &ASTCtx) { 4332 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4333 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4334 4335 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4336 ASSERT_THAT(FooDecl, NotNull()); 4337 4338 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4339 ASSERT_THAT(BarDecl, NotNull()); 4340 4341 // `__builtin_debugtrap` doesn't ensure program termination. 4342 EXPECT_NE(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 4343 }); 4344 } 4345 4346 TEST(TransferTest, StaticIntSingleVarDecl) { 4347 std::string Code = R"( 4348 void target() { 4349 static int Foo; 4350 // [[p]] 4351 } 4352 )"; 4353 runDataflow( 4354 Code, 4355 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4356 ASTContext &ASTCtx) { 4357 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4358 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4359 4360 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4361 ASSERT_THAT(FooDecl, NotNull()); 4362 4363 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 4364 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 4365 4366 const Value *FooVal = Env.getValue(*FooLoc); 4367 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 4368 }); 4369 } 4370 4371 TEST(TransferTest, StaticIntGroupVarDecl) { 4372 std::string Code = R"( 4373 void target() { 4374 static int Foo, Bar; 4375 (void)0; 4376 // [[p]] 4377 } 4378 )"; 4379 runDataflow( 4380 Code, 4381 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4382 ASTContext &ASTCtx) { 4383 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4384 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4385 4386 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4387 ASSERT_THAT(FooDecl, NotNull()); 4388 4389 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4390 ASSERT_THAT(BarDecl, NotNull()); 4391 4392 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 4393 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 4394 4395 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 4396 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 4397 4398 const Value *FooVal = Env.getValue(*FooLoc); 4399 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 4400 4401 const Value *BarVal = Env.getValue(*BarLoc); 4402 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 4403 4404 EXPECT_NE(FooVal, BarVal); 4405 }); 4406 } 4407 4408 TEST(TransferTest, GlobalIntVarDecl) { 4409 std::string Code = R"( 4410 static int Foo; 4411 4412 void target() { 4413 int Bar = Foo; 4414 int Baz = Foo; 4415 // [[p]] 4416 } 4417 )"; 4418 runDataflow( 4419 Code, 4420 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4421 ASTContext &ASTCtx) { 4422 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4423 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4424 4425 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4426 ASSERT_THAT(BarDecl, NotNull()); 4427 4428 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4429 ASSERT_THAT(BazDecl, NotNull()); 4430 4431 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 4432 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 4433 EXPECT_EQ(BarVal, BazVal); 4434 }); 4435 } 4436 4437 TEST(TransferTest, StaticMemberIntVarDecl) { 4438 std::string Code = R"( 4439 struct A { 4440 static int Foo; 4441 }; 4442 4443 void target(A a) { 4444 int Bar = a.Foo; 4445 int Baz = a.Foo; 4446 // [[p]] 4447 } 4448 )"; 4449 runDataflow( 4450 Code, 4451 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4452 ASTContext &ASTCtx) { 4453 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4454 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4455 4456 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4457 ASSERT_THAT(BarDecl, NotNull()); 4458 4459 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4460 ASSERT_THAT(BazDecl, NotNull()); 4461 4462 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 4463 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 4464 EXPECT_EQ(BarVal, BazVal); 4465 }); 4466 } 4467 4468 TEST(TransferTest, StaticMemberRefVarDecl) { 4469 std::string Code = R"( 4470 struct A { 4471 static int &Foo; 4472 }; 4473 4474 void target(A a) { 4475 int Bar = a.Foo; 4476 int Baz = a.Foo; 4477 // [[p]] 4478 } 4479 )"; 4480 runDataflow( 4481 Code, 4482 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4483 ASTContext &ASTCtx) { 4484 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4485 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4486 4487 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4488 ASSERT_THAT(BarDecl, NotNull()); 4489 4490 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4491 ASSERT_THAT(BazDecl, NotNull()); 4492 4493 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 4494 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 4495 EXPECT_EQ(BarVal, BazVal); 4496 }); 4497 } 4498 4499 TEST(TransferTest, AssignMemberBeforeCopy) { 4500 std::string Code = R"( 4501 struct A { 4502 int Foo; 4503 }; 4504 4505 void target() { 4506 A A1; 4507 A A2; 4508 int Bar; 4509 A1.Foo = Bar; 4510 A2 = A1; 4511 // [[p]] 4512 } 4513 )"; 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 *FooDecl = findValueDecl(ASTCtx, "Foo"); 4522 ASSERT_THAT(FooDecl, NotNull()); 4523 4524 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4525 ASSERT_THAT(BarDecl, NotNull()); 4526 4527 const ValueDecl *A1Decl = findValueDecl(ASTCtx, "A1"); 4528 ASSERT_THAT(A1Decl, NotNull()); 4529 4530 const ValueDecl *A2Decl = findValueDecl(ASTCtx, "A2"); 4531 ASSERT_THAT(A2Decl, NotNull()); 4532 4533 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 4534 4535 const auto &A2Loc = 4536 *cast<RecordStorageLocation>(Env.getStorageLocation(*A2Decl)); 4537 EXPECT_EQ(getFieldValue(&A2Loc, *FooDecl, Env), BarVal); 4538 }); 4539 } 4540 4541 TEST(TransferTest, BooleanEquality) { 4542 std::string Code = R"( 4543 void target(bool Bar) { 4544 bool Foo = true; 4545 if (Bar == Foo) { 4546 (void)0; 4547 /*[[p-then]]*/ 4548 } else { 4549 (void)0; 4550 /*[[p-else]]*/ 4551 } 4552 } 4553 )"; 4554 runDataflow( 4555 Code, 4556 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4557 ASTContext &ASTCtx) { 4558 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else")); 4559 const Environment &EnvThen = 4560 getEnvironmentAtAnnotation(Results, "p-then"); 4561 const Environment &EnvElse = 4562 getEnvironmentAtAnnotation(Results, "p-else"); 4563 4564 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4565 ASSERT_THAT(BarDecl, NotNull()); 4566 4567 auto &BarValThen = getFormula(*BarDecl, EnvThen); 4568 EXPECT_TRUE(EnvThen.proves(BarValThen)); 4569 4570 auto &BarValElse = getFormula(*BarDecl, EnvElse); 4571 EXPECT_TRUE(EnvElse.proves(EnvElse.arena().makeNot(BarValElse))); 4572 }); 4573 } 4574 4575 TEST(TransferTest, BooleanInequality) { 4576 std::string Code = R"( 4577 void target(bool Bar) { 4578 bool Foo = true; 4579 if (Bar != Foo) { 4580 (void)0; 4581 /*[[p-then]]*/ 4582 } else { 4583 (void)0; 4584 /*[[p-else]]*/ 4585 } 4586 } 4587 )"; 4588 runDataflow( 4589 Code, 4590 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4591 ASTContext &ASTCtx) { 4592 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else")); 4593 const Environment &EnvThen = 4594 getEnvironmentAtAnnotation(Results, "p-then"); 4595 const Environment &EnvElse = 4596 getEnvironmentAtAnnotation(Results, "p-else"); 4597 4598 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4599 ASSERT_THAT(BarDecl, NotNull()); 4600 4601 auto &BarValThen = getFormula(*BarDecl, EnvThen); 4602 EXPECT_TRUE(EnvThen.proves(EnvThen.arena().makeNot(BarValThen))); 4603 4604 auto &BarValElse = getFormula(*BarDecl, EnvElse); 4605 EXPECT_TRUE(EnvElse.proves(BarValElse)); 4606 }); 4607 } 4608 4609 TEST(TransferTest, IntegerLiteralEquality) { 4610 std::string Code = R"( 4611 void target() { 4612 bool equal = (42 == 42); 4613 // [[p]] 4614 } 4615 )"; 4616 runDataflow( 4617 Code, 4618 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4619 ASTContext &ASTCtx) { 4620 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4621 4622 auto &Equal = 4623 getValueForDecl<BoolValue>(ASTCtx, Env, "equal").formula(); 4624 EXPECT_TRUE(Env.proves(Equal)); 4625 }); 4626 } 4627 4628 TEST(TransferTest, CorrelatedBranches) { 4629 std::string Code = R"( 4630 void target(bool B, bool C) { 4631 if (B) { 4632 return; 4633 } 4634 (void)0; 4635 /*[[p0]]*/ 4636 if (C) { 4637 B = true; 4638 /*[[p1]]*/ 4639 } 4640 if (B) { 4641 (void)0; 4642 /*[[p2]]*/ 4643 } 4644 } 4645 )"; 4646 runDataflow( 4647 Code, 4648 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4649 ASTContext &ASTCtx) { 4650 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p0", "p1", "p2")); 4651 4652 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C"); 4653 ASSERT_THAT(CDecl, NotNull()); 4654 4655 { 4656 const Environment &Env = getEnvironmentAtAnnotation(Results, "p0"); 4657 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B"); 4658 ASSERT_THAT(BDecl, NotNull()); 4659 auto &BVal = getFormula(*BDecl, Env); 4660 4661 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BVal))); 4662 } 4663 4664 { 4665 const Environment &Env = getEnvironmentAtAnnotation(Results, "p1"); 4666 auto &CVal = getFormula(*CDecl, Env); 4667 EXPECT_TRUE(Env.proves(CVal)); 4668 } 4669 4670 { 4671 const Environment &Env = getEnvironmentAtAnnotation(Results, "p2"); 4672 auto &CVal = getFormula(*CDecl, Env); 4673 EXPECT_TRUE(Env.proves(CVal)); 4674 } 4675 }); 4676 } 4677 4678 TEST(TransferTest, LoopWithAssignmentConverges) { 4679 std::string Code = R"( 4680 bool foo(); 4681 4682 void target() { 4683 do { 4684 bool Bar = foo(); 4685 if (Bar) break; 4686 (void)Bar; 4687 /*[[p]]*/ 4688 } while (true); 4689 } 4690 )"; 4691 // The key property that we are verifying is implicit in `runDataflow` -- 4692 // namely, that the analysis succeeds, rather than hitting the maximum number 4693 // of iterations. 4694 runDataflow( 4695 Code, 4696 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4697 ASTContext &ASTCtx) { 4698 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4699 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4700 4701 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4702 ASSERT_THAT(BarDecl, NotNull()); 4703 4704 auto &BarVal = getFormula(*BarDecl, Env); 4705 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 4706 }); 4707 } 4708 4709 TEST(TransferTest, LoopWithStagedAssignments) { 4710 std::string Code = R"( 4711 bool foo(); 4712 4713 void target() { 4714 bool Bar = false; 4715 bool Err = false; 4716 while (foo()) { 4717 if (Bar) 4718 Err = true; 4719 Bar = true; 4720 /*[[p]]*/ 4721 } 4722 } 4723 )"; 4724 runDataflow( 4725 Code, 4726 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4727 ASTContext &ASTCtx) { 4728 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4729 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4730 4731 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4732 ASSERT_THAT(BarDecl, NotNull()); 4733 const ValueDecl *ErrDecl = findValueDecl(ASTCtx, "Err"); 4734 ASSERT_THAT(ErrDecl, NotNull()); 4735 4736 auto &BarVal = getFormula(*BarDecl, Env); 4737 auto &ErrVal = getFormula(*ErrDecl, Env); 4738 EXPECT_TRUE(Env.proves(BarVal)); 4739 // An unsound analysis, for example only evaluating the loop once, can 4740 // conclude that `Err` is false. So, we test that this conclusion is not 4741 // reached. 4742 EXPECT_FALSE(Env.proves(Env.arena().makeNot(ErrVal))); 4743 }); 4744 } 4745 4746 TEST(TransferTest, LoopWithReferenceAssignmentConverges) { 4747 std::string Code = R"( 4748 bool &foo(); 4749 4750 void target() { 4751 do { 4752 bool& Bar = foo(); 4753 if (Bar) break; 4754 (void)Bar; 4755 /*[[p]]*/ 4756 } while (true); 4757 } 4758 )"; 4759 // The key property that we are verifying is that the analysis succeeds, 4760 // rather than hitting the maximum number of iterations. 4761 runDataflow( 4762 Code, 4763 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4764 ASTContext &ASTCtx) { 4765 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4766 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4767 4768 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4769 ASSERT_THAT(BarDecl, NotNull()); 4770 4771 auto &BarVal = getFormula(*BarDecl, Env); 4772 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 4773 }); 4774 } 4775 4776 TEST(TransferTest, LoopWithStructReferenceAssignmentConverges) { 4777 std::string Code = R"( 4778 struct Lookup { 4779 int x; 4780 }; 4781 4782 void target(Lookup val, bool b) { 4783 const Lookup* l = nullptr; 4784 while (b) { 4785 l = &val; 4786 /*[[p-inner]]*/ 4787 } 4788 (void)0; 4789 /*[[p-outer]]*/ 4790 } 4791 )"; 4792 // The key property that we are verifying is implicit in `runDataflow` -- 4793 // namely, that the analysis succeeds, rather than hitting the maximum number 4794 // of iterations. 4795 runDataflow( 4796 Code, 4797 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4798 ASTContext &ASTCtx) { 4799 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-inner", "p-outer")); 4800 const Environment &InnerEnv = 4801 getEnvironmentAtAnnotation(Results, "p-inner"); 4802 const Environment &OuterEnv = 4803 getEnvironmentAtAnnotation(Results, "p-outer"); 4804 4805 const ValueDecl *ValDecl = findValueDecl(ASTCtx, "val"); 4806 ASSERT_THAT(ValDecl, NotNull()); 4807 4808 const ValueDecl *LDecl = findValueDecl(ASTCtx, "l"); 4809 ASSERT_THAT(LDecl, NotNull()); 4810 4811 // Inner. 4812 auto *LVal = dyn_cast<PointerValue>(InnerEnv.getValue(*LDecl)); 4813 ASSERT_THAT(LVal, NotNull()); 4814 4815 EXPECT_EQ(&LVal->getPointeeLoc(), 4816 InnerEnv.getStorageLocation(*ValDecl)); 4817 4818 // Outer. 4819 LVal = dyn_cast<PointerValue>(OuterEnv.getValue(*LDecl)); 4820 ASSERT_THAT(LVal, NotNull()); 4821 4822 // The loop body may not have been executed, so we should not conclude 4823 // that `l` points to `val`. 4824 EXPECT_NE(&LVal->getPointeeLoc(), 4825 OuterEnv.getStorageLocation(*ValDecl)); 4826 }); 4827 } 4828 4829 TEST(TransferTest, LoopDereferencingChangingPointerConverges) { 4830 std::string Code = R"cc( 4831 bool some_condition(); 4832 4833 void target(int i1, int i2) { 4834 int *p = &i1; 4835 while (true) { 4836 (void)*p; 4837 if (some_condition()) 4838 p = &i1; 4839 else 4840 p = &i2; 4841 } 4842 } 4843 )cc"; 4844 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 4845 } 4846 4847 TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) { 4848 std::string Code = R"cc( 4849 struct Lookup { 4850 int x; 4851 }; 4852 4853 bool some_condition(); 4854 4855 void target(Lookup l1, Lookup l2) { 4856 Lookup *l = &l1; 4857 while (true) { 4858 (void)l->x; 4859 if (some_condition()) 4860 l = &l1; 4861 else 4862 l = &l2; 4863 } 4864 } 4865 )cc"; 4866 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 4867 } 4868 4869 TEST(TransferTest, LoopWithShortCircuitedConditionConverges) { 4870 std::string Code = R"cc( 4871 bool foo(); 4872 4873 void target() { 4874 bool c = false; 4875 while (foo() || foo()) { 4876 c = true; 4877 } 4878 } 4879 )cc"; 4880 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 4881 } 4882 4883 TEST(TransferTest, LoopCanProveInvariantForBoolean) { 4884 // Check that we can prove `b` is always false in the loop. 4885 // This test exercises the logic in `widenDistinctValues()` that preserves 4886 // information if the boolean can be proved to be either true or false in both 4887 // the previous and current iteration. 4888 std::string Code = R"cc( 4889 int return_int(); 4890 void target() { 4891 bool b = return_int() == 0; 4892 if (b) return; 4893 while (true) { 4894 b; 4895 // [[p]] 4896 b = return_int() == 0; 4897 if (b) return; 4898 } 4899 } 4900 )cc"; 4901 runDataflow( 4902 Code, 4903 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4904 ASTContext &ASTCtx) { 4905 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4906 auto &BVal = getValueForDecl<BoolValue>(ASTCtx, Env, "b"); 4907 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BVal.formula()))); 4908 }); 4909 } 4910 4911 TEST(TransferTest, DoesNotCrashOnUnionThisExpr) { 4912 std::string Code = R"cc( 4913 union Union { 4914 int A; 4915 float B; 4916 }; 4917 4918 void foo() { 4919 Union A; 4920 Union B; 4921 A = B; 4922 } 4923 )cc"; 4924 // This is a crash regression test when calling the transfer function on a 4925 // `CXXThisExpr` that refers to a union. 4926 runDataflow( 4927 Code, 4928 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &, 4929 ASTContext &) {}, 4930 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator="); 4931 } 4932 4933 TEST(TransferTest, DoesNotCrashOnNullChildren) { 4934 std::string Code = (CoroutineLibrary + R"cc( 4935 task target() noexcept { 4936 co_return; 4937 } 4938 )cc") 4939 .str(); 4940 // This is a crash regression test when calling `AdornedCFG::build` on a 4941 // statement (in this case, the `CoroutineBodyStmt`) with null children. 4942 runDataflow( 4943 Code, 4944 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &, 4945 ASTContext &) {}, 4946 LangStandard::lang_cxx20, /*ApplyBuiltinTransfer=*/true); 4947 } 4948 4949 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToRefs) { 4950 std::string Code = R"( 4951 struct A { 4952 int Foo; 4953 int Bar; 4954 }; 4955 4956 void target() { 4957 int Qux; 4958 A Baz; 4959 Baz.Foo = Qux; 4960 auto &FooRef = Baz.Foo; 4961 auto &BarRef = Baz.Bar; 4962 auto &[BoundFooRef, BoundBarRef] = Baz; 4963 // [[p]] 4964 } 4965 )"; 4966 runDataflow( 4967 Code, 4968 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4969 ASTContext &ASTCtx) { 4970 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4971 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4972 4973 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 4974 ASSERT_THAT(FooRefDecl, NotNull()); 4975 4976 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 4977 ASSERT_THAT(BarRefDecl, NotNull()); 4978 4979 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4980 ASSERT_THAT(QuxDecl, NotNull()); 4981 4982 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef"); 4983 ASSERT_THAT(BoundFooRefDecl, NotNull()); 4984 4985 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef"); 4986 ASSERT_THAT(BoundBarRefDecl, NotNull()); 4987 4988 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 4989 ASSERT_THAT(FooRefLoc, NotNull()); 4990 4991 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 4992 ASSERT_THAT(BarRefLoc, NotNull()); 4993 4994 const Value *QuxVal = Env.getValue(*QuxDecl); 4995 ASSERT_THAT(QuxVal, NotNull()); 4996 4997 const StorageLocation *BoundFooRefLoc = 4998 Env.getStorageLocation(*BoundFooRefDecl); 4999 EXPECT_EQ(BoundFooRefLoc, FooRefLoc); 5000 5001 const StorageLocation *BoundBarRefLoc = 5002 Env.getStorageLocation(*BoundBarRefDecl); 5003 EXPECT_EQ(BoundBarRefLoc, BarRefLoc); 5004 5005 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal); 5006 }); 5007 } 5008 5009 TEST(TransferTest, StructuredBindingAssignFromStructRefMembersToRefs) { 5010 std::string Code = R"( 5011 struct A { 5012 int &Foo; 5013 int &Bar; 5014 }; 5015 5016 void target(A Baz) { 5017 int Qux; 5018 Baz.Foo = Qux; 5019 auto &FooRef = Baz.Foo; 5020 auto &BarRef = Baz.Bar; 5021 auto &[BoundFooRef, BoundBarRef] = Baz; 5022 // [[p]] 5023 } 5024 )"; 5025 runDataflow( 5026 Code, 5027 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5028 ASTContext &ASTCtx) { 5029 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5030 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5031 5032 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 5033 ASSERT_THAT(FooRefDecl, NotNull()); 5034 5035 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 5036 ASSERT_THAT(BarRefDecl, NotNull()); 5037 5038 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 5039 ASSERT_THAT(QuxDecl, NotNull()); 5040 5041 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef"); 5042 ASSERT_THAT(BoundFooRefDecl, NotNull()); 5043 5044 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef"); 5045 ASSERT_THAT(BoundBarRefDecl, NotNull()); 5046 5047 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 5048 ASSERT_THAT(FooRefLoc, NotNull()); 5049 5050 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 5051 ASSERT_THAT(BarRefLoc, NotNull()); 5052 5053 const Value *QuxVal = Env.getValue(*QuxDecl); 5054 ASSERT_THAT(QuxVal, NotNull()); 5055 5056 const StorageLocation *BoundFooRefLoc = 5057 Env.getStorageLocation(*BoundFooRefDecl); 5058 EXPECT_EQ(BoundFooRefLoc, FooRefLoc); 5059 5060 const StorageLocation *BoundBarRefLoc = 5061 Env.getStorageLocation(*BoundBarRefDecl); 5062 EXPECT_EQ(BoundBarRefLoc, BarRefLoc); 5063 5064 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal); 5065 }); 5066 } 5067 5068 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToInts) { 5069 std::string Code = R"( 5070 struct A { 5071 int Foo; 5072 int Bar; 5073 }; 5074 5075 void target() { 5076 int Qux; 5077 A Baz; 5078 Baz.Foo = Qux; 5079 auto &FooRef = Baz.Foo; 5080 auto &BarRef = Baz.Bar; 5081 auto [BoundFoo, BoundBar] = Baz; 5082 // [[p]] 5083 } 5084 )"; 5085 runDataflow( 5086 Code, 5087 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5088 ASTContext &ASTCtx) { 5089 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5090 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5091 5092 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 5093 ASSERT_THAT(FooRefDecl, NotNull()); 5094 5095 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 5096 ASSERT_THAT(BarRefDecl, NotNull()); 5097 5098 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 5099 ASSERT_THAT(BoundFooDecl, NotNull()); 5100 5101 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 5102 ASSERT_THAT(BoundBarDecl, NotNull()); 5103 5104 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 5105 ASSERT_THAT(QuxDecl, NotNull()); 5106 5107 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 5108 ASSERT_THAT(FooRefLoc, NotNull()); 5109 5110 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 5111 ASSERT_THAT(BarRefLoc, NotNull()); 5112 5113 const Value *QuxVal = Env.getValue(*QuxDecl); 5114 ASSERT_THAT(QuxVal, NotNull()); 5115 5116 const StorageLocation *BoundFooLoc = 5117 Env.getStorageLocation(*BoundFooDecl); 5118 EXPECT_NE(BoundFooLoc, FooRefLoc); 5119 5120 const StorageLocation *BoundBarLoc = 5121 Env.getStorageLocation(*BoundBarDecl); 5122 EXPECT_NE(BoundBarLoc, BarRefLoc); 5123 5124 EXPECT_EQ(Env.getValue(*BoundFooDecl), QuxVal); 5125 }); 5126 } 5127 5128 TEST(TransferTest, StructuredBindingAssignFromTupleLikeType) { 5129 std::string Code = R"( 5130 namespace std { 5131 using size_t = int; 5132 template <class> struct tuple_size; 5133 template <std::size_t, class> struct tuple_element; 5134 template <class...> class tuple; 5135 5136 namespace { 5137 template <class T, T v> 5138 struct size_helper { static const T value = v; }; 5139 } // namespace 5140 5141 template <class... T> 5142 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {}; 5143 5144 template <std::size_t I, class... T> 5145 struct tuple_element<I, tuple<T...>> { 5146 using type = __type_pack_element<I, T...>; 5147 }; 5148 5149 template <class...> class tuple {}; 5150 5151 template <std::size_t I, class... T> 5152 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 5153 } // namespace std 5154 5155 std::tuple<bool, int> makeTuple(); 5156 5157 void target(bool B) { 5158 auto [BoundFoo, BoundBar] = makeTuple(); 5159 bool Baz; 5160 // Include if-then-else to test interaction of `BindingDecl` with join. 5161 if (B) { 5162 Baz = BoundFoo; 5163 (void)BoundBar; 5164 // [[p1]] 5165 } else { 5166 Baz = BoundFoo; 5167 } 5168 (void)0; 5169 // [[p2]] 5170 } 5171 )"; 5172 runDataflow( 5173 Code, 5174 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5175 ASTContext &ASTCtx) { 5176 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 5177 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 5178 5179 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 5180 ASSERT_THAT(BoundFooDecl, NotNull()); 5181 5182 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 5183 ASSERT_THAT(BoundBarDecl, NotNull()); 5184 5185 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5186 ASSERT_THAT(BazDecl, NotNull()); 5187 5188 // BindingDecls always map to references -- either lvalue or rvalue, so 5189 // we still need to skip here. 5190 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl); 5191 ASSERT_THAT(BoundFooValue, NotNull()); 5192 EXPECT_TRUE(isa<BoolValue>(BoundFooValue)); 5193 5194 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl); 5195 ASSERT_THAT(BoundBarValue, NotNull()); 5196 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue)); 5197 5198 // Test that a `DeclRefExpr` to a `BindingDecl` works as expected. 5199 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue); 5200 5201 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 5202 5203 // Test that `BoundFooDecl` retains the value we expect, after the join. 5204 BoundFooValue = Env2.getValue(*BoundFooDecl); 5205 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue); 5206 }); 5207 } 5208 5209 TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) { 5210 std::string Code = R"( 5211 namespace std { 5212 using size_t = int; 5213 template <class> struct tuple_size; 5214 template <std::size_t, class> struct tuple_element; 5215 template <class...> class tuple; 5216 5217 namespace { 5218 template <class T, T v> 5219 struct size_helper { static const T value = v; }; 5220 } // namespace 5221 5222 template <class... T> 5223 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {}; 5224 5225 template <std::size_t I, class... T> 5226 struct tuple_element<I, tuple<T...>> { 5227 using type = __type_pack_element<I, T...>; 5228 }; 5229 5230 template <class...> class tuple {}; 5231 5232 template <std::size_t I, class... T> 5233 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 5234 } // namespace std 5235 5236 std::tuple<bool, int> &getTuple(); 5237 5238 void target(bool B) { 5239 auto &[BoundFoo, BoundBar] = getTuple(); 5240 bool Baz; 5241 // Include if-then-else to test interaction of `BindingDecl` with join. 5242 if (B) { 5243 Baz = BoundFoo; 5244 (void)BoundBar; 5245 // [[p1]] 5246 } else { 5247 Baz = BoundFoo; 5248 } 5249 (void)0; 5250 // [[p2]] 5251 } 5252 )"; 5253 runDataflow( 5254 Code, 5255 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5256 ASTContext &ASTCtx) { 5257 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 5258 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 5259 5260 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 5261 ASSERT_THAT(BoundFooDecl, NotNull()); 5262 5263 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 5264 ASSERT_THAT(BoundBarDecl, NotNull()); 5265 5266 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5267 ASSERT_THAT(BazDecl, NotNull()); 5268 5269 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl); 5270 ASSERT_THAT(BoundFooValue, NotNull()); 5271 EXPECT_TRUE(isa<BoolValue>(BoundFooValue)); 5272 5273 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl); 5274 ASSERT_THAT(BoundBarValue, NotNull()); 5275 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue)); 5276 5277 // Test that a `DeclRefExpr` to a `BindingDecl` (with reference type) 5278 // works as expected. We don't test aliasing properties of the 5279 // reference, because we don't model `std::get` and so have no way to 5280 // equate separate references into the tuple. 5281 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue); 5282 5283 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 5284 5285 // Test that `BoundFooDecl` retains the value we expect, after the join. 5286 BoundFooValue = Env2.getValue(*BoundFooDecl); 5287 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue); 5288 }); 5289 } 5290 5291 TEST(TransferTest, BinaryOperatorComma) { 5292 std::string Code = R"( 5293 void target(int Foo, int Bar) { 5294 int &Baz = (Foo, Bar); 5295 // [[p]] 5296 } 5297 )"; 5298 runDataflow( 5299 Code, 5300 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5301 ASTContext &ASTCtx) { 5302 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5303 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5304 5305 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5306 ASSERT_THAT(BarDecl, NotNull()); 5307 5308 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5309 ASSERT_THAT(BazDecl, NotNull()); 5310 5311 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 5312 ASSERT_THAT(BarLoc, NotNull()); 5313 5314 const StorageLocation *BazLoc = Env.getStorageLocation(*BazDecl); 5315 EXPECT_EQ(BazLoc, BarLoc); 5316 }); 5317 } 5318 5319 TEST(TransferTest, IfStmtBranchExtendsFlowCondition) { 5320 std::string Code = R"( 5321 void target(bool Foo) { 5322 if (Foo) { 5323 (void)0; 5324 // [[if_then]] 5325 } else { 5326 (void)0; 5327 // [[if_else]] 5328 } 5329 } 5330 )"; 5331 runDataflow( 5332 Code, 5333 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5334 ASTContext &ASTCtx) { 5335 ASSERT_THAT(Results.keys(), UnorderedElementsAre("if_then", "if_else")); 5336 const Environment &ThenEnv = 5337 getEnvironmentAtAnnotation(Results, "if_then"); 5338 const Environment &ElseEnv = 5339 getEnvironmentAtAnnotation(Results, "if_else"); 5340 5341 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5342 ASSERT_THAT(FooDecl, NotNull()); 5343 5344 auto &ThenFooVal= getFormula(*FooDecl, ThenEnv); 5345 EXPECT_TRUE(ThenEnv.proves(ThenFooVal)); 5346 5347 auto &ElseFooVal = getFormula(*FooDecl, ElseEnv); 5348 EXPECT_TRUE(ElseEnv.proves(ElseEnv.arena().makeNot(ElseFooVal))); 5349 }); 5350 } 5351 5352 TEST(TransferTest, WhileStmtBranchExtendsFlowCondition) { 5353 std::string Code = R"( 5354 void target(bool Foo) { 5355 while (Foo) { 5356 (void)0; 5357 // [[loop_body]] 5358 } 5359 (void)0; 5360 // [[after_loop]] 5361 } 5362 )"; 5363 runDataflow( 5364 Code, 5365 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5366 ASTContext &ASTCtx) { 5367 ASSERT_THAT(Results.keys(), 5368 UnorderedElementsAre("loop_body", "after_loop")); 5369 const Environment &LoopBodyEnv = 5370 getEnvironmentAtAnnotation(Results, "loop_body"); 5371 const Environment &AfterLoopEnv = 5372 getEnvironmentAtAnnotation(Results, "after_loop"); 5373 5374 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5375 ASSERT_THAT(FooDecl, NotNull()); 5376 5377 auto &LoopBodyFooVal = getFormula(*FooDecl, LoopBodyEnv); 5378 EXPECT_TRUE(LoopBodyEnv.proves(LoopBodyFooVal)); 5379 5380 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 5381 EXPECT_TRUE( 5382 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal))); 5383 }); 5384 } 5385 5386 TEST(TransferTest, DoWhileStmtBranchExtendsFlowCondition) { 5387 std::string Code = R"( 5388 void target(bool Foo) { 5389 bool Bar = true; 5390 do { 5391 (void)0; 5392 // [[loop_body]] 5393 Bar = false; 5394 } while (Foo); 5395 (void)0; 5396 // [[after_loop]] 5397 } 5398 )"; 5399 runDataflow( 5400 Code, 5401 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5402 ASTContext &ASTCtx) { 5403 ASSERT_THAT(Results.keys(), 5404 UnorderedElementsAre("loop_body", "after_loop")); 5405 const Environment &LoopBodyEnv = 5406 getEnvironmentAtAnnotation(Results, "loop_body"); 5407 const Environment &AfterLoopEnv = 5408 getEnvironmentAtAnnotation(Results, "after_loop"); 5409 auto &A = AfterLoopEnv.arena(); 5410 5411 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5412 ASSERT_THAT(FooDecl, NotNull()); 5413 5414 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5415 ASSERT_THAT(BarDecl, NotNull()); 5416 5417 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 5418 auto &LoopBodyBarVal = getFormula(*BarDecl, LoopBodyEnv); 5419 EXPECT_TRUE( 5420 LoopBodyEnv.proves(A.makeOr(LoopBodyBarVal, LoopBodyFooVal))); 5421 5422 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 5423 auto &AfterLoopBarVal = getFormula(*BarDecl, AfterLoopEnv); 5424 EXPECT_TRUE(AfterLoopEnv.proves(A.makeNot(AfterLoopFooVal))); 5425 EXPECT_TRUE(AfterLoopEnv.proves(A.makeNot(AfterLoopBarVal))); 5426 }); 5427 } 5428 5429 TEST(TransferTest, ForStmtBranchExtendsFlowCondition) { 5430 std::string Code = R"( 5431 void target(bool Foo) { 5432 for (; Foo;) { 5433 (void)0; 5434 // [[loop_body]] 5435 } 5436 (void)0; 5437 // [[after_loop]] 5438 } 5439 )"; 5440 runDataflow( 5441 Code, 5442 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5443 ASTContext &ASTCtx) { 5444 ASSERT_THAT(Results.keys(), 5445 UnorderedElementsAre("loop_body", "after_loop")); 5446 const Environment &LoopBodyEnv = 5447 getEnvironmentAtAnnotation(Results, "loop_body"); 5448 const Environment &AfterLoopEnv = 5449 getEnvironmentAtAnnotation(Results, "after_loop"); 5450 5451 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5452 ASSERT_THAT(FooDecl, NotNull()); 5453 5454 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 5455 EXPECT_TRUE(LoopBodyEnv.proves(LoopBodyFooVal)); 5456 5457 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 5458 EXPECT_TRUE( 5459 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal))); 5460 }); 5461 } 5462 5463 TEST(TransferTest, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition) { 5464 std::string Code = R"( 5465 void target(bool Foo) { 5466 for (;;) { 5467 (void)0; 5468 // [[loop_body]] 5469 } 5470 } 5471 )"; 5472 runDataflow( 5473 Code, 5474 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5475 ASTContext &ASTCtx) { 5476 ASSERT_THAT(Results.keys(), UnorderedElementsAre("loop_body")); 5477 const Environment &LoopBodyEnv = 5478 getEnvironmentAtAnnotation(Results, "loop_body"); 5479 5480 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5481 ASSERT_THAT(FooDecl, NotNull()); 5482 5483 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 5484 EXPECT_FALSE(LoopBodyEnv.proves(LoopBodyFooVal)); 5485 }); 5486 } 5487 5488 TEST(TransferTest, ContextSensitiveOptionDisabled) { 5489 std::string Code = R"( 5490 bool GiveBool(); 5491 void SetBool(bool &Var) { Var = true; } 5492 5493 void target() { 5494 bool Foo = GiveBool(); 5495 SetBool(Foo); 5496 // [[p]] 5497 } 5498 )"; 5499 runDataflow( 5500 Code, 5501 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5502 ASTContext &ASTCtx) { 5503 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5504 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5505 5506 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5507 ASSERT_THAT(FooDecl, NotNull()); 5508 5509 auto &FooVal = getFormula(*FooDecl, Env); 5510 EXPECT_FALSE(Env.proves(FooVal)); 5511 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5512 }, 5513 {BuiltinOptions{/*.ContextSensitiveOpts=*/std::nullopt}}); 5514 } 5515 5516 TEST(TransferTest, ContextSensitiveReturnReference) { 5517 std::string Code = R"( 5518 class S {}; 5519 S& target(bool b, S &s) { 5520 return s; 5521 // [[p]] 5522 } 5523 )"; 5524 runDataflow( 5525 Code, 5526 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5527 ASTContext &ASTCtx) { 5528 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5529 5530 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 5531 ASSERT_THAT(SDecl, NotNull()); 5532 5533 auto *SLoc = Env.getStorageLocation(*SDecl); 5534 ASSERT_THAT(SLoc, NotNull()); 5535 5536 ASSERT_THAT(Env.getReturnStorageLocation(), Eq(SLoc)); 5537 }, 5538 {BuiltinOptions{ContextSensitiveOptions{}}}); 5539 } 5540 5541 // This test is a regression test, based on a real crash. 5542 TEST(TransferTest, ContextSensitiveReturnReferenceWithConditionalOperator) { 5543 std::string Code = R"( 5544 class S {}; 5545 S& target(bool b, S &s) { 5546 return b ? s : s; 5547 // [[p]] 5548 } 5549 )"; 5550 runDataflow( 5551 Code, 5552 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5553 ASTContext &ASTCtx) { 5554 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5555 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5556 5557 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 5558 ASSERT_THAT(SDecl, NotNull()); 5559 5560 auto *SLoc = Env.getStorageLocation(*SDecl); 5561 ASSERT_THAT(SLoc, NotNull()); 5562 EXPECT_THAT(Env.getValue(*SLoc), NotNull()); 5563 5564 auto *Loc = Env.getReturnStorageLocation(); 5565 ASSERT_THAT(Loc, NotNull()); 5566 EXPECT_THAT(Env.getValue(*Loc), NotNull()); 5567 5568 // TODO: We would really like to make this stronger assertion, but that 5569 // doesn't work because we don't propagate values correctly through 5570 // the conditional operator yet. 5571 // ASSERT_THAT(Loc, Eq(SLoc)); 5572 }, 5573 {BuiltinOptions{ContextSensitiveOptions{}}}); 5574 } 5575 5576 TEST(TransferTest, ContextSensitiveReturnOneOfTwoReferences) { 5577 std::string Code = R"( 5578 class S {}; 5579 S &callee(bool b, S &s1_parm, S &s2_parm) { 5580 if (b) 5581 return s1_parm; 5582 else 5583 return s2_parm; 5584 } 5585 void target(bool b) { 5586 S s1; 5587 S s2; 5588 S &return_s1 = s1; 5589 S &return_s2 = s2; 5590 S &return_dont_know = callee(b, s1, s2); 5591 // [[p]] 5592 } 5593 )"; 5594 runDataflow( 5595 Code, 5596 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5597 ASTContext &ASTCtx) { 5598 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5599 5600 const ValueDecl *S1 = findValueDecl(ASTCtx, "s1"); 5601 ASSERT_THAT(S1, NotNull()); 5602 const ValueDecl *S2 = findValueDecl(ASTCtx, "s2"); 5603 ASSERT_THAT(S2, NotNull()); 5604 const ValueDecl *ReturnS1 = findValueDecl(ASTCtx, "return_s1"); 5605 ASSERT_THAT(ReturnS1, NotNull()); 5606 const ValueDecl *ReturnS2 = findValueDecl(ASTCtx, "return_s2"); 5607 ASSERT_THAT(ReturnS2, NotNull()); 5608 const ValueDecl *ReturnDontKnow = 5609 findValueDecl(ASTCtx, "return_dont_know"); 5610 ASSERT_THAT(ReturnDontKnow, NotNull()); 5611 5612 StorageLocation *S1Loc = Env.getStorageLocation(*S1); 5613 StorageLocation *S2Loc = Env.getStorageLocation(*S2); 5614 5615 EXPECT_THAT(Env.getStorageLocation(*ReturnS1), Eq(S1Loc)); 5616 EXPECT_THAT(Env.getStorageLocation(*ReturnS2), Eq(S2Loc)); 5617 5618 // In the case where we don't have a consistent storage location for 5619 // the return value, the framework creates a new storage location, which 5620 // should be different from the storage locations of `s1` and `s2`. 5621 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S1Loc)); 5622 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S2Loc)); 5623 }, 5624 {BuiltinOptions{ContextSensitiveOptions{}}}); 5625 } 5626 5627 TEST(TransferTest, ContextSensitiveDepthZero) { 5628 std::string Code = R"( 5629 bool GiveBool(); 5630 void SetBool(bool &Var) { Var = true; } 5631 5632 void target() { 5633 bool Foo = GiveBool(); 5634 SetBool(Foo); 5635 // [[p]] 5636 } 5637 )"; 5638 runDataflow( 5639 Code, 5640 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5641 ASTContext &ASTCtx) { 5642 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5643 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5644 5645 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5646 ASSERT_THAT(FooDecl, NotNull()); 5647 5648 auto &FooVal = getFormula(*FooDecl, Env); 5649 EXPECT_FALSE(Env.proves(FooVal)); 5650 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5651 }, 5652 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/0}}}); 5653 } 5654 5655 TEST(TransferTest, ContextSensitiveSetTrue) { 5656 std::string Code = R"( 5657 bool GiveBool(); 5658 void SetBool(bool &Var) { Var = true; } 5659 5660 void target() { 5661 bool Foo = GiveBool(); 5662 SetBool(Foo); 5663 // [[p]] 5664 } 5665 )"; 5666 runDataflow( 5667 Code, 5668 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5669 ASTContext &ASTCtx) { 5670 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5671 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5672 5673 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5674 ASSERT_THAT(FooDecl, NotNull()); 5675 5676 auto &FooVal = getFormula(*FooDecl, Env); 5677 EXPECT_TRUE(Env.proves(FooVal)); 5678 }, 5679 {BuiltinOptions{ContextSensitiveOptions{}}}); 5680 } 5681 5682 TEST(TransferTest, ContextSensitiveSetFalse) { 5683 std::string Code = R"( 5684 bool GiveBool(); 5685 void SetBool(bool &Var) { Var = false; } 5686 5687 void target() { 5688 bool Foo = GiveBool(); 5689 SetBool(Foo); 5690 // [[p]] 5691 } 5692 )"; 5693 runDataflow( 5694 Code, 5695 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5696 ASTContext &ASTCtx) { 5697 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5698 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5699 5700 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5701 ASSERT_THAT(FooDecl, NotNull()); 5702 5703 auto &FooVal = getFormula(*FooDecl, Env); 5704 EXPECT_TRUE(Env.proves(Env.arena().makeNot(FooVal))); 5705 }, 5706 {BuiltinOptions{ContextSensitiveOptions{}}}); 5707 } 5708 5709 TEST(TransferTest, ContextSensitiveSetBothTrueAndFalse) { 5710 std::string Code = R"( 5711 bool GiveBool(); 5712 void SetBool(bool &Var, bool Val) { Var = Val; } 5713 5714 void target() { 5715 bool Foo = GiveBool(); 5716 bool Bar = GiveBool(); 5717 SetBool(Foo, true); 5718 SetBool(Bar, false); 5719 // [[p]] 5720 } 5721 )"; 5722 runDataflow( 5723 Code, 5724 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5725 ASTContext &ASTCtx) { 5726 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5727 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5728 auto &A = Env.arena(); 5729 5730 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5731 ASSERT_THAT(FooDecl, NotNull()); 5732 5733 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5734 ASSERT_THAT(BarDecl, NotNull()); 5735 5736 auto &FooVal = getFormula(*FooDecl, Env); 5737 EXPECT_TRUE(Env.proves(FooVal)); 5738 EXPECT_FALSE(Env.proves(A.makeNot(FooVal))); 5739 5740 auto &BarVal = getFormula(*BarDecl, Env); 5741 EXPECT_FALSE(Env.proves(BarVal)); 5742 EXPECT_TRUE(Env.proves(A.makeNot(BarVal))); 5743 }, 5744 {BuiltinOptions{ContextSensitiveOptions{}}}); 5745 } 5746 5747 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthOne) { 5748 std::string Code = R"( 5749 bool GiveBool(); 5750 void SetBool1(bool &Var) { Var = true; } 5751 void SetBool2(bool &Var) { SetBool1(Var); } 5752 5753 void target() { 5754 bool Foo = GiveBool(); 5755 SetBool2(Foo); 5756 // [[p]] 5757 } 5758 )"; 5759 runDataflow( 5760 Code, 5761 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5762 ASTContext &ASTCtx) { 5763 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5764 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5765 5766 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5767 ASSERT_THAT(FooDecl, NotNull()); 5768 5769 auto &FooVal = getFormula(*FooDecl, Env); 5770 EXPECT_FALSE(Env.proves(FooVal)); 5771 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5772 }, 5773 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/1}}}); 5774 } 5775 5776 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthTwo) { 5777 std::string Code = R"( 5778 bool GiveBool(); 5779 void SetBool1(bool &Var) { Var = true; } 5780 void SetBool2(bool &Var) { SetBool1(Var); } 5781 5782 void target() { 5783 bool Foo = GiveBool(); 5784 SetBool2(Foo); 5785 // [[p]] 5786 } 5787 )"; 5788 runDataflow( 5789 Code, 5790 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5791 ASTContext &ASTCtx) { 5792 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5793 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5794 5795 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5796 ASSERT_THAT(FooDecl, NotNull()); 5797 5798 auto &FooVal = getFormula(*FooDecl, Env); 5799 EXPECT_TRUE(Env.proves(FooVal)); 5800 }, 5801 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}}); 5802 } 5803 5804 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthTwo) { 5805 std::string Code = R"( 5806 bool GiveBool(); 5807 void SetBool1(bool &Var) { Var = true; } 5808 void SetBool2(bool &Var) { SetBool1(Var); } 5809 void SetBool3(bool &Var) { SetBool2(Var); } 5810 5811 void target() { 5812 bool Foo = GiveBool(); 5813 SetBool3(Foo); 5814 // [[p]] 5815 } 5816 )"; 5817 runDataflow( 5818 Code, 5819 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5820 ASTContext &ASTCtx) { 5821 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5822 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5823 5824 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5825 ASSERT_THAT(FooDecl, NotNull()); 5826 5827 auto &FooVal = getFormula(*FooDecl, Env); 5828 EXPECT_FALSE(Env.proves(FooVal)); 5829 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5830 }, 5831 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}}); 5832 } 5833 5834 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthThree) { 5835 std::string Code = R"( 5836 bool GiveBool(); 5837 void SetBool1(bool &Var) { Var = true; } 5838 void SetBool2(bool &Var) { SetBool1(Var); } 5839 void SetBool3(bool &Var) { SetBool2(Var); } 5840 5841 void target() { 5842 bool Foo = GiveBool(); 5843 SetBool3(Foo); 5844 // [[p]] 5845 } 5846 )"; 5847 runDataflow( 5848 Code, 5849 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5850 ASTContext &ASTCtx) { 5851 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5852 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5853 5854 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5855 ASSERT_THAT(FooDecl, NotNull()); 5856 5857 auto &FooVal = getFormula(*FooDecl, Env); 5858 EXPECT_TRUE(Env.proves(FooVal)); 5859 }, 5860 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/3}}}); 5861 } 5862 5863 TEST(TransferTest, ContextSensitiveMutualRecursion) { 5864 std::string Code = R"( 5865 bool Pong(bool X, bool Y); 5866 5867 bool Ping(bool X, bool Y) { 5868 if (X) { 5869 return Y; 5870 } else { 5871 return Pong(!X, Y); 5872 } 5873 } 5874 5875 bool Pong(bool X, bool Y) { 5876 if (Y) { 5877 return X; 5878 } else { 5879 return Ping(X, !Y); 5880 } 5881 } 5882 5883 void target() { 5884 bool Foo = Ping(false, false); 5885 // [[p]] 5886 } 5887 )"; 5888 runDataflow( 5889 Code, 5890 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5891 ASTContext &ASTCtx) { 5892 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5893 // The analysis doesn't crash... 5894 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5895 5896 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5897 ASSERT_THAT(FooDecl, NotNull()); 5898 5899 auto &FooVal = getFormula(*FooDecl, Env); 5900 // ... but it also can't prove anything here. 5901 EXPECT_FALSE(Env.proves(FooVal)); 5902 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5903 }, 5904 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/4}}}); 5905 } 5906 5907 TEST(TransferTest, ContextSensitiveSetMultipleLines) { 5908 std::string Code = R"( 5909 void SetBools(bool &Var1, bool &Var2) { 5910 Var1 = true; 5911 Var2 = false; 5912 } 5913 5914 void target() { 5915 bool Foo = false; 5916 bool Bar = true; 5917 SetBools(Foo, Bar); 5918 // [[p]] 5919 } 5920 )"; 5921 runDataflow( 5922 Code, 5923 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5924 ASTContext &ASTCtx) { 5925 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5926 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5927 5928 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5929 ASSERT_THAT(FooDecl, NotNull()); 5930 5931 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5932 ASSERT_THAT(BarDecl, NotNull()); 5933 5934 auto &FooVal = getFormula(*FooDecl, Env); 5935 EXPECT_TRUE(Env.proves(FooVal)); 5936 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5937 5938 auto &BarVal = getFormula(*BarDecl, Env); 5939 EXPECT_FALSE(Env.proves(BarVal)); 5940 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 5941 }, 5942 {BuiltinOptions{ContextSensitiveOptions{}}}); 5943 } 5944 5945 TEST(TransferTest, ContextSensitiveSetMultipleBlocks) { 5946 std::string Code = R"( 5947 void IfCond(bool Cond, bool &Then, bool &Else) { 5948 if (Cond) { 5949 Then = true; 5950 } else { 5951 Else = true; 5952 } 5953 } 5954 5955 void target() { 5956 bool Foo = false; 5957 bool Bar = false; 5958 bool Baz = false; 5959 IfCond(Foo, Bar, Baz); 5960 // [[p]] 5961 } 5962 )"; 5963 runDataflow( 5964 Code, 5965 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5966 ASTContext &ASTCtx) { 5967 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5968 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5969 5970 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5971 ASSERT_THAT(BarDecl, NotNull()); 5972 5973 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5974 ASSERT_THAT(BazDecl, NotNull()); 5975 5976 auto &BarVal = getFormula(*BarDecl, Env); 5977 EXPECT_FALSE(Env.proves(BarVal)); 5978 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 5979 5980 auto &BazVal = getFormula(*BazDecl, Env); 5981 EXPECT_TRUE(Env.proves(BazVal)); 5982 EXPECT_FALSE(Env.proves(Env.arena().makeNot(BazVal))); 5983 }, 5984 {BuiltinOptions{ContextSensitiveOptions{}}}); 5985 } 5986 5987 TEST(TransferTest, ContextSensitiveReturnVoid) { 5988 std::string Code = R"( 5989 void Noop() { return; } 5990 5991 void target() { 5992 Noop(); 5993 // [[p]] 5994 } 5995 )"; 5996 runDataflow( 5997 Code, 5998 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5999 ASTContext &ASTCtx) { 6000 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6001 // This just tests that the analysis doesn't crash. 6002 }, 6003 {BuiltinOptions{ContextSensitiveOptions{}}}); 6004 } 6005 6006 TEST(TransferTest, ContextSensitiveReturnTrue) { 6007 std::string Code = R"( 6008 bool GiveBool() { return true; } 6009 6010 void target() { 6011 bool Foo = GiveBool(); 6012 // [[p]] 6013 } 6014 )"; 6015 runDataflow( 6016 Code, 6017 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6018 ASTContext &ASTCtx) { 6019 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6020 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6021 6022 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6023 ASSERT_THAT(FooDecl, NotNull()); 6024 6025 auto &FooVal = getFormula(*FooDecl, Env); 6026 EXPECT_TRUE(Env.proves(FooVal)); 6027 }, 6028 {BuiltinOptions{ContextSensitiveOptions{}}}); 6029 } 6030 6031 TEST(TransferTest, ContextSensitiveReturnFalse) { 6032 std::string Code = R"( 6033 bool GiveBool() { return false; } 6034 6035 void target() { 6036 bool Foo = GiveBool(); 6037 // [[p]] 6038 } 6039 )"; 6040 runDataflow( 6041 Code, 6042 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6043 ASTContext &ASTCtx) { 6044 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6045 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6046 6047 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6048 ASSERT_THAT(FooDecl, NotNull()); 6049 6050 auto &FooVal = getFormula(*FooDecl, Env); 6051 EXPECT_TRUE(Env.proves(Env.arena().makeNot(FooVal))); 6052 }, 6053 {BuiltinOptions{ContextSensitiveOptions{}}}); 6054 } 6055 6056 TEST(TransferTest, ContextSensitiveReturnArg) { 6057 std::string Code = R"( 6058 bool GiveBool(); 6059 bool GiveBack(bool Arg) { return Arg; } 6060 6061 void target() { 6062 bool Foo = GiveBool(); 6063 bool Bar = GiveBack(Foo); 6064 bool Baz = Foo == Bar; 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 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6074 6075 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 6076 ASSERT_THAT(BazDecl, NotNull()); 6077 6078 auto &BazVal = getFormula(*BazDecl, Env); 6079 EXPECT_TRUE(Env.proves(BazVal)); 6080 }, 6081 {BuiltinOptions{ContextSensitiveOptions{}}}); 6082 } 6083 6084 TEST(TransferTest, ContextSensitiveReturnInt) { 6085 std::string Code = R"( 6086 int identity(int x) { return x; } 6087 6088 void target() { 6089 int y = identity(42); 6090 // [[p]] 6091 } 6092 )"; 6093 runDataflow( 6094 Code, 6095 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6096 ASTContext &ASTCtx) { 6097 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6098 // This just tests that the analysis doesn't crash. 6099 }, 6100 {BuiltinOptions{ContextSensitiveOptions{}}}); 6101 } 6102 6103 TEST(TransferTest, ContextSensitiveReturnRecord) { 6104 std::string Code = R"( 6105 struct S { 6106 bool B; 6107 }; 6108 6109 S makeS(bool BVal) { return {BVal}; } 6110 6111 void target() { 6112 S FalseS = makeS(false); 6113 S TrueS = makeS(true); 6114 // [[p]] 6115 } 6116 )"; 6117 runDataflow( 6118 Code, 6119 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6120 ASTContext &ASTCtx) { 6121 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6122 6123 auto &FalseSLoc = 6124 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "FalseS"); 6125 auto &TrueSLoc = 6126 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "TrueS"); 6127 6128 EXPECT_EQ(getFieldValue(&FalseSLoc, "B", ASTCtx, Env), 6129 &Env.getBoolLiteralValue(false)); 6130 EXPECT_EQ(getFieldValue(&TrueSLoc, "B", ASTCtx, Env), 6131 &Env.getBoolLiteralValue(true)); 6132 }, 6133 {BuiltinOptions{ContextSensitiveOptions{}}}); 6134 } 6135 6136 TEST(TransferTest, ContextSensitiveReturnSelfReferentialRecord) { 6137 std::string Code = R"( 6138 struct S { 6139 S() { self = this; } 6140 S *self; 6141 }; 6142 6143 S makeS() { 6144 // RVO guarantees that this will be constructed directly into `MyS`. 6145 return S(); 6146 } 6147 6148 void target() { 6149 S MyS = makeS(); 6150 // [[p]] 6151 } 6152 )"; 6153 runDataflow( 6154 Code, 6155 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6156 ASTContext &ASTCtx) { 6157 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6158 6159 auto &MySLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "MyS"); 6160 6161 auto *SelfVal = 6162 cast<PointerValue>(getFieldValue(&MySLoc, "self", ASTCtx, Env)); 6163 EXPECT_EQ(&SelfVal->getPointeeLoc(), &MySLoc); 6164 }, 6165 {BuiltinOptions{ContextSensitiveOptions{}}}); 6166 } 6167 6168 TEST(TransferTest, ContextSensitiveMethodLiteral) { 6169 std::string Code = R"( 6170 class MyClass { 6171 public: 6172 bool giveBool() { return true; } 6173 }; 6174 6175 void target() { 6176 MyClass MyObj; 6177 bool Foo = MyObj.giveBool(); 6178 // [[p]] 6179 } 6180 )"; 6181 runDataflow( 6182 Code, 6183 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6184 ASTContext &ASTCtx) { 6185 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6186 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6187 6188 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6189 ASSERT_THAT(FooDecl, NotNull()); 6190 6191 auto &FooVal = getFormula(*FooDecl, Env); 6192 EXPECT_TRUE(Env.proves(FooVal)); 6193 }, 6194 {BuiltinOptions{ContextSensitiveOptions{}}}); 6195 } 6196 6197 TEST(TransferTest, ContextSensitiveMethodGetter) { 6198 std::string Code = R"( 6199 class MyClass { 6200 public: 6201 bool getField() { return Field; } 6202 6203 bool Field; 6204 }; 6205 6206 void target() { 6207 MyClass MyObj; 6208 MyObj.Field = true; 6209 bool Foo = MyObj.getField(); 6210 // [[p]] 6211 } 6212 )"; 6213 runDataflow( 6214 Code, 6215 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6216 ASTContext &ASTCtx) { 6217 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6218 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6219 6220 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6221 ASSERT_THAT(FooDecl, NotNull()); 6222 6223 auto &FooVal = getFormula(*FooDecl, Env); 6224 EXPECT_TRUE(Env.proves(FooVal)); 6225 }, 6226 {BuiltinOptions{ContextSensitiveOptions{}}}); 6227 } 6228 6229 TEST(TransferTest, ContextSensitiveMethodSetter) { 6230 std::string Code = R"( 6231 class MyClass { 6232 public: 6233 void setField(bool Val) { Field = Val; } 6234 6235 bool Field; 6236 }; 6237 6238 void target() { 6239 MyClass MyObj; 6240 MyObj.setField(true); 6241 bool Foo = MyObj.Field; 6242 // [[p]] 6243 } 6244 )"; 6245 runDataflow( 6246 Code, 6247 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6248 ASTContext &ASTCtx) { 6249 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6250 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6251 6252 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6253 ASSERT_THAT(FooDecl, NotNull()); 6254 6255 auto &FooVal = getFormula(*FooDecl, Env); 6256 EXPECT_TRUE(Env.proves(FooVal)); 6257 }, 6258 {BuiltinOptions{ContextSensitiveOptions{}}}); 6259 } 6260 6261 TEST(TransferTest, ContextSensitiveMethodGetterAndSetter) { 6262 std::string Code = R"( 6263 class MyClass { 6264 public: 6265 bool getField() { return Field; } 6266 void setField(bool Val) { Field = Val; } 6267 6268 private: 6269 bool Field; 6270 }; 6271 6272 void target() { 6273 MyClass MyObj; 6274 MyObj.setField(true); 6275 bool Foo = MyObj.getField(); 6276 // [[p]] 6277 } 6278 )"; 6279 runDataflow( 6280 Code, 6281 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6282 ASTContext &ASTCtx) { 6283 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6284 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6285 6286 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6287 ASSERT_THAT(FooDecl, NotNull()); 6288 6289 auto &FooVal = getFormula(*FooDecl, Env); 6290 EXPECT_TRUE(Env.proves(FooVal)); 6291 }, 6292 {BuiltinOptions{ContextSensitiveOptions{}}}); 6293 } 6294 6295 6296 TEST(TransferTest, ContextSensitiveMethodTwoLayersVoid) { 6297 std::string Code = R"( 6298 class MyClass { 6299 public: 6300 void Inner() { MyField = true; } 6301 void Outer() { Inner(); } 6302 6303 bool MyField; 6304 }; 6305 6306 void target() { 6307 MyClass MyObj; 6308 MyObj.Outer(); 6309 bool Foo = MyObj.MyField; 6310 // [[p]] 6311 } 6312 )"; 6313 runDataflow( 6314 Code, 6315 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6316 ASTContext &ASTCtx) { 6317 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6318 ; 6319 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6320 6321 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6322 ASSERT_THAT(FooDecl, NotNull()); 6323 6324 auto &FooVal = getFormula(*FooDecl, Env); 6325 EXPECT_TRUE(Env.proves(FooVal)); 6326 }, 6327 {BuiltinOptions{ContextSensitiveOptions{}}}); 6328 } 6329 6330 TEST(TransferTest, ContextSensitiveMethodTwoLayersReturn) { 6331 std::string Code = R"( 6332 class MyClass { 6333 public: 6334 bool Inner() { return MyField; } 6335 bool Outer() { return Inner(); } 6336 6337 bool MyField; 6338 }; 6339 6340 void target() { 6341 MyClass MyObj; 6342 MyObj.MyField = true; 6343 bool Foo = MyObj.Outer(); 6344 // [[p]] 6345 } 6346 )"; 6347 runDataflow( 6348 Code, 6349 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6350 ASTContext &ASTCtx) { 6351 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6352 ; 6353 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6354 6355 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6356 ASSERT_THAT(FooDecl, NotNull()); 6357 6358 auto &FooVal = getFormula(*FooDecl, Env); 6359 EXPECT_TRUE(Env.proves(FooVal)); 6360 }, 6361 {BuiltinOptions{ContextSensitiveOptions{}}}); 6362 } 6363 6364 TEST(TransferTest, ContextSensitiveConstructorBody) { 6365 std::string Code = R"( 6366 class MyClass { 6367 public: 6368 MyClass() { MyField = true; } 6369 6370 bool MyField; 6371 }; 6372 6373 void target() { 6374 MyClass MyObj; 6375 bool Foo = MyObj.MyField; 6376 // [[p]] 6377 } 6378 )"; 6379 runDataflow( 6380 Code, 6381 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6382 ASTContext &ASTCtx) { 6383 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6384 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6385 6386 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6387 ASSERT_THAT(FooDecl, NotNull()); 6388 6389 auto &FooVal = getFormula(*FooDecl, Env); 6390 EXPECT_TRUE(Env.proves(FooVal)); 6391 }, 6392 {BuiltinOptions{ContextSensitiveOptions{}}}); 6393 } 6394 6395 TEST(TransferTest, ContextSensitiveConstructorInitializer) { 6396 std::string Code = R"( 6397 class MyClass { 6398 public: 6399 MyClass() : MyField(true) {} 6400 6401 bool MyField; 6402 }; 6403 6404 void target() { 6405 MyClass MyObj; 6406 bool Foo = MyObj.MyField; 6407 // [[p]] 6408 } 6409 )"; 6410 runDataflow( 6411 Code, 6412 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6413 ASTContext &ASTCtx) { 6414 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6415 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6416 6417 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6418 ASSERT_THAT(FooDecl, NotNull()); 6419 6420 auto &FooVal = getFormula(*FooDecl, Env); 6421 EXPECT_TRUE(Env.proves(FooVal)); 6422 }, 6423 {BuiltinOptions{ContextSensitiveOptions{}}}); 6424 } 6425 6426 TEST(TransferTest, ContextSensitiveConstructorDefault) { 6427 std::string Code = R"( 6428 class MyClass { 6429 public: 6430 MyClass() = default; 6431 6432 bool MyField = true; 6433 }; 6434 6435 void target() { 6436 MyClass MyObj; 6437 bool Foo = MyObj.MyField; 6438 // [[p]] 6439 } 6440 )"; 6441 runDataflow( 6442 Code, 6443 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6444 ASTContext &ASTCtx) { 6445 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6446 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6447 6448 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6449 ASSERT_THAT(FooDecl, NotNull()); 6450 6451 auto &FooVal = getFormula(*FooDecl, Env); 6452 EXPECT_TRUE(Env.proves(FooVal)); 6453 }, 6454 {BuiltinOptions{ContextSensitiveOptions{}}}); 6455 } 6456 6457 TEST(TransferTest, ContextSensitiveSelfReferentialClass) { 6458 // Test that the `this` pointer seen in the constructor has the same value 6459 // as the address of the variable the object is constructed into. 6460 std::string Code = R"( 6461 class MyClass { 6462 public: 6463 MyClass() : Self(this) {} 6464 MyClass *Self; 6465 }; 6466 6467 void target() { 6468 MyClass MyObj; 6469 MyClass *SelfPtr = MyObj.Self; 6470 // [[p]] 6471 } 6472 )"; 6473 runDataflow( 6474 Code, 6475 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6476 ASTContext &ASTCtx) { 6477 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6478 6479 const ValueDecl *MyObjDecl = findValueDecl(ASTCtx, "MyObj"); 6480 ASSERT_THAT(MyObjDecl, NotNull()); 6481 6482 const ValueDecl *SelfDecl = findValueDecl(ASTCtx, "SelfPtr"); 6483 ASSERT_THAT(SelfDecl, NotNull()); 6484 6485 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6486 auto &SelfVal = *cast<PointerValue>(Env.getValue(*SelfDecl)); 6487 EXPECT_EQ(Env.getStorageLocation(*MyObjDecl), &SelfVal.getPointeeLoc()); 6488 }, 6489 {BuiltinOptions{ContextSensitiveOptions{}}}); 6490 } 6491 6492 TEST(TransferTest, UnnamedBitfieldInitializer) { 6493 std::string Code = R"( 6494 struct B {}; 6495 struct A { 6496 unsigned a; 6497 unsigned : 4; 6498 unsigned c; 6499 B b; 6500 }; 6501 void target() { 6502 A a = {}; 6503 A test = a; 6504 (void)test.c; 6505 } 6506 )"; 6507 runDataflow( 6508 Code, 6509 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6510 ASTContext &ASTCtx) { 6511 // This doesn't need a body because this test was crashing the framework 6512 // before handling correctly Unnamed bitfields in `InitListExpr`. 6513 }); 6514 } 6515 6516 // Repro for a crash that used to occur with chained short-circuiting logical 6517 // operators. 6518 TEST(TransferTest, ChainedLogicalOps) { 6519 std::string Code = R"( 6520 bool target() { 6521 bool b = true || false || false || false; 6522 // [[p]] 6523 return b; 6524 } 6525 )"; 6526 runDataflow( 6527 Code, 6528 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6529 ASTContext &ASTCtx) { 6530 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6531 auto &B = getValueForDecl<BoolValue>(ASTCtx, Env, "b").formula(); 6532 EXPECT_TRUE(Env.proves(B)); 6533 }); 6534 } 6535 6536 // Repro for a crash that used to occur when we call a `noreturn` function 6537 // within one of the operands of a `&&` or `||` operator. 6538 TEST(TransferTest, NoReturnFunctionInsideShortCircuitedBooleanOp) { 6539 std::string Code = R"( 6540 __attribute__((noreturn)) int doesnt_return(); 6541 bool some_condition(); 6542 void target(bool b1, bool b2) { 6543 // Neither of these should crash. In addition, if we don't terminate the 6544 // program, we know that the operators need to trigger the short-circuit 6545 // logic, so `NoreturnOnRhsOfAnd` will be false and `NoreturnOnRhsOfOr` 6546 // will be true. 6547 bool NoreturnOnRhsOfAnd = b1 && doesnt_return() > 0; 6548 bool NoreturnOnRhsOfOr = b2 || doesnt_return() > 0; 6549 6550 // Calling a `noreturn` function on the LHS of an `&&` or `||` makes the 6551 // entire expression unreachable. So we know that in both of the following 6552 // cases, if `target()` terminates, the `else` branch was taken. 6553 bool NoreturnOnLhsMakesAndUnreachable = false; 6554 if (some_condition()) 6555 doesnt_return() > 0 && some_condition(); 6556 else 6557 NoreturnOnLhsMakesAndUnreachable = true; 6558 6559 bool NoreturnOnLhsMakesOrUnreachable = false; 6560 if (some_condition()) 6561 doesnt_return() > 0 || some_condition(); 6562 else 6563 NoreturnOnLhsMakesOrUnreachable = true; 6564 6565 // [[p]] 6566 } 6567 )"; 6568 runDataflow( 6569 Code, 6570 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6571 ASTContext &ASTCtx) { 6572 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6573 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6574 auto &A = Env.arena(); 6575 6576 // Check that [[p]] is reachable with a non-false flow condition. 6577 EXPECT_FALSE(Env.proves(A.makeLiteral(false))); 6578 6579 auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, "b1").formula(); 6580 EXPECT_TRUE(Env.proves(A.makeNot(B1))); 6581 6582 auto &NoreturnOnRhsOfAnd = 6583 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfAnd").formula(); 6584 EXPECT_TRUE(Env.proves(A.makeNot(NoreturnOnRhsOfAnd))); 6585 6586 auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, "b2").formula(); 6587 EXPECT_TRUE(Env.proves(B2)); 6588 6589 auto &NoreturnOnRhsOfOr = 6590 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfOr") 6591 .formula(); 6592 EXPECT_TRUE(Env.proves(NoreturnOnRhsOfOr)); 6593 6594 auto &NoreturnOnLhsMakesAndUnreachable = getValueForDecl<BoolValue>( 6595 ASTCtx, Env, "NoreturnOnLhsMakesAndUnreachable").formula(); 6596 EXPECT_TRUE(Env.proves(NoreturnOnLhsMakesAndUnreachable)); 6597 6598 auto &NoreturnOnLhsMakesOrUnreachable = getValueForDecl<BoolValue>( 6599 ASTCtx, Env, "NoreturnOnLhsMakesOrUnreachable").formula(); 6600 EXPECT_TRUE(Env.proves(NoreturnOnLhsMakesOrUnreachable)); 6601 }); 6602 } 6603 6604 TEST(TransferTest, NewExpressions) { 6605 std::string Code = R"( 6606 void target() { 6607 int *p = new int(42); 6608 // [[after_new]] 6609 } 6610 )"; 6611 runDataflow( 6612 Code, 6613 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6614 ASTContext &ASTCtx) { 6615 const Environment &Env = 6616 getEnvironmentAtAnnotation(Results, "after_new"); 6617 6618 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p"); 6619 6620 EXPECT_THAT(Env.getValue(P.getPointeeLoc()), NotNull()); 6621 }); 6622 } 6623 6624 TEST(TransferTest, NewExpressions_Structs) { 6625 std::string Code = R"( 6626 struct Inner { 6627 int InnerField; 6628 }; 6629 6630 struct Outer { 6631 Inner OuterField; 6632 }; 6633 6634 void target() { 6635 Outer *p = new Outer; 6636 // Access the fields to make sure the analysis actually generates children 6637 // for them in the `RecordStorageLocation` and `RecordValue`. 6638 p->OuterField.InnerField; 6639 // [[after_new]] 6640 } 6641 )"; 6642 runDataflow( 6643 Code, 6644 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6645 ASTContext &ASTCtx) { 6646 const Environment &Env = 6647 getEnvironmentAtAnnotation(Results, "after_new"); 6648 6649 const ValueDecl *OuterField = findValueDecl(ASTCtx, "OuterField"); 6650 const ValueDecl *InnerField = findValueDecl(ASTCtx, "InnerField"); 6651 6652 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p"); 6653 6654 auto &OuterLoc = cast<RecordStorageLocation>(P.getPointeeLoc()); 6655 auto &OuterFieldLoc = 6656 *cast<RecordStorageLocation>(OuterLoc.getChild(*OuterField)); 6657 auto &InnerFieldLoc = *OuterFieldLoc.getChild(*InnerField); 6658 6659 // Values for the struct and all fields exist after the new. 6660 EXPECT_THAT(Env.getValue(OuterLoc), NotNull()); 6661 EXPECT_THAT(Env.getValue(OuterFieldLoc), NotNull()); 6662 EXPECT_THAT(Env.getValue(InnerFieldLoc), NotNull()); 6663 }); 6664 } 6665 6666 TEST(TransferTest, FunctionToPointerDecayHasValue) { 6667 std::string Code = R"( 6668 struct A { static void static_member_func(); }; 6669 void target() { 6670 // To check that we're treating function-to-pointer decay correctly, 6671 // create two pointers, then verify they refer to the same storage 6672 // location. 6673 // We need to do the test this way because even if an initializer (in this 6674 // case, the function-to-pointer decay) does not create a value, we still 6675 // create a value for the variable. 6676 void (*non_member_p1)() = target; 6677 void (*non_member_p2)() = target; 6678 6679 // Do the same thing but for a static member function. 6680 void (*member_p1)() = A::static_member_func; 6681 void (*member_p2)() = A::static_member_func; 6682 // [[p]] 6683 } 6684 )"; 6685 runDataflow( 6686 Code, 6687 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6688 ASTContext &ASTCtx) { 6689 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6690 6691 auto &NonMemberP1 = 6692 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p1"); 6693 auto &NonMemberP2 = 6694 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p2"); 6695 EXPECT_EQ(&NonMemberP1.getPointeeLoc(), &NonMemberP2.getPointeeLoc()); 6696 6697 auto &MemberP1 = 6698 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p1"); 6699 auto &MemberP2 = 6700 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p2"); 6701 EXPECT_EQ(&MemberP1.getPointeeLoc(), &MemberP2.getPointeeLoc()); 6702 }); 6703 } 6704 6705 // Check that a builtin function is not associated with a value. (It's only 6706 // possible to call builtin functions directly, not take their address.) 6707 TEST(TransferTest, BuiltinFunctionModeled) { 6708 std::string Code = R"( 6709 void target() { 6710 __builtin_expect(0, 0); 6711 // [[p]] 6712 } 6713 )"; 6714 runDataflow( 6715 Code, 6716 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6717 ASTContext &ASTCtx) { 6718 using ast_matchers::selectFirst; 6719 using ast_matchers::match; 6720 using ast_matchers::traverse; 6721 using ast_matchers::implicitCastExpr; 6722 using ast_matchers::hasCastKind; 6723 6724 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6725 6726 auto *ImplicitCast = selectFirst<ImplicitCastExpr>( 6727 "implicit_cast", 6728 match(traverse(TK_AsIs, 6729 implicitCastExpr(hasCastKind(CK_BuiltinFnToFnPtr)) 6730 .bind("implicit_cast")), 6731 ASTCtx)); 6732 6733 ASSERT_THAT(ImplicitCast, NotNull()); 6734 EXPECT_THAT(Env.getValue(*ImplicitCast), IsNull()); 6735 }); 6736 } 6737 6738 // Check that a callee of a member operator call is modeled as a `PointerValue`. 6739 // Member operator calls are unusual in that their callee is a pointer that 6740 // stems from a `FunctionToPointerDecay`. In calls to non-operator non-static 6741 // member functions, the callee is a `MemberExpr` (which does not have pointer 6742 // type). 6743 // We want to make sure that we produce a pointer value for the callee in this 6744 // specific scenario and that its storage location is durable (for convergence). 6745 TEST(TransferTest, MemberOperatorCallModelsPointerForCallee) { 6746 std::string Code = R"( 6747 struct S { 6748 bool operator!=(S s); 6749 }; 6750 void target() { 6751 S s; 6752 (void)(s != s); 6753 (void)(s != s); 6754 // [[p]] 6755 } 6756 )"; 6757 runDataflow( 6758 Code, 6759 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6760 ASTContext &ASTCtx) { 6761 using ast_matchers::selectFirst; 6762 using ast_matchers::match; 6763 using ast_matchers::traverse; 6764 using ast_matchers::cxxOperatorCallExpr; 6765 6766 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6767 6768 auto Matches = match( 6769 traverse(TK_AsIs, cxxOperatorCallExpr().bind("call")), ASTCtx); 6770 6771 ASSERT_EQ(Matches.size(), 2UL); 6772 6773 auto *Call1 = Matches[0].getNodeAs<CXXOperatorCallExpr>("call"); 6774 auto *Call2 = Matches[1].getNodeAs<CXXOperatorCallExpr>("call"); 6775 6776 ASSERT_THAT(Call1, NotNull()); 6777 ASSERT_THAT(Call2, NotNull()); 6778 6779 EXPECT_EQ(cast<ImplicitCastExpr>(Call1->getCallee())->getCastKind(), 6780 CK_FunctionToPointerDecay); 6781 EXPECT_EQ(cast<ImplicitCastExpr>(Call2->getCallee())->getCastKind(), 6782 CK_FunctionToPointerDecay); 6783 6784 auto *Ptr1 = cast<PointerValue>(Env.getValue(*Call1->getCallee())); 6785 auto *Ptr2 = cast<PointerValue>(Env.getValue(*Call2->getCallee())); 6786 6787 ASSERT_EQ(&Ptr1->getPointeeLoc(), &Ptr2->getPointeeLoc()); 6788 }); 6789 } 6790 6791 // Check that fields of anonymous records are modeled. 6792 TEST(TransferTest, AnonymousStruct) { 6793 std::string Code = R"( 6794 struct S { 6795 struct { 6796 bool b; 6797 }; 6798 }; 6799 void target() { 6800 S s; 6801 s.b = true; 6802 // [[p]] 6803 } 6804 )"; 6805 runDataflow( 6806 Code, 6807 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6808 ASTContext &ASTCtx) { 6809 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6810 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 6811 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b"); 6812 const IndirectFieldDecl *IndirectField = 6813 findIndirectFieldDecl(ASTCtx, "b"); 6814 6815 auto *S = cast<RecordStorageLocation>(Env.getStorageLocation(*SDecl)); 6816 auto &AnonStruct = *cast<RecordStorageLocation>( 6817 S->getChild(*cast<ValueDecl>(IndirectField->chain().front()))); 6818 6819 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env)); 6820 ASSERT_TRUE(Env.proves(B->formula())); 6821 }); 6822 } 6823 6824 TEST(TransferTest, AnonymousStructWithInitializer) { 6825 std::string Code = R"( 6826 struct target { 6827 target() { 6828 (void)0; 6829 // [[p]] 6830 } 6831 struct { 6832 bool b = true; 6833 }; 6834 }; 6835 )"; 6836 runDataflow( 6837 Code, 6838 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6839 ASTContext &ASTCtx) { 6840 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6841 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b"); 6842 const IndirectFieldDecl *IndirectField = 6843 findIndirectFieldDecl(ASTCtx, "b"); 6844 6845 auto *ThisLoc = 6846 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation()); 6847 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild( 6848 *cast<ValueDecl>(IndirectField->chain().front()))); 6849 6850 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env)); 6851 ASSERT_TRUE(Env.proves(B->formula())); 6852 }); 6853 } 6854 6855 TEST(TransferTest, AnonymousStructWithReferenceField) { 6856 std::string Code = R"( 6857 int global_i = 0; 6858 struct target { 6859 target() { 6860 (void)0; 6861 // [[p]] 6862 } 6863 struct { 6864 int &i = global_i; 6865 }; 6866 }; 6867 )"; 6868 runDataflow( 6869 Code, 6870 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6871 ASTContext &ASTCtx) { 6872 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6873 const ValueDecl *GlobalIDecl = findValueDecl(ASTCtx, "global_i"); 6874 const ValueDecl *IDecl = findValueDecl(ASTCtx, "i"); 6875 const IndirectFieldDecl *IndirectField = 6876 findIndirectFieldDecl(ASTCtx, "i"); 6877 6878 auto *ThisLoc = 6879 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation()); 6880 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild( 6881 *cast<ValueDecl>(IndirectField->chain().front()))); 6882 6883 ASSERT_EQ(AnonStruct.getChild(*IDecl), 6884 Env.getStorageLocation(*GlobalIDecl)); 6885 }); 6886 } 6887 6888 TEST(TransferTest, EvaluateBlockWithUnreachablePreds) { 6889 // This is a crash repro. 6890 // `false` block may not have been processed when we try to evaluate the `||` 6891 // after visiting `true`, because it is not necessary (and therefore the edge 6892 // is marked unreachable). Trying to get the analysis state via 6893 // `getEnvironment` for the subexpression still should not crash. 6894 std::string Code = R"( 6895 int target(int i) { 6896 if ((i < 0 && true) || false) { 6897 return 0; 6898 } 6899 return 0; 6900 } 6901 )"; 6902 runDataflow( 6903 Code, 6904 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6905 ASTContext &ASTCtx) {}); 6906 } 6907 6908 TEST(TransferTest, LambdaCaptureByCopy) { 6909 std::string Code = R"( 6910 void target(int Foo, int Bar) { 6911 [Foo]() { 6912 (void)0; 6913 // [[p]] 6914 }(); 6915 } 6916 )"; 6917 runDataflowOnLambda( 6918 Code, 6919 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6920 ASTContext &ASTCtx) { 6921 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6922 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6923 6924 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6925 ASSERT_THAT(FooDecl, NotNull()); 6926 6927 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6928 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6929 6930 const Value *FooVal = Env.getValue(*FooLoc); 6931 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6932 6933 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6934 ASSERT_THAT(BarDecl, NotNull()); 6935 6936 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6937 EXPECT_THAT(BarLoc, IsNull()); 6938 }); 6939 } 6940 6941 TEST(TransferTest, LambdaCaptureByReference) { 6942 std::string Code = R"( 6943 void target(int Foo, int Bar) { 6944 [&Foo]() { 6945 (void)0; 6946 // [[p]] 6947 }(); 6948 } 6949 )"; 6950 runDataflowOnLambda( 6951 Code, 6952 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6953 ASTContext &ASTCtx) { 6954 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6955 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6956 6957 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6958 ASSERT_THAT(FooDecl, NotNull()); 6959 6960 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6961 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6962 6963 const Value *FooVal = Env.getValue(*FooLoc); 6964 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6965 6966 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6967 ASSERT_THAT(BarDecl, NotNull()); 6968 6969 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6970 EXPECT_THAT(BarLoc, IsNull()); 6971 }); 6972 } 6973 6974 TEST(TransferTest, LambdaCaptureWithInitializer) { 6975 std::string Code = R"( 6976 void target(int Bar) { 6977 [Foo=Bar]() { 6978 (void)0; 6979 // [[p]] 6980 }(); 6981 } 6982 )"; 6983 runDataflowOnLambda( 6984 Code, 6985 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6986 ASTContext &ASTCtx) { 6987 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6988 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6989 6990 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6991 ASSERT_THAT(FooDecl, NotNull()); 6992 6993 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6994 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6995 6996 const Value *FooVal = Env.getValue(*FooLoc); 6997 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6998 6999 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 7000 ASSERT_THAT(BarDecl, NotNull()); 7001 7002 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 7003 EXPECT_THAT(BarLoc, IsNull()); 7004 }); 7005 } 7006 7007 TEST(TransferTest, LambdaCaptureByCopyImplicit) { 7008 std::string Code = R"( 7009 void target(int Foo, int Bar) { 7010 [=]() { 7011 Foo; 7012 // [[p]] 7013 }(); 7014 } 7015 )"; 7016 runDataflowOnLambda( 7017 Code, 7018 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7019 ASTContext &ASTCtx) { 7020 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 7021 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7022 7023 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 7024 ASSERT_THAT(FooDecl, NotNull()); 7025 7026 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 7027 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 7028 7029 const Value *FooVal = Env.getValue(*FooLoc); 7030 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 7031 7032 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 7033 ASSERT_THAT(BarDecl, NotNull()); 7034 7035 // There is no storage location for `Bar` because it isn't used in the 7036 // body of the lambda. 7037 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 7038 EXPECT_THAT(BarLoc, IsNull()); 7039 }); 7040 } 7041 7042 TEST(TransferTest, LambdaCaptureByReferenceImplicit) { 7043 std::string Code = R"( 7044 void target(int Foo, int Bar) { 7045 [&]() { 7046 Foo; 7047 // [[p]] 7048 }(); 7049 } 7050 )"; 7051 runDataflowOnLambda( 7052 Code, 7053 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7054 ASTContext &ASTCtx) { 7055 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 7056 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7057 7058 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 7059 ASSERT_THAT(FooDecl, NotNull()); 7060 7061 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 7062 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 7063 7064 const Value *FooVal = Env.getValue(*FooLoc); 7065 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 7066 7067 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 7068 ASSERT_THAT(BarDecl, NotNull()); 7069 7070 // There is no storage location for `Bar` because it isn't used in the 7071 // body of the lambda. 7072 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 7073 EXPECT_THAT(BarLoc, IsNull()); 7074 }); 7075 } 7076 7077 TEST(TransferTest, LambdaCaptureThis) { 7078 std::string Code = R"( 7079 struct Bar { 7080 int Foo; 7081 7082 void target() { 7083 [this]() { 7084 Foo; 7085 // [[p]] 7086 }(); 7087 } 7088 }; 7089 )"; 7090 runDataflowOnLambda( 7091 Code, 7092 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7093 ASTContext &ASTCtx) { 7094 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 7095 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7096 7097 const RecordStorageLocation *ThisPointeeLoc = 7098 Env.getThisPointeeStorageLocation(); 7099 ASSERT_THAT(ThisPointeeLoc, NotNull()); 7100 7101 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 7102 ASSERT_THAT(FooDecl, NotNull()); 7103 7104 const StorageLocation *FooLoc = ThisPointeeLoc->getChild(*FooDecl); 7105 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 7106 7107 const Value *FooVal = Env.getValue(*FooLoc); 7108 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 7109 }); 7110 } 7111 7112 // This test verifies correct modeling of a relational dependency that goes 7113 // through unmodeled functions (the simple `cond()` in this case). 7114 TEST(TransferTest, ConditionalRelation) { 7115 std::string Code = R"( 7116 bool cond(); 7117 void target() { 7118 bool a = true; 7119 bool b = true; 7120 if (cond()) { 7121 a = false; 7122 if (cond()) { 7123 b = false; 7124 } 7125 } 7126 (void)0; 7127 // [[p]] 7128 } 7129 )"; 7130 runDataflow( 7131 Code, 7132 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 7133 ASTContext &ASTCtx) { 7134 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 7135 auto &A = Env.arena(); 7136 auto &VarA = getValueForDecl<BoolValue>(ASTCtx, Env, "a").formula(); 7137 auto &VarB = getValueForDecl<BoolValue>(ASTCtx, Env, "b").formula(); 7138 7139 EXPECT_FALSE(Env.allows(A.makeAnd(VarA, A.makeNot(VarB)))); 7140 }); 7141 } 7142 7143 } // namespace 7144