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