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