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