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, InitListExprAsUnion) { 2371 // This is a crash repro. 2372 std::string Code = R"cc( 2373 class target { 2374 union { 2375 int *a; 2376 bool *b; 2377 } F; 2378 2379 public: 2380 constexpr target() : F{nullptr} { 2381 int *null = nullptr; 2382 F.b; // Make sure we reference 'b' so it is modeled. 2383 // [[p]] 2384 } 2385 }; 2386 )cc"; 2387 runDataflow( 2388 Code, 2389 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2390 ASTContext &ASTCtx) { 2391 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2392 2393 auto &FLoc = getFieldLoc<RecordStorageLocation>( 2394 *Env.getThisPointeeStorageLocation(), "F", ASTCtx); 2395 auto *AVal = cast<PointerValue>(getFieldValue(&FLoc, "a", ASTCtx, Env)); 2396 ASSERT_EQ(AVal, &getValueForDecl<PointerValue>(ASTCtx, Env, "null")); 2397 ASSERT_EQ(getFieldValue(&FLoc, "b", ASTCtx, Env), nullptr); 2398 }); 2399 } 2400 2401 TEST(TransferTest, CopyConstructor) { 2402 std::string Code = R"( 2403 struct A { 2404 int Baz; 2405 }; 2406 2407 void target() { 2408 A Foo = { 1 }; 2409 A Bar = Foo; 2410 // [[after_copy]] 2411 Foo.Baz = 2; 2412 // [[after_update]] 2413 } 2414 )"; 2415 runDataflow( 2416 Code, 2417 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2418 ASTContext &ASTCtx) { 2419 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2420 ASSERT_THAT(FooDecl, NotNull()); 2421 2422 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2423 ASSERT_THAT(BarDecl, NotNull()); 2424 2425 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2426 ASSERT_THAT(BazDecl, NotNull()); 2427 2428 // after_copy 2429 { 2430 const Environment &Env = 2431 getEnvironmentAtAnnotation(Results, "after_copy"); 2432 2433 const auto *FooLoc = 2434 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2435 const auto *BarLoc = 2436 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2437 2438 // `Foo` and `Bar` have different `RecordValue`s associated with them. 2439 const auto *FooVal = cast<RecordValue>(Env.getValue(*FooLoc)); 2440 const auto *BarVal = cast<RecordValue>(Env.getValue(*BarLoc)); 2441 EXPECT_NE(FooVal, BarVal); 2442 2443 // But the records compare equal. 2444 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env)); 2445 2446 // In particular, the value of `Baz` in both records is the same. 2447 const auto *FooBazVal = 2448 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2449 const auto *BarBazVal = 2450 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2451 EXPECT_EQ(FooBazVal, BarBazVal); 2452 } 2453 2454 // after_update 2455 { 2456 const Environment &Env = 2457 getEnvironmentAtAnnotation(Results, "after_update"); 2458 2459 const auto *FooLoc = 2460 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2461 const auto *BarLoc = 2462 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2463 2464 EXPECT_FALSE(recordsEqual(*FooLoc, *BarLoc, Env)); 2465 2466 const auto *FooBazVal = 2467 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2468 const auto *BarBazVal = 2469 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2470 EXPECT_NE(FooBazVal, BarBazVal); 2471 } 2472 }); 2473 } 2474 2475 TEST(TransferTest, CopyConstructorWithDefaultArgument) { 2476 std::string Code = R"( 2477 struct A { 2478 int Baz; 2479 A() = default; 2480 A(const A& a, bool def = true) { Baz = a.Baz; } 2481 }; 2482 2483 void target() { 2484 A Foo; 2485 (void)Foo.Baz; 2486 A Bar = Foo; 2487 // [[p]] 2488 } 2489 )"; 2490 runDataflow( 2491 Code, 2492 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2493 ASTContext &ASTCtx) { 2494 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2495 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2496 2497 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2498 ASSERT_THAT(FooDecl, NotNull()); 2499 2500 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2501 ASSERT_THAT(BarDecl, NotNull()); 2502 2503 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2504 ASSERT_THAT(BazDecl, NotNull()); 2505 2506 const auto *FooLoc = 2507 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2508 const auto *BarLoc = 2509 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2510 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env)); 2511 2512 const auto *FooBazVal = 2513 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2514 const auto *BarBazVal = 2515 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2516 EXPECT_EQ(FooBazVal, BarBazVal); 2517 }); 2518 } 2519 2520 TEST(TransferTest, CopyConstructorWithParens) { 2521 std::string Code = R"( 2522 struct A { 2523 int Baz; 2524 }; 2525 2526 void target() { 2527 A Foo; 2528 (void)Foo.Baz; 2529 A Bar((A(Foo))); 2530 // [[p]] 2531 } 2532 )"; 2533 runDataflow( 2534 Code, 2535 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2536 ASTContext &ASTCtx) { 2537 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2538 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2539 2540 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2541 ASSERT_THAT(FooDecl, NotNull()); 2542 2543 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2544 ASSERT_THAT(BarDecl, NotNull()); 2545 2546 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2547 ASSERT_THAT(BazDecl, NotNull()); 2548 2549 const auto *FooLoc = 2550 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2551 const auto *BarLoc = 2552 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2553 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env)); 2554 2555 const auto *FooBazVal = 2556 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2557 const auto *BarBazVal = 2558 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2559 EXPECT_EQ(FooBazVal, BarBazVal); 2560 }); 2561 } 2562 2563 TEST(TransferTest, CopyConstructorWithInitializerListAsSyntacticSugar) { 2564 std::string Code = R"( 2565 struct A { 2566 int Baz; 2567 }; 2568 void target() { 2569 A Foo = {3}; 2570 (void)Foo.Baz; 2571 A Bar = {A(Foo)}; 2572 // [[p]] 2573 } 2574 )"; 2575 runDataflow( 2576 Code, 2577 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2578 ASTContext &ASTCtx) { 2579 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2580 2581 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2582 2583 const auto &FooLoc = 2584 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo"); 2585 const auto &BarLoc = 2586 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar"); 2587 2588 const auto *FooBazVal = 2589 cast<IntegerValue>(getFieldValue(&FooLoc, *BazDecl, Env)); 2590 const auto *BarBazVal = 2591 cast<IntegerValue>(getFieldValue(&BarLoc, *BazDecl, Env)); 2592 EXPECT_EQ(FooBazVal, BarBazVal); 2593 }); 2594 } 2595 2596 TEST(TransferTest, CopyConstructorArgIsRefReturnedByFunction) { 2597 // This is a crash repro. 2598 std::string Code = R"( 2599 struct S {}; 2600 const S &returnsSRef(); 2601 void target() { 2602 S s(returnsSRef()); 2603 } 2604 )"; 2605 runDataflow( 2606 Code, 2607 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2608 ASTContext &ASTCtx) {}); 2609 } 2610 2611 TEST(TransferTest, MoveConstructor) { 2612 std::string Code = R"( 2613 namespace std { 2614 2615 template <typename T> struct remove_reference { using type = T; }; 2616 template <typename T> struct remove_reference<T&> { using type = T; }; 2617 template <typename T> struct remove_reference<T&&> { using type = T; }; 2618 2619 template <typename T> 2620 using remove_reference_t = typename remove_reference<T>::type; 2621 2622 template <typename T> 2623 std::remove_reference_t<T>&& move(T&& x); 2624 2625 } // namespace std 2626 2627 struct A { 2628 int Baz; 2629 }; 2630 2631 void target() { 2632 A Foo; 2633 A Bar; 2634 (void)Foo.Baz; 2635 // [[p1]] 2636 Foo = std::move(Bar); 2637 // [[p2]] 2638 } 2639 )"; 2640 runDataflow( 2641 Code, 2642 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2643 ASTContext &ASTCtx) { 2644 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 2645 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 2646 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 2647 2648 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2649 ASSERT_THAT(FooDecl, NotNull()); 2650 2651 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2652 ASSERT_THAT(BarDecl, NotNull()); 2653 2654 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2655 ASSERT_THAT(BazDecl, NotNull()); 2656 2657 const auto *FooLoc1 = 2658 cast<RecordStorageLocation>(Env1.getStorageLocation(*FooDecl)); 2659 const auto *BarLoc1 = 2660 cast<RecordStorageLocation>(Env1.getStorageLocation(*BarDecl)); 2661 2662 EXPECT_FALSE(recordsEqual(*FooLoc1, *BarLoc1, Env1)); 2663 2664 const auto *FooVal1 = cast<RecordValue>(Env1.getValue(*FooLoc1)); 2665 const auto *BarVal1 = cast<RecordValue>(Env1.getValue(*BarLoc1)); 2666 EXPECT_NE(FooVal1, BarVal1); 2667 2668 const auto *FooBazVal1 = 2669 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env1)); 2670 const auto *BarBazVal1 = 2671 cast<IntegerValue>(getFieldValue(BarLoc1, *BazDecl, Env1)); 2672 EXPECT_NE(FooBazVal1, BarBazVal1); 2673 2674 const auto *FooLoc2 = 2675 cast<RecordStorageLocation>(Env2.getStorageLocation(*FooDecl)); 2676 const auto *FooVal2 = cast<RecordValue>(Env2.getValue(*FooLoc2)); 2677 EXPECT_NE(FooVal2, BarVal1); 2678 EXPECT_TRUE(recordsEqual(*FooLoc2, Env2, *BarLoc1, Env1)); 2679 2680 const auto *FooBazVal2 = 2681 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env2)); 2682 EXPECT_EQ(FooBazVal2, BarBazVal1); 2683 }); 2684 } 2685 2686 TEST(TransferTest, BindTemporary) { 2687 std::string Code = R"( 2688 struct A { 2689 virtual ~A() = default; 2690 2691 int Baz; 2692 }; 2693 2694 void target(A Foo) { 2695 int Bar = A(Foo).Baz; 2696 // [[p]] 2697 } 2698 )"; 2699 runDataflow( 2700 Code, 2701 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2702 ASTContext &ASTCtx) { 2703 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2704 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2705 2706 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2707 ASSERT_THAT(FooDecl, NotNull()); 2708 2709 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2710 ASSERT_THAT(BarDecl, NotNull()); 2711 2712 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2713 ASSERT_THAT(BazDecl, NotNull()); 2714 2715 const auto &FooLoc = 2716 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2717 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 2718 EXPECT_EQ(BarVal, getFieldValue(&FooLoc, *BazDecl, Env)); 2719 }); 2720 } 2721 2722 TEST(TransferTest, ResultObjectLocation) { 2723 std::string Code = R"( 2724 struct A { 2725 virtual ~A() = default; 2726 }; 2727 2728 void target() { 2729 0, A(); 2730 (void)0; // [[p]] 2731 } 2732 )"; 2733 using ast_matchers::binaryOperator; 2734 using ast_matchers::cxxBindTemporaryExpr; 2735 using ast_matchers::cxxTemporaryObjectExpr; 2736 using ast_matchers::exprWithCleanups; 2737 using ast_matchers::has; 2738 using ast_matchers::hasOperatorName; 2739 using ast_matchers::hasRHS; 2740 using ast_matchers::match; 2741 using ast_matchers::selectFirst; 2742 using ast_matchers::traverse; 2743 runDataflow( 2744 Code, 2745 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2746 ASTContext &ASTCtx) { 2747 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2748 2749 // The expression `0, A()` in the code above produces the following 2750 // structure, consisting of four prvalues of record type. 2751 // `Env.getResultObjectLocation()` should return the same location for 2752 // all of these. 2753 auto MatchResult = match( 2754 traverse(TK_AsIs, 2755 exprWithCleanups( 2756 has(binaryOperator( 2757 hasOperatorName(","), 2758 hasRHS(cxxBindTemporaryExpr( 2759 has(cxxTemporaryObjectExpr().bind( 2760 "toe"))) 2761 .bind("bte"))) 2762 .bind("comma"))) 2763 .bind("ewc")), 2764 ASTCtx); 2765 auto *TOE = selectFirst<CXXTemporaryObjectExpr>("toe", MatchResult); 2766 ASSERT_NE(TOE, nullptr); 2767 auto *Comma = selectFirst<BinaryOperator>("comma", MatchResult); 2768 ASSERT_NE(Comma, nullptr); 2769 auto *EWC = selectFirst<ExprWithCleanups>("ewc", MatchResult); 2770 ASSERT_NE(EWC, nullptr); 2771 auto *BTE = selectFirst<CXXBindTemporaryExpr>("bte", MatchResult); 2772 ASSERT_NE(BTE, nullptr); 2773 2774 RecordStorageLocation &Loc = Env.getResultObjectLocation(*TOE); 2775 EXPECT_EQ(&Loc, &Env.getResultObjectLocation(*Comma)); 2776 EXPECT_EQ(&Loc, &Env.getResultObjectLocation(*EWC)); 2777 EXPECT_EQ(&Loc, &Env.getResultObjectLocation(*BTE)); 2778 }); 2779 } 2780 2781 TEST(TransferTest, ResultObjectLocationForDefaultInitExpr) { 2782 std::string Code = R"( 2783 struct S {}; 2784 struct target { 2785 target () { 2786 (void)0; 2787 // [[p]] 2788 } 2789 S s = {}; 2790 }; 2791 )"; 2792 2793 using ast_matchers::cxxCtorInitializer; 2794 using ast_matchers::match; 2795 using ast_matchers::selectFirst; 2796 runDataflow( 2797 Code, 2798 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2799 ASTContext &ASTCtx) { 2800 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2801 2802 const ValueDecl *SField = findValueDecl(ASTCtx, "s"); 2803 2804 auto *CtorInit = selectFirst<CXXCtorInitializer>( 2805 "ctor_initializer", 2806 match(cxxCtorInitializer().bind("ctor_initializer"), ASTCtx)); 2807 ASSERT_NE(CtorInit, nullptr); 2808 2809 auto *DefaultInit = cast<CXXDefaultInitExpr>(CtorInit->getInit()); 2810 2811 RecordStorageLocation &Loc = Env.getResultObjectLocation(*DefaultInit); 2812 2813 // FIXME: The result object location for the `CXXDefaultInitExpr` should 2814 // be the location of the member variable being initialized, but we 2815 // don't do this correctly yet; see also comments in 2816 // `builtinTransferInitializer()`. 2817 // For the time being, we just document the current erroneous behavior 2818 // here (this should be `EXPECT_EQ` when the behavior is fixed). 2819 EXPECT_NE(&Loc, Env.getThisPointeeStorageLocation()->getChild(*SField)); 2820 }); 2821 } 2822 2823 // This test ensures that CXXOperatorCallExpr returning prvalues are correctly 2824 // handled by the transfer functions, especially that `getResultObjectLocation` 2825 // correctly returns a storage location for those. 2826 TEST(TransferTest, ResultObjectLocationForCXXOperatorCallExpr) { 2827 std::string Code = R"( 2828 struct A { 2829 A operator+(int); 2830 }; 2831 2832 void target() { 2833 A a; 2834 a + 3; 2835 (void)0; // [[p]] 2836 } 2837 )"; 2838 using ast_matchers::cxxOperatorCallExpr; 2839 using ast_matchers::match; 2840 using ast_matchers::selectFirst; 2841 using ast_matchers::traverse; 2842 runDataflow( 2843 Code, 2844 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2845 ASTContext &ASTCtx) { 2846 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2847 2848 auto *CallExpr = selectFirst<CXXOperatorCallExpr>( 2849 "call_expr", 2850 match(cxxOperatorCallExpr().bind("call_expr"), ASTCtx)); 2851 2852 EXPECT_NE(&Env.getResultObjectLocation(*CallExpr), nullptr); 2853 }); 2854 } 2855 2856 TEST(TransferTest, StaticCast) { 2857 std::string Code = R"( 2858 void target(int Foo) { 2859 int Bar = static_cast<int>(Foo); 2860 // [[p]] 2861 } 2862 )"; 2863 runDataflow( 2864 Code, 2865 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2866 ASTContext &ASTCtx) { 2867 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2868 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2869 2870 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2871 ASSERT_THAT(FooDecl, NotNull()); 2872 2873 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2874 ASSERT_THAT(BarDecl, NotNull()); 2875 2876 const auto *FooVal = Env.getValue(*FooDecl); 2877 const auto *BarVal = Env.getValue(*BarDecl); 2878 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 2879 EXPECT_TRUE(isa<IntegerValue>(BarVal)); 2880 EXPECT_EQ(FooVal, BarVal); 2881 }); 2882 } 2883 2884 TEST(TransferTest, IntegralCast) { 2885 std::string Code = R"( 2886 void target(int Foo) { 2887 long Bar = Foo; 2888 // [[p]] 2889 } 2890 )"; 2891 runDataflow( 2892 Code, 2893 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2894 ASTContext &ASTCtx) { 2895 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2896 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2897 2898 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2899 ASSERT_THAT(FooDecl, NotNull()); 2900 2901 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2902 ASSERT_THAT(BarDecl, NotNull()); 2903 2904 const auto *FooVal = Env.getValue(*FooDecl); 2905 const auto *BarVal = Env.getValue(*BarDecl); 2906 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 2907 EXPECT_TRUE(isa<IntegerValue>(BarVal)); 2908 EXPECT_EQ(FooVal, BarVal); 2909 }); 2910 } 2911 2912 TEST(TransferTest, IntegraltoBooleanCast) { 2913 std::string Code = R"( 2914 void target(int Foo) { 2915 bool Bar = Foo; 2916 // [[p]] 2917 } 2918 )"; 2919 runDataflow( 2920 Code, 2921 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2922 ASTContext &ASTCtx) { 2923 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2924 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2925 2926 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2927 ASSERT_THAT(FooDecl, NotNull()); 2928 2929 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2930 ASSERT_THAT(BarDecl, NotNull()); 2931 2932 const auto *FooVal = Env.getValue(*FooDecl); 2933 const auto *BarVal = Env.getValue(*BarDecl); 2934 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 2935 EXPECT_TRUE(isa<BoolValue>(BarVal)); 2936 }); 2937 } 2938 2939 TEST(TransferTest, IntegralToBooleanCastFromBool) { 2940 std::string Code = R"( 2941 void target(bool Foo) { 2942 int Zab = Foo; 2943 bool Bar = Zab; 2944 // [[p]] 2945 } 2946 )"; 2947 runDataflow( 2948 Code, 2949 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2950 ASTContext &ASTCtx) { 2951 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2952 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2953 2954 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2955 ASSERT_THAT(FooDecl, NotNull()); 2956 2957 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2958 ASSERT_THAT(BarDecl, NotNull()); 2959 2960 const auto *FooVal = Env.getValue(*FooDecl); 2961 const auto *BarVal = Env.getValue(*BarDecl); 2962 EXPECT_TRUE(isa<BoolValue>(FooVal)); 2963 EXPECT_TRUE(isa<BoolValue>(BarVal)); 2964 EXPECT_EQ(FooVal, BarVal); 2965 }); 2966 } 2967 2968 TEST(TransferTest, NullToPointerCast) { 2969 std::string Code = R"( 2970 using my_nullptr_t = decltype(nullptr); 2971 struct Baz {}; 2972 void target() { 2973 int *FooX = nullptr; 2974 int *FooY = nullptr; 2975 bool **Bar = nullptr; 2976 Baz *Baz = nullptr; 2977 my_nullptr_t Null = 0; 2978 // [[p]] 2979 } 2980 )"; 2981 runDataflow( 2982 Code, 2983 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2984 ASTContext &ASTCtx) { 2985 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2986 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2987 2988 const ValueDecl *FooXDecl = findValueDecl(ASTCtx, "FooX"); 2989 ASSERT_THAT(FooXDecl, NotNull()); 2990 2991 const ValueDecl *FooYDecl = findValueDecl(ASTCtx, "FooY"); 2992 ASSERT_THAT(FooYDecl, NotNull()); 2993 2994 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2995 ASSERT_THAT(BarDecl, NotNull()); 2996 2997 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2998 ASSERT_THAT(BazDecl, NotNull()); 2999 3000 const ValueDecl *NullDecl = findValueDecl(ASTCtx, "Null"); 3001 ASSERT_THAT(NullDecl, NotNull()); 3002 3003 const auto *FooXVal = cast<PointerValue>(Env.getValue(*FooXDecl)); 3004 const auto *FooYVal = cast<PointerValue>(Env.getValue(*FooYDecl)); 3005 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 3006 const auto *BazVal = cast<PointerValue>(Env.getValue(*BazDecl)); 3007 const auto *NullVal = cast<PointerValue>(Env.getValue(*NullDecl)); 3008 3009 EXPECT_EQ(FooXVal, FooYVal); 3010 EXPECT_NE(FooXVal, BarVal); 3011 EXPECT_NE(FooXVal, BazVal); 3012 EXPECT_NE(BarVal, BazVal); 3013 3014 const StorageLocation &FooPointeeLoc = FooXVal->getPointeeLoc(); 3015 EXPECT_TRUE(isa<ScalarStorageLocation>(FooPointeeLoc)); 3016 EXPECT_THAT(Env.getValue(FooPointeeLoc), IsNull()); 3017 3018 const StorageLocation &BarPointeeLoc = BarVal->getPointeeLoc(); 3019 EXPECT_TRUE(isa<ScalarStorageLocation>(BarPointeeLoc)); 3020 EXPECT_THAT(Env.getValue(BarPointeeLoc), IsNull()); 3021 3022 const StorageLocation &BazPointeeLoc = BazVal->getPointeeLoc(); 3023 EXPECT_TRUE(isa<RecordStorageLocation>(BazPointeeLoc)); 3024 EXPECT_THAT(Env.getValue(BazPointeeLoc), IsNull()); 3025 3026 const StorageLocation &NullPointeeLoc = NullVal->getPointeeLoc(); 3027 EXPECT_TRUE(isa<ScalarStorageLocation>(NullPointeeLoc)); 3028 EXPECT_THAT(Env.getValue(NullPointeeLoc), IsNull()); 3029 }); 3030 } 3031 3032 TEST(TransferTest, PointerToMemberVariable) { 3033 std::string Code = R"( 3034 struct S { 3035 int i; 3036 }; 3037 void target() { 3038 int S::*MemberPointer = &S::i; 3039 // [[p]] 3040 } 3041 )"; 3042 runDataflow( 3043 Code, 3044 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3045 ASTContext &ASTCtx) { 3046 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3047 3048 const ValueDecl *MemberPointerDecl = 3049 findValueDecl(ASTCtx, "MemberPointer"); 3050 ASSERT_THAT(MemberPointerDecl, NotNull()); 3051 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 3052 }); 3053 } 3054 3055 TEST(TransferTest, PointerToMemberFunction) { 3056 std::string Code = R"( 3057 struct S { 3058 void Method(); 3059 }; 3060 void target() { 3061 void (S::*MemberPointer)() = &S::Method; 3062 // [[p]] 3063 } 3064 )"; 3065 runDataflow( 3066 Code, 3067 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3068 ASTContext &ASTCtx) { 3069 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3070 3071 const ValueDecl *MemberPointerDecl = 3072 findValueDecl(ASTCtx, "MemberPointer"); 3073 ASSERT_THAT(MemberPointerDecl, NotNull()); 3074 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 3075 }); 3076 } 3077 3078 TEST(TransferTest, NullToMemberPointerCast) { 3079 std::string Code = R"( 3080 struct Foo {}; 3081 void target() { 3082 int Foo::*MemberPointer = nullptr; 3083 // [[p]] 3084 } 3085 )"; 3086 runDataflow( 3087 Code, 3088 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3089 ASTContext &ASTCtx) { 3090 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3091 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3092 3093 const ValueDecl *MemberPointerDecl = 3094 findValueDecl(ASTCtx, "MemberPointer"); 3095 ASSERT_THAT(MemberPointerDecl, NotNull()); 3096 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 3097 }); 3098 } 3099 3100 TEST(TransferTest, AddrOfValue) { 3101 std::string Code = R"( 3102 void target() { 3103 int Foo; 3104 int *Bar = &Foo; 3105 // [[p]] 3106 } 3107 )"; 3108 runDataflow( 3109 Code, 3110 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3111 ASTContext &ASTCtx) { 3112 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3113 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3114 3115 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3116 ASSERT_THAT(FooDecl, NotNull()); 3117 3118 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3119 ASSERT_THAT(BarDecl, NotNull()); 3120 3121 const auto *FooLoc = 3122 cast<ScalarStorageLocation>(Env.getStorageLocation(*FooDecl)); 3123 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 3124 EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc); 3125 }); 3126 } 3127 3128 TEST(TransferTest, AddrOfReference) { 3129 std::string Code = R"( 3130 void target(int *Foo) { 3131 int *Bar = &(*Foo); 3132 // [[p]] 3133 } 3134 )"; 3135 runDataflow( 3136 Code, 3137 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3138 ASTContext &ASTCtx) { 3139 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3140 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3141 3142 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3143 ASSERT_THAT(FooDecl, NotNull()); 3144 3145 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3146 ASSERT_THAT(BarDecl, NotNull()); 3147 3148 const auto *FooVal = cast<PointerValue>(Env.getValue(*FooDecl)); 3149 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 3150 EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc()); 3151 }); 3152 } 3153 3154 TEST(TransferTest, CannotAnalyzeFunctionTemplate) { 3155 std::string Code = R"( 3156 template <typename T> 3157 void target() {} 3158 )"; 3159 ASSERT_THAT_ERROR( 3160 checkDataflowWithNoopAnalysis(Code), 3161 llvm::FailedWithMessage("Cannot analyze templated declarations")); 3162 } 3163 3164 TEST(TransferTest, CannotAnalyzeMethodOfClassTemplate) { 3165 std::string Code = R"( 3166 template <typename T> 3167 struct A { 3168 void target() {} 3169 }; 3170 )"; 3171 ASSERT_THAT_ERROR( 3172 checkDataflowWithNoopAnalysis(Code), 3173 llvm::FailedWithMessage("Cannot analyze templated declarations")); 3174 } 3175 3176 TEST(TransferTest, VarDeclInitAssignConditionalOperator) { 3177 std::string Code = R"( 3178 struct A {}; 3179 3180 void target(A Foo, A Bar, bool Cond) { 3181 A Baz = Cond ? Foo : Bar; 3182 /*[[p]]*/ 3183 } 3184 )"; 3185 runDataflow( 3186 Code, 3187 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3188 ASTContext &ASTCtx) { 3189 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3190 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3191 3192 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3193 ASSERT_THAT(FooDecl, NotNull()); 3194 3195 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3196 ASSERT_THAT(BarDecl, NotNull()); 3197 3198 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3199 ASSERT_THAT(BazDecl, NotNull()); 3200 3201 const auto *FooVal = cast<RecordValue>(Env.getValue(*FooDecl)); 3202 const auto *BarVal = cast<RecordValue>(Env.getValue(*BarDecl)); 3203 3204 const auto *BazVal = dyn_cast<RecordValue>(Env.getValue(*BazDecl)); 3205 ASSERT_THAT(BazVal, NotNull()); 3206 3207 EXPECT_NE(BazVal, FooVal); 3208 EXPECT_NE(BazVal, BarVal); 3209 }); 3210 } 3211 3212 TEST(TransferTest, VarDeclInDoWhile) { 3213 std::string Code = R"( 3214 void target(int *Foo) { 3215 do { 3216 int Bar = *Foo; 3217 // [[in_loop]] 3218 } while (false); 3219 (void)0; 3220 // [[after_loop]] 3221 } 3222 )"; 3223 runDataflow( 3224 Code, 3225 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3226 ASTContext &ASTCtx) { 3227 const Environment &EnvInLoop = 3228 getEnvironmentAtAnnotation(Results, "in_loop"); 3229 const Environment &EnvAfterLoop = 3230 getEnvironmentAtAnnotation(Results, "after_loop"); 3231 3232 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3233 ASSERT_THAT(FooDecl, NotNull()); 3234 3235 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3236 ASSERT_THAT(BarDecl, NotNull()); 3237 3238 const auto *FooVal = 3239 cast<PointerValue>(EnvAfterLoop.getValue(*FooDecl)); 3240 const auto *FooPointeeVal = 3241 cast<IntegerValue>(EnvAfterLoop.getValue(FooVal->getPointeeLoc())); 3242 3243 const auto *BarVal = cast<IntegerValue>(EnvInLoop.getValue(*BarDecl)); 3244 EXPECT_EQ(BarVal, FooPointeeVal); 3245 3246 ASSERT_THAT(EnvAfterLoop.getValue(*BarDecl), IsNull()); 3247 }); 3248 } 3249 3250 TEST(TransferTest, UnreachableAfterWhileTrue) { 3251 std::string Code = R"( 3252 void target() { 3253 while (true) {} 3254 (void)0; 3255 /*[[p]]*/ 3256 } 3257 )"; 3258 runDataflow( 3259 Code, 3260 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3261 ASTContext &ASTCtx) { 3262 // The node after the while-true is pruned because it is trivially 3263 // known to be unreachable. 3264 ASSERT_TRUE(Results.empty()); 3265 }); 3266 } 3267 3268 TEST(TransferTest, AggregateInitialization) { 3269 std::string BracesCode = R"( 3270 struct A { 3271 int Foo; 3272 }; 3273 3274 struct B { 3275 int Bar; 3276 A Baz; 3277 int Qux; 3278 }; 3279 3280 void target(int BarArg, int FooArg, int QuxArg) { 3281 B Quux{BarArg, {FooArg}, QuxArg}; 3282 B OtherB; 3283 /*[[p]]*/ 3284 } 3285 )"; 3286 std::string BraceElisionCode = R"( 3287 struct A { 3288 int Foo; 3289 }; 3290 3291 struct B { 3292 int Bar; 3293 A Baz; 3294 int Qux; 3295 }; 3296 3297 void target(int BarArg, int FooArg, int QuxArg) { 3298 B Quux = {BarArg, FooArg, QuxArg}; 3299 B OtherB; 3300 /*[[p]]*/ 3301 } 3302 )"; 3303 for (const std::string &Code : {BracesCode, BraceElisionCode}) { 3304 runDataflow( 3305 Code, 3306 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3307 ASTContext &ASTCtx) { 3308 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3309 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3310 3311 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3312 ASSERT_THAT(FooDecl, NotNull()); 3313 3314 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3315 ASSERT_THAT(BarDecl, NotNull()); 3316 3317 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3318 ASSERT_THAT(BazDecl, NotNull()); 3319 3320 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 3321 ASSERT_THAT(QuxDecl, NotNull()); 3322 3323 const ValueDecl *FooArgDecl = findValueDecl(ASTCtx, "FooArg"); 3324 ASSERT_THAT(FooArgDecl, NotNull()); 3325 3326 const ValueDecl *BarArgDecl = findValueDecl(ASTCtx, "BarArg"); 3327 ASSERT_THAT(BarArgDecl, NotNull()); 3328 3329 const ValueDecl *QuxArgDecl = findValueDecl(ASTCtx, "QuxArg"); 3330 ASSERT_THAT(QuxArgDecl, NotNull()); 3331 3332 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 3333 ASSERT_THAT(QuuxDecl, NotNull()); 3334 3335 const auto *FooArgVal = cast<IntegerValue>(Env.getValue(*FooArgDecl)); 3336 const auto *BarArgVal = cast<IntegerValue>(Env.getValue(*BarArgDecl)); 3337 const auto *QuxArgVal = cast<IntegerValue>(Env.getValue(*QuxArgDecl)); 3338 3339 const auto &QuuxLoc = 3340 *cast<RecordStorageLocation>(Env.getStorageLocation(*QuuxDecl)); 3341 const auto &BazLoc = 3342 *cast<RecordStorageLocation>(QuuxLoc.getChild(*BazDecl)); 3343 3344 EXPECT_EQ(getFieldValue(&QuuxLoc, *BarDecl, Env), BarArgVal); 3345 EXPECT_EQ(getFieldValue(&BazLoc, *FooDecl, Env), FooArgVal); 3346 EXPECT_EQ(getFieldValue(&QuuxLoc, *QuxDecl, Env), QuxArgVal); 3347 3348 // Check that fields initialized in an initializer list are always 3349 // modeled in other instances of the same type. 3350 const auto &OtherBLoc = 3351 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "OtherB"); 3352 EXPECT_THAT(OtherBLoc.getChild(*BarDecl), NotNull()); 3353 EXPECT_THAT(OtherBLoc.getChild(*BazDecl), NotNull()); 3354 EXPECT_THAT(OtherBLoc.getChild(*QuxDecl), NotNull()); 3355 }); 3356 } 3357 } 3358 3359 TEST(TransferTest, AggregateInitializationReferenceField) { 3360 std::string Code = R"( 3361 struct S { 3362 int &RefField; 3363 }; 3364 3365 void target(int i) { 3366 S s = { i }; 3367 /*[[p]]*/ 3368 } 3369 )"; 3370 runDataflow( 3371 Code, 3372 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3373 ASTContext &ASTCtx) { 3374 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3375 3376 const ValueDecl *RefFieldDecl = findValueDecl(ASTCtx, "RefField"); 3377 3378 auto &ILoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "i"); 3379 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"); 3380 3381 EXPECT_EQ(SLoc.getChild(*RefFieldDecl), &ILoc); 3382 }); 3383 } 3384 3385 TEST(TransferTest, AggregateInitialization_NotExplicitlyInitializedField) { 3386 std::string Code = R"( 3387 struct S { 3388 int i1; 3389 int i2; 3390 }; 3391 3392 void target(int i) { 3393 S s = { i }; 3394 /*[[p]]*/ 3395 } 3396 )"; 3397 runDataflow( 3398 Code, 3399 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3400 ASTContext &ASTCtx) { 3401 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3402 3403 const ValueDecl *I1FieldDecl = findValueDecl(ASTCtx, "i1"); 3404 const ValueDecl *I2FieldDecl = findValueDecl(ASTCtx, "i2"); 3405 3406 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"); 3407 3408 auto &IValue = getValueForDecl<IntegerValue>(ASTCtx, Env, "i"); 3409 auto &I1Value = 3410 *cast<IntegerValue>(getFieldValue(&SLoc, *I1FieldDecl, Env)); 3411 EXPECT_EQ(&I1Value, &IValue); 3412 auto &I2Value = 3413 *cast<IntegerValue>(getFieldValue(&SLoc, *I2FieldDecl, Env)); 3414 EXPECT_NE(&I2Value, &IValue); 3415 }); 3416 } 3417 3418 TEST(TransferTest, AggregateInitializationFunctionPointer) { 3419 // This is a repro for an assertion failure. 3420 // nullptr takes on the type of a const function pointer, but its type was 3421 // asserted to be equal to the *unqualified* type of Field, which no longer 3422 // included the const. 3423 std::string Code = R"( 3424 struct S { 3425 void (*const Field)(); 3426 }; 3427 3428 void target() { 3429 S s{nullptr}; 3430 } 3431 )"; 3432 runDataflow( 3433 Code, 3434 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3435 ASTContext &ASTCtx) {}); 3436 } 3437 3438 TEST(TransferTest, AssignToUnionMember) { 3439 std::string Code = R"( 3440 union A { 3441 int Foo; 3442 }; 3443 3444 void target(int Bar) { 3445 A Baz; 3446 Baz.Foo = Bar; 3447 // [[p]] 3448 } 3449 )"; 3450 runDataflow( 3451 Code, 3452 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3453 ASTContext &ASTCtx) { 3454 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3455 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3456 3457 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3458 ASSERT_THAT(BazDecl, NotNull()); 3459 ASSERT_TRUE(BazDecl->getType()->isUnionType()); 3460 3461 auto BazFields = BazDecl->getType()->getAsRecordDecl()->fields(); 3462 FieldDecl *FooDecl = nullptr; 3463 for (FieldDecl *Field : BazFields) { 3464 if (Field->getNameAsString() == "Foo") { 3465 FooDecl = Field; 3466 } else { 3467 FAIL() << "Unexpected field: " << Field->getNameAsString(); 3468 } 3469 } 3470 ASSERT_THAT(FooDecl, NotNull()); 3471 3472 const auto *BazLoc = dyn_cast_or_null<RecordStorageLocation>( 3473 Env.getStorageLocation(*BazDecl)); 3474 ASSERT_THAT(BazLoc, NotNull()); 3475 ASSERT_THAT(Env.getValue(*BazLoc), NotNull()); 3476 3477 const auto *FooVal = 3478 cast<IntegerValue>(getFieldValue(BazLoc, *FooDecl, Env)); 3479 3480 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3481 ASSERT_THAT(BarDecl, NotNull()); 3482 const auto *BarLoc = Env.getStorageLocation(*BarDecl); 3483 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 3484 3485 EXPECT_EQ(Env.getValue(*BarLoc), FooVal); 3486 }); 3487 } 3488 3489 TEST(TransferTest, AssignFromBoolLiteral) { 3490 std::string Code = R"( 3491 void target() { 3492 bool Foo = true; 3493 bool Bar = false; 3494 // [[p]] 3495 } 3496 )"; 3497 runDataflow( 3498 Code, 3499 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3500 ASTContext &ASTCtx) { 3501 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3502 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3503 3504 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3505 ASSERT_THAT(FooDecl, NotNull()); 3506 3507 const auto *FooVal = 3508 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3509 ASSERT_THAT(FooVal, NotNull()); 3510 3511 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3512 ASSERT_THAT(BarDecl, NotNull()); 3513 3514 const auto *BarVal = 3515 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 3516 ASSERT_THAT(BarVal, NotNull()); 3517 3518 EXPECT_EQ(FooVal, &Env.getBoolLiteralValue(true)); 3519 EXPECT_EQ(BarVal, &Env.getBoolLiteralValue(false)); 3520 }); 3521 } 3522 3523 TEST(TransferTest, AssignFromCompositeBoolExpression) { 3524 { 3525 std::string Code = R"( 3526 void target(bool Foo, bool Bar, bool Qux) { 3527 bool Baz = (Foo) && (Bar || Qux); 3528 // [[p]] 3529 } 3530 )"; 3531 runDataflow( 3532 Code, 3533 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3534 ASTContext &ASTCtx) { 3535 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3536 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3537 3538 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3539 ASSERT_THAT(FooDecl, NotNull()); 3540 3541 const auto *FooVal = 3542 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3543 ASSERT_THAT(FooVal, NotNull()); 3544 3545 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3546 ASSERT_THAT(BarDecl, NotNull()); 3547 3548 const auto *BarVal = 3549 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 3550 ASSERT_THAT(BarVal, NotNull()); 3551 3552 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 3553 ASSERT_THAT(QuxDecl, NotNull()); 3554 3555 const auto *QuxVal = 3556 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl)); 3557 ASSERT_THAT(QuxVal, NotNull()); 3558 3559 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3560 ASSERT_THAT(BazDecl, NotNull()); 3561 3562 const auto *BazVal = 3563 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl)); 3564 ASSERT_THAT(BazVal, NotNull()); 3565 auto &A = Env.arena(); 3566 EXPECT_EQ(&BazVal->formula(), 3567 &A.makeAnd(FooVal->formula(), 3568 A.makeOr(BarVal->formula(), QuxVal->formula()))); 3569 }); 3570 } 3571 3572 { 3573 std::string Code = R"( 3574 void target(bool Foo, bool Bar, bool Qux) { 3575 bool Baz = (Foo && Qux) || (Bar); 3576 // [[p]] 3577 } 3578 )"; 3579 runDataflow( 3580 Code, 3581 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3582 ASTContext &ASTCtx) { 3583 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3584 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3585 3586 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3587 ASSERT_THAT(FooDecl, NotNull()); 3588 3589 const auto *FooVal = 3590 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3591 ASSERT_THAT(FooVal, NotNull()); 3592 3593 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3594 ASSERT_THAT(BarDecl, NotNull()); 3595 3596 const auto *BarVal = 3597 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 3598 ASSERT_THAT(BarVal, NotNull()); 3599 3600 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 3601 ASSERT_THAT(QuxDecl, NotNull()); 3602 3603 const auto *QuxVal = 3604 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl)); 3605 ASSERT_THAT(QuxVal, NotNull()); 3606 3607 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3608 ASSERT_THAT(BazDecl, NotNull()); 3609 3610 const auto *BazVal = 3611 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl)); 3612 ASSERT_THAT(BazVal, NotNull()); 3613 auto &A = Env.arena(); 3614 EXPECT_EQ(&BazVal->formula(), 3615 &A.makeOr(A.makeAnd(FooVal->formula(), QuxVal->formula()), 3616 BarVal->formula())); 3617 }); 3618 } 3619 3620 { 3621 std::string Code = R"( 3622 void target(bool A, bool B, bool C, bool D) { 3623 bool Foo = ((A && B) && C) && D; 3624 // [[p]] 3625 } 3626 )"; 3627 runDataflow( 3628 Code, 3629 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3630 ASTContext &ASTCtx) { 3631 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3632 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3633 3634 const ValueDecl *ADecl = findValueDecl(ASTCtx, "A"); 3635 ASSERT_THAT(ADecl, NotNull()); 3636 3637 const auto *AVal = dyn_cast_or_null<BoolValue>(Env.getValue(*ADecl)); 3638 ASSERT_THAT(AVal, NotNull()); 3639 3640 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B"); 3641 ASSERT_THAT(BDecl, NotNull()); 3642 3643 const auto *BVal = dyn_cast_or_null<BoolValue>(Env.getValue(*BDecl)); 3644 ASSERT_THAT(BVal, NotNull()); 3645 3646 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C"); 3647 ASSERT_THAT(CDecl, NotNull()); 3648 3649 const auto *CVal = dyn_cast_or_null<BoolValue>(Env.getValue(*CDecl)); 3650 ASSERT_THAT(CVal, NotNull()); 3651 3652 const ValueDecl *DDecl = findValueDecl(ASTCtx, "D"); 3653 ASSERT_THAT(DDecl, NotNull()); 3654 3655 const auto *DVal = dyn_cast_or_null<BoolValue>(Env.getValue(*DDecl)); 3656 ASSERT_THAT(DVal, NotNull()); 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 auto &A = Env.arena(); 3665 EXPECT_EQ( 3666 &FooVal->formula(), 3667 &A.makeAnd(A.makeAnd(A.makeAnd(AVal->formula(), BVal->formula()), 3668 CVal->formula()), 3669 DVal->formula())); 3670 }); 3671 } 3672 } 3673 3674 TEST(TransferTest, AssignFromBoolNegation) { 3675 std::string Code = R"( 3676 void target() { 3677 bool Foo = true; 3678 bool Bar = !(Foo); 3679 // [[p]] 3680 } 3681 )"; 3682 runDataflow( 3683 Code, 3684 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3685 ASTContext &ASTCtx) { 3686 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3687 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3688 3689 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3690 ASSERT_THAT(FooDecl, NotNull()); 3691 3692 const auto *FooVal = 3693 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3694 ASSERT_THAT(FooVal, NotNull()); 3695 3696 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3697 ASSERT_THAT(BarDecl, NotNull()); 3698 3699 const auto *BarVal = 3700 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 3701 ASSERT_THAT(BarVal, NotNull()); 3702 auto &A = Env.arena(); 3703 EXPECT_EQ(&BarVal->formula(), &A.makeNot(FooVal->formula())); 3704 }); 3705 } 3706 3707 TEST(TransferTest, BuiltinExpect) { 3708 std::string Code = R"( 3709 void target(long Foo) { 3710 long Bar = __builtin_expect(Foo, true); 3711 /*[[p]]*/ 3712 } 3713 )"; 3714 runDataflow( 3715 Code, 3716 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3717 ASTContext &ASTCtx) { 3718 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3719 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3720 3721 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3722 ASSERT_THAT(FooDecl, NotNull()); 3723 3724 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3725 ASSERT_THAT(BarDecl, NotNull()); 3726 3727 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3728 }); 3729 } 3730 3731 // `__builtin_expect` takes and returns a `long` argument, so other types 3732 // involve casts. This verifies that we identify the input and output in that 3733 // case. 3734 TEST(TransferTest, BuiltinExpectBoolArg) { 3735 std::string Code = R"( 3736 void target(bool Foo) { 3737 bool Bar = __builtin_expect(Foo, true); 3738 /*[[p]]*/ 3739 } 3740 )"; 3741 runDataflow( 3742 Code, 3743 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3744 ASTContext &ASTCtx) { 3745 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3746 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3747 3748 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3749 ASSERT_THAT(FooDecl, NotNull()); 3750 3751 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3752 ASSERT_THAT(BarDecl, NotNull()); 3753 3754 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3755 }); 3756 } 3757 3758 TEST(TransferTest, BuiltinUnreachable) { 3759 std::string Code = R"( 3760 void target(bool Foo) { 3761 bool Bar = false; 3762 if (Foo) 3763 Bar = Foo; 3764 else 3765 __builtin_unreachable(); 3766 (void)0; 3767 /*[[p]]*/ 3768 } 3769 )"; 3770 runDataflow( 3771 Code, 3772 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3773 ASTContext &ASTCtx) { 3774 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3775 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3776 3777 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3778 ASSERT_THAT(FooDecl, NotNull()); 3779 3780 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3781 ASSERT_THAT(BarDecl, NotNull()); 3782 3783 // `__builtin_unreachable` promises that the code is 3784 // unreachable, so the compiler treats the "then" branch as the 3785 // only possible predecessor of this statement. 3786 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3787 }); 3788 } 3789 3790 TEST(TransferTest, BuiltinTrap) { 3791 std::string Code = R"( 3792 void target(bool Foo) { 3793 bool Bar = false; 3794 if (Foo) 3795 Bar = Foo; 3796 else 3797 __builtin_trap(); 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_trap` ensures program termination, so only the 3816 // "then" branch is a predecessor of this statement. 3817 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3818 }); 3819 } 3820 3821 TEST(TransferTest, BuiltinDebugTrap) { 3822 std::string Code = R"( 3823 void target(bool Foo) { 3824 bool Bar = false; 3825 if (Foo) 3826 Bar = Foo; 3827 else 3828 __builtin_debugtrap(); 3829 (void)0; 3830 /*[[p]]*/ 3831 } 3832 )"; 3833 runDataflow( 3834 Code, 3835 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3836 ASTContext &ASTCtx) { 3837 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3838 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3839 3840 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3841 ASSERT_THAT(FooDecl, NotNull()); 3842 3843 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3844 ASSERT_THAT(BarDecl, NotNull()); 3845 3846 // `__builtin_debugtrap` doesn't ensure program termination. 3847 EXPECT_NE(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3848 }); 3849 } 3850 3851 TEST(TransferTest, StaticIntSingleVarDecl) { 3852 std::string Code = R"( 3853 void target() { 3854 static int Foo; 3855 // [[p]] 3856 } 3857 )"; 3858 runDataflow( 3859 Code, 3860 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3861 ASTContext &ASTCtx) { 3862 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3863 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3864 3865 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3866 ASSERT_THAT(FooDecl, NotNull()); 3867 3868 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 3869 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 3870 3871 const Value *FooVal = Env.getValue(*FooLoc); 3872 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 3873 }); 3874 } 3875 3876 TEST(TransferTest, StaticIntGroupVarDecl) { 3877 std::string Code = R"( 3878 void target() { 3879 static int Foo, Bar; 3880 (void)0; 3881 // [[p]] 3882 } 3883 )"; 3884 runDataflow( 3885 Code, 3886 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3887 ASTContext &ASTCtx) { 3888 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3889 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3890 3891 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3892 ASSERT_THAT(FooDecl, NotNull()); 3893 3894 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3895 ASSERT_THAT(BarDecl, NotNull()); 3896 3897 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 3898 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 3899 3900 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 3901 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 3902 3903 const Value *FooVal = Env.getValue(*FooLoc); 3904 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 3905 3906 const Value *BarVal = Env.getValue(*BarLoc); 3907 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 3908 3909 EXPECT_NE(FooVal, BarVal); 3910 }); 3911 } 3912 3913 TEST(TransferTest, GlobalIntVarDecl) { 3914 std::string Code = R"( 3915 static int Foo; 3916 3917 void target() { 3918 int Bar = Foo; 3919 int Baz = 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, StaticMemberIntVarDecl) { 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, StaticMemberRefVarDecl) { 3974 std::string Code = R"( 3975 struct A { 3976 static int &Foo; 3977 }; 3978 3979 void target(A a) { 3980 int Bar = a.Foo; 3981 int Baz = a.Foo; 3982 // [[p]] 3983 } 3984 )"; 3985 runDataflow( 3986 Code, 3987 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3988 ASTContext &ASTCtx) { 3989 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3990 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3991 3992 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3993 ASSERT_THAT(BarDecl, NotNull()); 3994 3995 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3996 ASSERT_THAT(BazDecl, NotNull()); 3997 3998 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 3999 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 4000 EXPECT_EQ(BarVal, BazVal); 4001 }); 4002 } 4003 4004 TEST(TransferTest, AssignMemberBeforeCopy) { 4005 std::string Code = R"( 4006 struct A { 4007 int Foo; 4008 }; 4009 4010 void target() { 4011 A A1; 4012 A A2; 4013 int Bar; 4014 A1.Foo = Bar; 4015 A2 = A1; 4016 // [[p]] 4017 } 4018 )"; 4019 runDataflow( 4020 Code, 4021 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4022 ASTContext &ASTCtx) { 4023 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4024 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4025 4026 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4027 ASSERT_THAT(FooDecl, NotNull()); 4028 4029 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4030 ASSERT_THAT(BarDecl, NotNull()); 4031 4032 const ValueDecl *A1Decl = findValueDecl(ASTCtx, "A1"); 4033 ASSERT_THAT(A1Decl, NotNull()); 4034 4035 const ValueDecl *A2Decl = findValueDecl(ASTCtx, "A2"); 4036 ASSERT_THAT(A2Decl, NotNull()); 4037 4038 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 4039 4040 const auto &A2Loc = 4041 *cast<RecordStorageLocation>(Env.getStorageLocation(*A2Decl)); 4042 EXPECT_EQ(getFieldValue(&A2Loc, *FooDecl, Env), BarVal); 4043 }); 4044 } 4045 4046 TEST(TransferTest, BooleanEquality) { 4047 std::string Code = R"( 4048 void target(bool Bar) { 4049 bool Foo = true; 4050 if (Bar == Foo) { 4051 (void)0; 4052 /*[[p-then]]*/ 4053 } else { 4054 (void)0; 4055 /*[[p-else]]*/ 4056 } 4057 } 4058 )"; 4059 runDataflow( 4060 Code, 4061 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4062 ASTContext &ASTCtx) { 4063 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else")); 4064 const Environment &EnvThen = 4065 getEnvironmentAtAnnotation(Results, "p-then"); 4066 const Environment &EnvElse = 4067 getEnvironmentAtAnnotation(Results, "p-else"); 4068 4069 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4070 ASSERT_THAT(BarDecl, NotNull()); 4071 4072 auto &BarValThen = getFormula(*BarDecl, EnvThen); 4073 EXPECT_TRUE(EnvThen.proves(BarValThen)); 4074 4075 auto &BarValElse = getFormula(*BarDecl, EnvElse); 4076 EXPECT_TRUE(EnvElse.proves(EnvElse.arena().makeNot(BarValElse))); 4077 }); 4078 } 4079 4080 TEST(TransferTest, BooleanInequality) { 4081 std::string Code = R"( 4082 void target(bool Bar) { 4083 bool Foo = true; 4084 if (Bar != Foo) { 4085 (void)0; 4086 /*[[p-then]]*/ 4087 } else { 4088 (void)0; 4089 /*[[p-else]]*/ 4090 } 4091 } 4092 )"; 4093 runDataflow( 4094 Code, 4095 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4096 ASTContext &ASTCtx) { 4097 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else")); 4098 const Environment &EnvThen = 4099 getEnvironmentAtAnnotation(Results, "p-then"); 4100 const Environment &EnvElse = 4101 getEnvironmentAtAnnotation(Results, "p-else"); 4102 4103 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4104 ASSERT_THAT(BarDecl, NotNull()); 4105 4106 auto &BarValThen = getFormula(*BarDecl, EnvThen); 4107 EXPECT_TRUE(EnvThen.proves(EnvThen.arena().makeNot(BarValThen))); 4108 4109 auto &BarValElse = getFormula(*BarDecl, EnvElse); 4110 EXPECT_TRUE(EnvElse.proves(BarValElse)); 4111 }); 4112 } 4113 4114 TEST(TransferTest, IntegerLiteralEquality) { 4115 std::string Code = R"( 4116 void target() { 4117 bool equal = (42 == 42); 4118 // [[p]] 4119 } 4120 )"; 4121 runDataflow( 4122 Code, 4123 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4124 ASTContext &ASTCtx) { 4125 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4126 4127 auto &Equal = 4128 getValueForDecl<BoolValue>(ASTCtx, Env, "equal").formula(); 4129 EXPECT_TRUE(Env.proves(Equal)); 4130 }); 4131 } 4132 4133 TEST(TransferTest, CorrelatedBranches) { 4134 std::string Code = R"( 4135 void target(bool B, bool C) { 4136 if (B) { 4137 return; 4138 } 4139 (void)0; 4140 /*[[p0]]*/ 4141 if (C) { 4142 B = true; 4143 /*[[p1]]*/ 4144 } 4145 if (B) { 4146 (void)0; 4147 /*[[p2]]*/ 4148 } 4149 } 4150 )"; 4151 runDataflow( 4152 Code, 4153 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4154 ASTContext &ASTCtx) { 4155 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p0", "p1", "p2")); 4156 4157 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C"); 4158 ASSERT_THAT(CDecl, NotNull()); 4159 4160 { 4161 const Environment &Env = getEnvironmentAtAnnotation(Results, "p0"); 4162 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B"); 4163 ASSERT_THAT(BDecl, NotNull()); 4164 auto &BVal = getFormula(*BDecl, Env); 4165 4166 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BVal))); 4167 } 4168 4169 { 4170 const Environment &Env = getEnvironmentAtAnnotation(Results, "p1"); 4171 auto &CVal = getFormula(*CDecl, Env); 4172 EXPECT_TRUE(Env.proves(CVal)); 4173 } 4174 4175 { 4176 const Environment &Env = getEnvironmentAtAnnotation(Results, "p2"); 4177 auto &CVal = getFormula(*CDecl, Env); 4178 EXPECT_TRUE(Env.proves(CVal)); 4179 } 4180 }); 4181 } 4182 4183 TEST(TransferTest, LoopWithAssignmentConverges) { 4184 std::string Code = R"( 4185 bool foo(); 4186 4187 void target() { 4188 do { 4189 bool Bar = foo(); 4190 if (Bar) break; 4191 (void)Bar; 4192 /*[[p]]*/ 4193 } while (true); 4194 } 4195 )"; 4196 // The key property that we are verifying is implicit in `runDataflow` -- 4197 // namely, that the analysis succeeds, rather than hitting the maximum number 4198 // of iterations. 4199 runDataflow( 4200 Code, 4201 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4202 ASTContext &ASTCtx) { 4203 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4204 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4205 4206 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4207 ASSERT_THAT(BarDecl, NotNull()); 4208 4209 auto &BarVal = getFormula(*BarDecl, Env); 4210 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 4211 }); 4212 } 4213 4214 TEST(TransferTest, LoopWithStagedAssignments) { 4215 std::string Code = R"( 4216 bool foo(); 4217 4218 void target() { 4219 bool Bar = false; 4220 bool Err = false; 4221 while (foo()) { 4222 if (Bar) 4223 Err = true; 4224 Bar = true; 4225 /*[[p]]*/ 4226 } 4227 } 4228 )"; 4229 runDataflow( 4230 Code, 4231 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4232 ASTContext &ASTCtx) { 4233 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4234 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4235 4236 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4237 ASSERT_THAT(BarDecl, NotNull()); 4238 const ValueDecl *ErrDecl = findValueDecl(ASTCtx, "Err"); 4239 ASSERT_THAT(ErrDecl, NotNull()); 4240 4241 auto &BarVal = getFormula(*BarDecl, Env); 4242 auto &ErrVal = getFormula(*ErrDecl, Env); 4243 EXPECT_TRUE(Env.proves(BarVal)); 4244 // An unsound analysis, for example only evaluating the loop once, can 4245 // conclude that `Err` is false. So, we test that this conclusion is not 4246 // reached. 4247 EXPECT_FALSE(Env.proves(Env.arena().makeNot(ErrVal))); 4248 }); 4249 } 4250 4251 TEST(TransferTest, LoopWithReferenceAssignmentConverges) { 4252 std::string Code = R"( 4253 bool &foo(); 4254 4255 void target() { 4256 do { 4257 bool& Bar = foo(); 4258 if (Bar) break; 4259 (void)Bar; 4260 /*[[p]]*/ 4261 } while (true); 4262 } 4263 )"; 4264 // The key property that we are verifying is that the analysis succeeds, 4265 // rather than hitting the maximum number of iterations. 4266 runDataflow( 4267 Code, 4268 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4269 ASTContext &ASTCtx) { 4270 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4271 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4272 4273 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4274 ASSERT_THAT(BarDecl, NotNull()); 4275 4276 auto &BarVal = getFormula(*BarDecl, Env); 4277 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 4278 }); 4279 } 4280 4281 TEST(TransferTest, LoopWithStructReferenceAssignmentConverges) { 4282 std::string Code = R"( 4283 struct Lookup { 4284 int x; 4285 }; 4286 4287 void target(Lookup val, bool b) { 4288 const Lookup* l = nullptr; 4289 while (b) { 4290 l = &val; 4291 /*[[p-inner]]*/ 4292 } 4293 (void)0; 4294 /*[[p-outer]]*/ 4295 } 4296 )"; 4297 // The key property that we are verifying is implicit in `runDataflow` -- 4298 // namely, that the analysis succeeds, rather than hitting the maximum number 4299 // of iterations. 4300 runDataflow( 4301 Code, 4302 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4303 ASTContext &ASTCtx) { 4304 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-inner", "p-outer")); 4305 const Environment &InnerEnv = 4306 getEnvironmentAtAnnotation(Results, "p-inner"); 4307 const Environment &OuterEnv = 4308 getEnvironmentAtAnnotation(Results, "p-outer"); 4309 4310 const ValueDecl *ValDecl = findValueDecl(ASTCtx, "val"); 4311 ASSERT_THAT(ValDecl, NotNull()); 4312 4313 const ValueDecl *LDecl = findValueDecl(ASTCtx, "l"); 4314 ASSERT_THAT(LDecl, NotNull()); 4315 4316 // Inner. 4317 auto *LVal = dyn_cast<PointerValue>(InnerEnv.getValue(*LDecl)); 4318 ASSERT_THAT(LVal, NotNull()); 4319 4320 EXPECT_EQ(&LVal->getPointeeLoc(), 4321 InnerEnv.getStorageLocation(*ValDecl)); 4322 4323 // Outer. 4324 LVal = dyn_cast<PointerValue>(OuterEnv.getValue(*LDecl)); 4325 ASSERT_THAT(LVal, NotNull()); 4326 4327 // The loop body may not have been executed, so we should not conclude 4328 // that `l` points to `val`. 4329 EXPECT_NE(&LVal->getPointeeLoc(), 4330 OuterEnv.getStorageLocation(*ValDecl)); 4331 }); 4332 } 4333 4334 TEST(TransferTest, LoopDereferencingChangingPointerConverges) { 4335 std::string Code = R"cc( 4336 bool some_condition(); 4337 4338 void target(int i1, int i2) { 4339 int *p = &i1; 4340 while (true) { 4341 (void)*p; 4342 if (some_condition()) 4343 p = &i1; 4344 else 4345 p = &i2; 4346 } 4347 } 4348 )cc"; 4349 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 4350 } 4351 4352 TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) { 4353 std::string Code = R"cc( 4354 struct Lookup { 4355 int x; 4356 }; 4357 4358 bool some_condition(); 4359 4360 void target(Lookup l1, Lookup l2) { 4361 Lookup *l = &l1; 4362 while (true) { 4363 (void)l->x; 4364 if (some_condition()) 4365 l = &l1; 4366 else 4367 l = &l2; 4368 } 4369 } 4370 )cc"; 4371 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 4372 } 4373 4374 TEST(TransferTest, LoopWithShortCircuitedConditionConverges) { 4375 std::string Code = R"cc( 4376 bool foo(); 4377 4378 void target() { 4379 bool c = false; 4380 while (foo() || foo()) { 4381 c = true; 4382 } 4383 } 4384 )cc"; 4385 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 4386 } 4387 4388 TEST(TransferTest, LoopCanProveInvariantForBoolean) { 4389 // Check that we can prove `b` is always false in the loop. 4390 // This test exercises the logic in `widenDistinctValues()` that preserves 4391 // information if the boolean can be proved to be either true or false in both 4392 // the previous and current iteration. 4393 std::string Code = R"cc( 4394 int return_int(); 4395 void target() { 4396 bool b = return_int() == 0; 4397 if (b) return; 4398 while (true) { 4399 b; 4400 // [[p]] 4401 b = return_int() == 0; 4402 if (b) return; 4403 } 4404 } 4405 )cc"; 4406 runDataflow( 4407 Code, 4408 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4409 ASTContext &ASTCtx) { 4410 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4411 auto &BVal = getValueForDecl<BoolValue>(ASTCtx, Env, "b"); 4412 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BVal.formula()))); 4413 }); 4414 } 4415 4416 TEST(TransferTest, DoesNotCrashOnUnionThisExpr) { 4417 std::string Code = R"( 4418 union Union { 4419 int A; 4420 float B; 4421 }; 4422 4423 void foo() { 4424 Union A; 4425 Union B; 4426 A = B; 4427 } 4428 )"; 4429 // This is a crash regression test when calling the transfer function on a 4430 // `CXXThisExpr` that refers to a union. 4431 runDataflow( 4432 Code, 4433 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &, 4434 ASTContext &) {}, 4435 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator="); 4436 } 4437 4438 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToRefs) { 4439 std::string Code = R"( 4440 struct A { 4441 int Foo; 4442 int Bar; 4443 }; 4444 4445 void target() { 4446 int Qux; 4447 A Baz; 4448 Baz.Foo = Qux; 4449 auto &FooRef = Baz.Foo; 4450 auto &BarRef = Baz.Bar; 4451 auto &[BoundFooRef, BoundBarRef] = Baz; 4452 // [[p]] 4453 } 4454 )"; 4455 runDataflow( 4456 Code, 4457 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4458 ASTContext &ASTCtx) { 4459 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4460 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4461 4462 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 4463 ASSERT_THAT(FooRefDecl, NotNull()); 4464 4465 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 4466 ASSERT_THAT(BarRefDecl, NotNull()); 4467 4468 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4469 ASSERT_THAT(QuxDecl, NotNull()); 4470 4471 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef"); 4472 ASSERT_THAT(BoundFooRefDecl, NotNull()); 4473 4474 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef"); 4475 ASSERT_THAT(BoundBarRefDecl, NotNull()); 4476 4477 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 4478 ASSERT_THAT(FooRefLoc, NotNull()); 4479 4480 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 4481 ASSERT_THAT(BarRefLoc, NotNull()); 4482 4483 const Value *QuxVal = Env.getValue(*QuxDecl); 4484 ASSERT_THAT(QuxVal, NotNull()); 4485 4486 const StorageLocation *BoundFooRefLoc = 4487 Env.getStorageLocation(*BoundFooRefDecl); 4488 EXPECT_EQ(BoundFooRefLoc, FooRefLoc); 4489 4490 const StorageLocation *BoundBarRefLoc = 4491 Env.getStorageLocation(*BoundBarRefDecl); 4492 EXPECT_EQ(BoundBarRefLoc, BarRefLoc); 4493 4494 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal); 4495 }); 4496 } 4497 4498 TEST(TransferTest, StructuredBindingAssignFromStructRefMembersToRefs) { 4499 std::string Code = R"( 4500 struct A { 4501 int &Foo; 4502 int &Bar; 4503 }; 4504 4505 void target(A Baz) { 4506 int Qux; 4507 Baz.Foo = Qux; 4508 auto &FooRef = Baz.Foo; 4509 auto &BarRef = Baz.Bar; 4510 auto &[BoundFooRef, BoundBarRef] = Baz; 4511 // [[p]] 4512 } 4513 )"; 4514 runDataflow( 4515 Code, 4516 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4517 ASTContext &ASTCtx) { 4518 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4519 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4520 4521 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 4522 ASSERT_THAT(FooRefDecl, NotNull()); 4523 4524 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 4525 ASSERT_THAT(BarRefDecl, NotNull()); 4526 4527 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4528 ASSERT_THAT(QuxDecl, NotNull()); 4529 4530 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef"); 4531 ASSERT_THAT(BoundFooRefDecl, NotNull()); 4532 4533 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef"); 4534 ASSERT_THAT(BoundBarRefDecl, NotNull()); 4535 4536 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 4537 ASSERT_THAT(FooRefLoc, NotNull()); 4538 4539 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 4540 ASSERT_THAT(BarRefLoc, NotNull()); 4541 4542 const Value *QuxVal = Env.getValue(*QuxDecl); 4543 ASSERT_THAT(QuxVal, NotNull()); 4544 4545 const StorageLocation *BoundFooRefLoc = 4546 Env.getStorageLocation(*BoundFooRefDecl); 4547 EXPECT_EQ(BoundFooRefLoc, FooRefLoc); 4548 4549 const StorageLocation *BoundBarRefLoc = 4550 Env.getStorageLocation(*BoundBarRefDecl); 4551 EXPECT_EQ(BoundBarRefLoc, BarRefLoc); 4552 4553 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal); 4554 }); 4555 } 4556 4557 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToInts) { 4558 std::string Code = R"( 4559 struct A { 4560 int Foo; 4561 int Bar; 4562 }; 4563 4564 void target() { 4565 int Qux; 4566 A Baz; 4567 Baz.Foo = Qux; 4568 auto &FooRef = Baz.Foo; 4569 auto &BarRef = Baz.Bar; 4570 auto [BoundFoo, BoundBar] = Baz; 4571 // [[p]] 4572 } 4573 )"; 4574 runDataflow( 4575 Code, 4576 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4577 ASTContext &ASTCtx) { 4578 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4579 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4580 4581 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 4582 ASSERT_THAT(FooRefDecl, NotNull()); 4583 4584 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 4585 ASSERT_THAT(BarRefDecl, NotNull()); 4586 4587 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 4588 ASSERT_THAT(BoundFooDecl, NotNull()); 4589 4590 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 4591 ASSERT_THAT(BoundBarDecl, NotNull()); 4592 4593 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4594 ASSERT_THAT(QuxDecl, NotNull()); 4595 4596 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 4597 ASSERT_THAT(FooRefLoc, NotNull()); 4598 4599 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 4600 ASSERT_THAT(BarRefLoc, NotNull()); 4601 4602 const Value *QuxVal = Env.getValue(*QuxDecl); 4603 ASSERT_THAT(QuxVal, NotNull()); 4604 4605 const StorageLocation *BoundFooLoc = 4606 Env.getStorageLocation(*BoundFooDecl); 4607 EXPECT_NE(BoundFooLoc, FooRefLoc); 4608 4609 const StorageLocation *BoundBarLoc = 4610 Env.getStorageLocation(*BoundBarDecl); 4611 EXPECT_NE(BoundBarLoc, BarRefLoc); 4612 4613 EXPECT_EQ(Env.getValue(*BoundFooDecl), QuxVal); 4614 }); 4615 } 4616 4617 TEST(TransferTest, StructuredBindingAssignFromTupleLikeType) { 4618 std::string Code = R"( 4619 namespace std { 4620 using size_t = int; 4621 template <class> struct tuple_size; 4622 template <std::size_t, class> struct tuple_element; 4623 template <class...> class tuple; 4624 4625 namespace { 4626 template <class T, T v> 4627 struct size_helper { static const T value = v; }; 4628 } // namespace 4629 4630 template <class... T> 4631 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {}; 4632 4633 template <std::size_t I, class... T> 4634 struct tuple_element<I, tuple<T...>> { 4635 using type = __type_pack_element<I, T...>; 4636 }; 4637 4638 template <class...> class tuple {}; 4639 4640 template <std::size_t I, class... T> 4641 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 4642 } // namespace std 4643 4644 std::tuple<bool, int> makeTuple(); 4645 4646 void target(bool B) { 4647 auto [BoundFoo, BoundBar] = makeTuple(); 4648 bool Baz; 4649 // Include if-then-else to test interaction of `BindingDecl` with join. 4650 if (B) { 4651 Baz = BoundFoo; 4652 (void)BoundBar; 4653 // [[p1]] 4654 } else { 4655 Baz = BoundFoo; 4656 } 4657 (void)0; 4658 // [[p2]] 4659 } 4660 )"; 4661 runDataflow( 4662 Code, 4663 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4664 ASTContext &ASTCtx) { 4665 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 4666 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 4667 4668 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 4669 ASSERT_THAT(BoundFooDecl, NotNull()); 4670 4671 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 4672 ASSERT_THAT(BoundBarDecl, NotNull()); 4673 4674 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4675 ASSERT_THAT(BazDecl, NotNull()); 4676 4677 // BindingDecls always map to references -- either lvalue or rvalue, so 4678 // we still need to skip here. 4679 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl); 4680 ASSERT_THAT(BoundFooValue, NotNull()); 4681 EXPECT_TRUE(isa<BoolValue>(BoundFooValue)); 4682 4683 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl); 4684 ASSERT_THAT(BoundBarValue, NotNull()); 4685 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue)); 4686 4687 // Test that a `DeclRefExpr` to a `BindingDecl` works as expected. 4688 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue); 4689 4690 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 4691 4692 // Test that `BoundFooDecl` retains the value we expect, after the join. 4693 BoundFooValue = Env2.getValue(*BoundFooDecl); 4694 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue); 4695 }); 4696 } 4697 4698 TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) { 4699 std::string Code = R"( 4700 namespace std { 4701 using size_t = int; 4702 template <class> struct tuple_size; 4703 template <std::size_t, class> struct tuple_element; 4704 template <class...> class tuple; 4705 4706 namespace { 4707 template <class T, T v> 4708 struct size_helper { static const T value = v; }; 4709 } // namespace 4710 4711 template <class... T> 4712 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {}; 4713 4714 template <std::size_t I, class... T> 4715 struct tuple_element<I, tuple<T...>> { 4716 using type = __type_pack_element<I, T...>; 4717 }; 4718 4719 template <class...> class tuple {}; 4720 4721 template <std::size_t I, class... T> 4722 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 4723 } // namespace std 4724 4725 std::tuple<bool, int> &getTuple(); 4726 4727 void target(bool B) { 4728 auto &[BoundFoo, BoundBar] = getTuple(); 4729 bool Baz; 4730 // Include if-then-else to test interaction of `BindingDecl` with join. 4731 if (B) { 4732 Baz = BoundFoo; 4733 (void)BoundBar; 4734 // [[p1]] 4735 } else { 4736 Baz = BoundFoo; 4737 } 4738 (void)0; 4739 // [[p2]] 4740 } 4741 )"; 4742 runDataflow( 4743 Code, 4744 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4745 ASTContext &ASTCtx) { 4746 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 4747 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 4748 4749 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 4750 ASSERT_THAT(BoundFooDecl, NotNull()); 4751 4752 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 4753 ASSERT_THAT(BoundBarDecl, NotNull()); 4754 4755 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4756 ASSERT_THAT(BazDecl, NotNull()); 4757 4758 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl); 4759 ASSERT_THAT(BoundFooValue, NotNull()); 4760 EXPECT_TRUE(isa<BoolValue>(BoundFooValue)); 4761 4762 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl); 4763 ASSERT_THAT(BoundBarValue, NotNull()); 4764 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue)); 4765 4766 // Test that a `DeclRefExpr` to a `BindingDecl` (with reference type) 4767 // works as expected. We don't test aliasing properties of the 4768 // reference, because we don't model `std::get` and so have no way to 4769 // equate separate references into the tuple. 4770 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue); 4771 4772 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 4773 4774 // Test that `BoundFooDecl` retains the value we expect, after the join. 4775 BoundFooValue = Env2.getValue(*BoundFooDecl); 4776 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue); 4777 }); 4778 } 4779 4780 TEST(TransferTest, BinaryOperatorComma) { 4781 std::string Code = R"( 4782 void target(int Foo, int Bar) { 4783 int &Baz = (Foo, Bar); 4784 // [[p]] 4785 } 4786 )"; 4787 runDataflow( 4788 Code, 4789 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4790 ASTContext &ASTCtx) { 4791 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4792 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4793 4794 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4795 ASSERT_THAT(BarDecl, NotNull()); 4796 4797 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4798 ASSERT_THAT(BazDecl, NotNull()); 4799 4800 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 4801 ASSERT_THAT(BarLoc, NotNull()); 4802 4803 const StorageLocation *BazLoc = Env.getStorageLocation(*BazDecl); 4804 EXPECT_EQ(BazLoc, BarLoc); 4805 }); 4806 } 4807 4808 TEST(TransferTest, IfStmtBranchExtendsFlowCondition) { 4809 std::string Code = R"( 4810 void target(bool Foo) { 4811 if (Foo) { 4812 (void)0; 4813 // [[if_then]] 4814 } else { 4815 (void)0; 4816 // [[if_else]] 4817 } 4818 } 4819 )"; 4820 runDataflow( 4821 Code, 4822 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4823 ASTContext &ASTCtx) { 4824 ASSERT_THAT(Results.keys(), UnorderedElementsAre("if_then", "if_else")); 4825 const Environment &ThenEnv = 4826 getEnvironmentAtAnnotation(Results, "if_then"); 4827 const Environment &ElseEnv = 4828 getEnvironmentAtAnnotation(Results, "if_else"); 4829 4830 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4831 ASSERT_THAT(FooDecl, NotNull()); 4832 4833 auto &ThenFooVal= getFormula(*FooDecl, ThenEnv); 4834 EXPECT_TRUE(ThenEnv.proves(ThenFooVal)); 4835 4836 auto &ElseFooVal = getFormula(*FooDecl, ElseEnv); 4837 EXPECT_TRUE(ElseEnv.proves(ElseEnv.arena().makeNot(ElseFooVal))); 4838 }); 4839 } 4840 4841 TEST(TransferTest, WhileStmtBranchExtendsFlowCondition) { 4842 std::string Code = R"( 4843 void target(bool Foo) { 4844 while (Foo) { 4845 (void)0; 4846 // [[loop_body]] 4847 } 4848 (void)0; 4849 // [[after_loop]] 4850 } 4851 )"; 4852 runDataflow( 4853 Code, 4854 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4855 ASTContext &ASTCtx) { 4856 ASSERT_THAT(Results.keys(), 4857 UnorderedElementsAre("loop_body", "after_loop")); 4858 const Environment &LoopBodyEnv = 4859 getEnvironmentAtAnnotation(Results, "loop_body"); 4860 const Environment &AfterLoopEnv = 4861 getEnvironmentAtAnnotation(Results, "after_loop"); 4862 4863 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4864 ASSERT_THAT(FooDecl, NotNull()); 4865 4866 auto &LoopBodyFooVal = getFormula(*FooDecl, LoopBodyEnv); 4867 EXPECT_TRUE(LoopBodyEnv.proves(LoopBodyFooVal)); 4868 4869 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 4870 EXPECT_TRUE( 4871 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal))); 4872 }); 4873 } 4874 4875 TEST(TransferTest, DoWhileStmtBranchExtendsFlowCondition) { 4876 std::string Code = R"( 4877 void target(bool Foo) { 4878 bool Bar = true; 4879 do { 4880 (void)0; 4881 // [[loop_body]] 4882 Bar = false; 4883 } while (Foo); 4884 (void)0; 4885 // [[after_loop]] 4886 } 4887 )"; 4888 runDataflow( 4889 Code, 4890 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4891 ASTContext &ASTCtx) { 4892 ASSERT_THAT(Results.keys(), 4893 UnorderedElementsAre("loop_body", "after_loop")); 4894 const Environment &LoopBodyEnv = 4895 getEnvironmentAtAnnotation(Results, "loop_body"); 4896 const Environment &AfterLoopEnv = 4897 getEnvironmentAtAnnotation(Results, "after_loop"); 4898 auto &A = AfterLoopEnv.arena(); 4899 4900 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4901 ASSERT_THAT(FooDecl, NotNull()); 4902 4903 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4904 ASSERT_THAT(BarDecl, NotNull()); 4905 4906 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 4907 auto &LoopBodyBarVal = getFormula(*BarDecl, LoopBodyEnv); 4908 EXPECT_TRUE( 4909 LoopBodyEnv.proves(A.makeOr(LoopBodyBarVal, LoopBodyFooVal))); 4910 4911 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 4912 auto &AfterLoopBarVal = getFormula(*BarDecl, AfterLoopEnv); 4913 EXPECT_TRUE(AfterLoopEnv.proves(A.makeNot(AfterLoopFooVal))); 4914 EXPECT_TRUE(AfterLoopEnv.proves(A.makeNot(AfterLoopBarVal))); 4915 }); 4916 } 4917 4918 TEST(TransferTest, ForStmtBranchExtendsFlowCondition) { 4919 std::string Code = R"( 4920 void target(bool Foo) { 4921 for (; Foo;) { 4922 (void)0; 4923 // [[loop_body]] 4924 } 4925 (void)0; 4926 // [[after_loop]] 4927 } 4928 )"; 4929 runDataflow( 4930 Code, 4931 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4932 ASTContext &ASTCtx) { 4933 ASSERT_THAT(Results.keys(), 4934 UnorderedElementsAre("loop_body", "after_loop")); 4935 const Environment &LoopBodyEnv = 4936 getEnvironmentAtAnnotation(Results, "loop_body"); 4937 const Environment &AfterLoopEnv = 4938 getEnvironmentAtAnnotation(Results, "after_loop"); 4939 4940 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4941 ASSERT_THAT(FooDecl, NotNull()); 4942 4943 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 4944 EXPECT_TRUE(LoopBodyEnv.proves(LoopBodyFooVal)); 4945 4946 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 4947 EXPECT_TRUE( 4948 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal))); 4949 }); 4950 } 4951 4952 TEST(TransferTest, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition) { 4953 std::string Code = R"( 4954 void target(bool Foo) { 4955 for (;;) { 4956 (void)0; 4957 // [[loop_body]] 4958 } 4959 } 4960 )"; 4961 runDataflow( 4962 Code, 4963 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4964 ASTContext &ASTCtx) { 4965 ASSERT_THAT(Results.keys(), UnorderedElementsAre("loop_body")); 4966 const Environment &LoopBodyEnv = 4967 getEnvironmentAtAnnotation(Results, "loop_body"); 4968 4969 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4970 ASSERT_THAT(FooDecl, NotNull()); 4971 4972 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 4973 EXPECT_FALSE(LoopBodyEnv.proves(LoopBodyFooVal)); 4974 }); 4975 } 4976 4977 TEST(TransferTest, ContextSensitiveOptionDisabled) { 4978 std::string Code = R"( 4979 bool GiveBool(); 4980 void SetBool(bool &Var) { Var = true; } 4981 4982 void target() { 4983 bool Foo = GiveBool(); 4984 SetBool(Foo); 4985 // [[p]] 4986 } 4987 )"; 4988 runDataflow( 4989 Code, 4990 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4991 ASTContext &ASTCtx) { 4992 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4993 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4994 4995 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4996 ASSERT_THAT(FooDecl, NotNull()); 4997 4998 auto &FooVal = getFormula(*FooDecl, Env); 4999 EXPECT_FALSE(Env.proves(FooVal)); 5000 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5001 }, 5002 {BuiltinOptions{/*.ContextSensitiveOpts=*/std::nullopt}}); 5003 } 5004 5005 TEST(TransferTest, ContextSensitiveReturnReference) { 5006 std::string Code = R"( 5007 class S {}; 5008 S& target(bool b, S &s) { 5009 return s; 5010 // [[p]] 5011 } 5012 )"; 5013 runDataflow( 5014 Code, 5015 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5016 ASTContext &ASTCtx) { 5017 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5018 5019 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 5020 ASSERT_THAT(SDecl, NotNull()); 5021 5022 auto *SLoc = Env.getStorageLocation(*SDecl); 5023 ASSERT_THAT(SLoc, NotNull()); 5024 5025 ASSERT_THAT(Env.getReturnStorageLocation(), Eq(SLoc)); 5026 }, 5027 {BuiltinOptions{ContextSensitiveOptions{}}}); 5028 } 5029 5030 // This test is a regression test, based on a real crash. 5031 TEST(TransferTest, ContextSensitiveReturnReferenceWithConditionalOperator) { 5032 std::string Code = R"( 5033 class S {}; 5034 S& target(bool b, S &s) { 5035 return b ? s : s; 5036 // [[p]] 5037 } 5038 )"; 5039 runDataflow( 5040 Code, 5041 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5042 ASTContext &ASTCtx) { 5043 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5044 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5045 5046 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 5047 ASSERT_THAT(SDecl, NotNull()); 5048 5049 auto *SLoc = Env.getStorageLocation(*SDecl); 5050 ASSERT_THAT(SLoc, NotNull()); 5051 EXPECT_THAT(Env.getValue(*SLoc), NotNull()); 5052 5053 auto *Loc = Env.getReturnStorageLocation(); 5054 ASSERT_THAT(Loc, NotNull()); 5055 EXPECT_THAT(Env.getValue(*Loc), NotNull()); 5056 5057 // TODO: We would really like to make this stronger assertion, but that 5058 // doesn't work because we don't propagate values correctly through 5059 // the conditional operator yet. 5060 // ASSERT_THAT(Loc, Eq(SLoc)); 5061 }, 5062 {BuiltinOptions{ContextSensitiveOptions{}}}); 5063 } 5064 5065 TEST(TransferTest, ContextSensitiveReturnOneOfTwoReferences) { 5066 std::string Code = R"( 5067 class S {}; 5068 S &callee(bool b, S &s1_parm, S &s2_parm) { 5069 if (b) 5070 return s1_parm; 5071 else 5072 return s2_parm; 5073 } 5074 void target(bool b) { 5075 S s1; 5076 S s2; 5077 S &return_s1 = s1; 5078 S &return_s2 = s2; 5079 S &return_dont_know = callee(b, s1, s2); 5080 // [[p]] 5081 } 5082 )"; 5083 runDataflow( 5084 Code, 5085 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5086 ASTContext &ASTCtx) { 5087 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5088 5089 const ValueDecl *S1 = findValueDecl(ASTCtx, "s1"); 5090 ASSERT_THAT(S1, NotNull()); 5091 const ValueDecl *S2 = findValueDecl(ASTCtx, "s2"); 5092 ASSERT_THAT(S2, NotNull()); 5093 const ValueDecl *ReturnS1 = findValueDecl(ASTCtx, "return_s1"); 5094 ASSERT_THAT(ReturnS1, NotNull()); 5095 const ValueDecl *ReturnS2 = findValueDecl(ASTCtx, "return_s2"); 5096 ASSERT_THAT(ReturnS2, NotNull()); 5097 const ValueDecl *ReturnDontKnow = 5098 findValueDecl(ASTCtx, "return_dont_know"); 5099 ASSERT_THAT(ReturnDontKnow, NotNull()); 5100 5101 StorageLocation *S1Loc = Env.getStorageLocation(*S1); 5102 StorageLocation *S2Loc = Env.getStorageLocation(*S2); 5103 5104 EXPECT_THAT(Env.getStorageLocation(*ReturnS1), Eq(S1Loc)); 5105 EXPECT_THAT(Env.getStorageLocation(*ReturnS2), Eq(S2Loc)); 5106 5107 // In the case where we don't have a consistent storage location for 5108 // the return value, the framework creates a new storage location, which 5109 // should be different from the storage locations of `s1` and `s2`. 5110 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S1Loc)); 5111 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S2Loc)); 5112 }, 5113 {BuiltinOptions{ContextSensitiveOptions{}}}); 5114 } 5115 5116 TEST(TransferTest, ContextSensitiveDepthZero) { 5117 std::string Code = R"( 5118 bool GiveBool(); 5119 void SetBool(bool &Var) { Var = true; } 5120 5121 void target() { 5122 bool Foo = GiveBool(); 5123 SetBool(Foo); 5124 // [[p]] 5125 } 5126 )"; 5127 runDataflow( 5128 Code, 5129 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5130 ASTContext &ASTCtx) { 5131 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5132 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5133 5134 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5135 ASSERT_THAT(FooDecl, NotNull()); 5136 5137 auto &FooVal = getFormula(*FooDecl, Env); 5138 EXPECT_FALSE(Env.proves(FooVal)); 5139 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5140 }, 5141 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/0}}}); 5142 } 5143 5144 TEST(TransferTest, ContextSensitiveSetTrue) { 5145 std::string Code = R"( 5146 bool GiveBool(); 5147 void SetBool(bool &Var) { Var = true; } 5148 5149 void target() { 5150 bool Foo = GiveBool(); 5151 SetBool(Foo); 5152 // [[p]] 5153 } 5154 )"; 5155 runDataflow( 5156 Code, 5157 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5158 ASTContext &ASTCtx) { 5159 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5160 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5161 5162 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5163 ASSERT_THAT(FooDecl, NotNull()); 5164 5165 auto &FooVal = getFormula(*FooDecl, Env); 5166 EXPECT_TRUE(Env.proves(FooVal)); 5167 }, 5168 {BuiltinOptions{ContextSensitiveOptions{}}}); 5169 } 5170 5171 TEST(TransferTest, ContextSensitiveSetFalse) { 5172 std::string Code = R"( 5173 bool GiveBool(); 5174 void SetBool(bool &Var) { Var = false; } 5175 5176 void target() { 5177 bool Foo = GiveBool(); 5178 SetBool(Foo); 5179 // [[p]] 5180 } 5181 )"; 5182 runDataflow( 5183 Code, 5184 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5185 ASTContext &ASTCtx) { 5186 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5187 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5188 5189 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5190 ASSERT_THAT(FooDecl, NotNull()); 5191 5192 auto &FooVal = getFormula(*FooDecl, Env); 5193 EXPECT_TRUE(Env.proves(Env.arena().makeNot(FooVal))); 5194 }, 5195 {BuiltinOptions{ContextSensitiveOptions{}}}); 5196 } 5197 5198 TEST(TransferTest, ContextSensitiveSetBothTrueAndFalse) { 5199 std::string Code = R"( 5200 bool GiveBool(); 5201 void SetBool(bool &Var, bool Val) { Var = Val; } 5202 5203 void target() { 5204 bool Foo = GiveBool(); 5205 bool Bar = GiveBool(); 5206 SetBool(Foo, true); 5207 SetBool(Bar, false); 5208 // [[p]] 5209 } 5210 )"; 5211 runDataflow( 5212 Code, 5213 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5214 ASTContext &ASTCtx) { 5215 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5216 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5217 auto &A = Env.arena(); 5218 5219 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5220 ASSERT_THAT(FooDecl, NotNull()); 5221 5222 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5223 ASSERT_THAT(BarDecl, NotNull()); 5224 5225 auto &FooVal = getFormula(*FooDecl, Env); 5226 EXPECT_TRUE(Env.proves(FooVal)); 5227 EXPECT_FALSE(Env.proves(A.makeNot(FooVal))); 5228 5229 auto &BarVal = getFormula(*BarDecl, Env); 5230 EXPECT_FALSE(Env.proves(BarVal)); 5231 EXPECT_TRUE(Env.proves(A.makeNot(BarVal))); 5232 }, 5233 {BuiltinOptions{ContextSensitiveOptions{}}}); 5234 } 5235 5236 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthOne) { 5237 std::string Code = R"( 5238 bool GiveBool(); 5239 void SetBool1(bool &Var) { Var = true; } 5240 void SetBool2(bool &Var) { SetBool1(Var); } 5241 5242 void target() { 5243 bool Foo = GiveBool(); 5244 SetBool2(Foo); 5245 // [[p]] 5246 } 5247 )"; 5248 runDataflow( 5249 Code, 5250 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5251 ASTContext &ASTCtx) { 5252 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5253 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5254 5255 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5256 ASSERT_THAT(FooDecl, NotNull()); 5257 5258 auto &FooVal = getFormula(*FooDecl, Env); 5259 EXPECT_FALSE(Env.proves(FooVal)); 5260 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5261 }, 5262 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/1}}}); 5263 } 5264 5265 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthTwo) { 5266 std::string Code = R"( 5267 bool GiveBool(); 5268 void SetBool1(bool &Var) { Var = true; } 5269 void SetBool2(bool &Var) { SetBool1(Var); } 5270 5271 void target() { 5272 bool Foo = GiveBool(); 5273 SetBool2(Foo); 5274 // [[p]] 5275 } 5276 )"; 5277 runDataflow( 5278 Code, 5279 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5280 ASTContext &ASTCtx) { 5281 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5282 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5283 5284 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5285 ASSERT_THAT(FooDecl, NotNull()); 5286 5287 auto &FooVal = getFormula(*FooDecl, Env); 5288 EXPECT_TRUE(Env.proves(FooVal)); 5289 }, 5290 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}}); 5291 } 5292 5293 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthTwo) { 5294 std::string Code = R"( 5295 bool GiveBool(); 5296 void SetBool1(bool &Var) { Var = true; } 5297 void SetBool2(bool &Var) { SetBool1(Var); } 5298 void SetBool3(bool &Var) { SetBool2(Var); } 5299 5300 void target() { 5301 bool Foo = GiveBool(); 5302 SetBool3(Foo); 5303 // [[p]] 5304 } 5305 )"; 5306 runDataflow( 5307 Code, 5308 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5309 ASTContext &ASTCtx) { 5310 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5311 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5312 5313 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5314 ASSERT_THAT(FooDecl, NotNull()); 5315 5316 auto &FooVal = getFormula(*FooDecl, Env); 5317 EXPECT_FALSE(Env.proves(FooVal)); 5318 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5319 }, 5320 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}}); 5321 } 5322 5323 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthThree) { 5324 std::string Code = R"( 5325 bool GiveBool(); 5326 void SetBool1(bool &Var) { Var = true; } 5327 void SetBool2(bool &Var) { SetBool1(Var); } 5328 void SetBool3(bool &Var) { SetBool2(Var); } 5329 5330 void target() { 5331 bool Foo = GiveBool(); 5332 SetBool3(Foo); 5333 // [[p]] 5334 } 5335 )"; 5336 runDataflow( 5337 Code, 5338 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5339 ASTContext &ASTCtx) { 5340 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5341 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5342 5343 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5344 ASSERT_THAT(FooDecl, NotNull()); 5345 5346 auto &FooVal = getFormula(*FooDecl, Env); 5347 EXPECT_TRUE(Env.proves(FooVal)); 5348 }, 5349 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/3}}}); 5350 } 5351 5352 TEST(TransferTest, ContextSensitiveMutualRecursion) { 5353 std::string Code = R"( 5354 bool Pong(bool X, bool Y); 5355 5356 bool Ping(bool X, bool Y) { 5357 if (X) { 5358 return Y; 5359 } else { 5360 return Pong(!X, Y); 5361 } 5362 } 5363 5364 bool Pong(bool X, bool Y) { 5365 if (Y) { 5366 return X; 5367 } else { 5368 return Ping(X, !Y); 5369 } 5370 } 5371 5372 void target() { 5373 bool Foo = Ping(false, false); 5374 // [[p]] 5375 } 5376 )"; 5377 runDataflow( 5378 Code, 5379 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5380 ASTContext &ASTCtx) { 5381 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5382 // The analysis doesn't crash... 5383 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5384 5385 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5386 ASSERT_THAT(FooDecl, NotNull()); 5387 5388 auto &FooVal = getFormula(*FooDecl, Env); 5389 // ... but it also can't prove anything here. 5390 EXPECT_FALSE(Env.proves(FooVal)); 5391 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5392 }, 5393 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/4}}}); 5394 } 5395 5396 TEST(TransferTest, ContextSensitiveSetMultipleLines) { 5397 std::string Code = R"( 5398 void SetBools(bool &Var1, bool &Var2) { 5399 Var1 = true; 5400 Var2 = false; 5401 } 5402 5403 void target() { 5404 bool Foo = false; 5405 bool Bar = true; 5406 SetBools(Foo, Bar); 5407 // [[p]] 5408 } 5409 )"; 5410 runDataflow( 5411 Code, 5412 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5413 ASTContext &ASTCtx) { 5414 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5415 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5416 5417 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5418 ASSERT_THAT(FooDecl, NotNull()); 5419 5420 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5421 ASSERT_THAT(BarDecl, NotNull()); 5422 5423 auto &FooVal = getFormula(*FooDecl, Env); 5424 EXPECT_TRUE(Env.proves(FooVal)); 5425 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5426 5427 auto &BarVal = getFormula(*BarDecl, Env); 5428 EXPECT_FALSE(Env.proves(BarVal)); 5429 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 5430 }, 5431 {BuiltinOptions{ContextSensitiveOptions{}}}); 5432 } 5433 5434 TEST(TransferTest, ContextSensitiveSetMultipleBlocks) { 5435 std::string Code = R"( 5436 void IfCond(bool Cond, bool &Then, bool &Else) { 5437 if (Cond) { 5438 Then = true; 5439 } else { 5440 Else = true; 5441 } 5442 } 5443 5444 void target() { 5445 bool Foo = false; 5446 bool Bar = false; 5447 bool Baz = false; 5448 IfCond(Foo, Bar, Baz); 5449 // [[p]] 5450 } 5451 )"; 5452 runDataflow( 5453 Code, 5454 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5455 ASTContext &ASTCtx) { 5456 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5457 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5458 5459 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5460 ASSERT_THAT(BarDecl, NotNull()); 5461 5462 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5463 ASSERT_THAT(BazDecl, NotNull()); 5464 5465 auto &BarVal = getFormula(*BarDecl, Env); 5466 EXPECT_FALSE(Env.proves(BarVal)); 5467 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 5468 5469 auto &BazVal = getFormula(*BazDecl, Env); 5470 EXPECT_TRUE(Env.proves(BazVal)); 5471 EXPECT_FALSE(Env.proves(Env.arena().makeNot(BazVal))); 5472 }, 5473 {BuiltinOptions{ContextSensitiveOptions{}}}); 5474 } 5475 5476 TEST(TransferTest, ContextSensitiveReturnVoid) { 5477 std::string Code = R"( 5478 void Noop() { return; } 5479 5480 void target() { 5481 Noop(); 5482 // [[p]] 5483 } 5484 )"; 5485 runDataflow( 5486 Code, 5487 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5488 ASTContext &ASTCtx) { 5489 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5490 // This just tests that the analysis doesn't crash. 5491 }, 5492 {BuiltinOptions{ContextSensitiveOptions{}}}); 5493 } 5494 5495 TEST(TransferTest, ContextSensitiveReturnTrue) { 5496 std::string Code = R"( 5497 bool GiveBool() { return true; } 5498 5499 void target() { 5500 bool Foo = GiveBool(); 5501 // [[p]] 5502 } 5503 )"; 5504 runDataflow( 5505 Code, 5506 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5507 ASTContext &ASTCtx) { 5508 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5509 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5510 5511 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5512 ASSERT_THAT(FooDecl, NotNull()); 5513 5514 auto &FooVal = getFormula(*FooDecl, Env); 5515 EXPECT_TRUE(Env.proves(FooVal)); 5516 }, 5517 {BuiltinOptions{ContextSensitiveOptions{}}}); 5518 } 5519 5520 TEST(TransferTest, ContextSensitiveReturnFalse) { 5521 std::string Code = R"( 5522 bool GiveBool() { return false; } 5523 5524 void target() { 5525 bool Foo = GiveBool(); 5526 // [[p]] 5527 } 5528 )"; 5529 runDataflow( 5530 Code, 5531 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5532 ASTContext &ASTCtx) { 5533 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5534 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5535 5536 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5537 ASSERT_THAT(FooDecl, NotNull()); 5538 5539 auto &FooVal = getFormula(*FooDecl, Env); 5540 EXPECT_TRUE(Env.proves(Env.arena().makeNot(FooVal))); 5541 }, 5542 {BuiltinOptions{ContextSensitiveOptions{}}}); 5543 } 5544 5545 TEST(TransferTest, ContextSensitiveReturnArg) { 5546 std::string Code = R"( 5547 bool GiveBool(); 5548 bool GiveBack(bool Arg) { return Arg; } 5549 5550 void target() { 5551 bool Foo = GiveBool(); 5552 bool Bar = GiveBack(Foo); 5553 bool Baz = Foo == Bar; 5554 // [[p]] 5555 } 5556 )"; 5557 runDataflow( 5558 Code, 5559 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5560 ASTContext &ASTCtx) { 5561 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5562 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5563 5564 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5565 ASSERT_THAT(BazDecl, NotNull()); 5566 5567 auto &BazVal = getFormula(*BazDecl, Env); 5568 EXPECT_TRUE(Env.proves(BazVal)); 5569 }, 5570 {BuiltinOptions{ContextSensitiveOptions{}}}); 5571 } 5572 5573 TEST(TransferTest, ContextSensitiveReturnInt) { 5574 std::string Code = R"( 5575 int identity(int x) { return x; } 5576 5577 void target() { 5578 int y = identity(42); 5579 // [[p]] 5580 } 5581 )"; 5582 runDataflow( 5583 Code, 5584 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5585 ASTContext &ASTCtx) { 5586 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5587 // This just tests that the analysis doesn't crash. 5588 }, 5589 {BuiltinOptions{ContextSensitiveOptions{}}}); 5590 } 5591 5592 TEST(TransferTest, ContextSensitiveMethodLiteral) { 5593 std::string Code = R"( 5594 class MyClass { 5595 public: 5596 bool giveBool() { return true; } 5597 }; 5598 5599 void target() { 5600 MyClass MyObj; 5601 bool Foo = MyObj.giveBool(); 5602 // [[p]] 5603 } 5604 )"; 5605 runDataflow( 5606 Code, 5607 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5608 ASTContext &ASTCtx) { 5609 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5610 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5611 5612 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5613 ASSERT_THAT(FooDecl, NotNull()); 5614 5615 auto &FooVal = getFormula(*FooDecl, Env); 5616 EXPECT_TRUE(Env.proves(FooVal)); 5617 }, 5618 {BuiltinOptions{ContextSensitiveOptions{}}}); 5619 } 5620 5621 TEST(TransferTest, ContextSensitiveMethodGetter) { 5622 std::string Code = R"( 5623 class MyClass { 5624 public: 5625 bool getField() { return Field; } 5626 5627 bool Field; 5628 }; 5629 5630 void target() { 5631 MyClass MyObj; 5632 MyObj.Field = true; 5633 bool Foo = MyObj.getField(); 5634 // [[p]] 5635 } 5636 )"; 5637 runDataflow( 5638 Code, 5639 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5640 ASTContext &ASTCtx) { 5641 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5642 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5643 5644 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5645 ASSERT_THAT(FooDecl, NotNull()); 5646 5647 auto &FooVal = getFormula(*FooDecl, Env); 5648 EXPECT_TRUE(Env.proves(FooVal)); 5649 }, 5650 {BuiltinOptions{ContextSensitiveOptions{}}}); 5651 } 5652 5653 TEST(TransferTest, ContextSensitiveMethodSetter) { 5654 std::string Code = R"( 5655 class MyClass { 5656 public: 5657 void setField(bool Val) { Field = Val; } 5658 5659 bool Field; 5660 }; 5661 5662 void target() { 5663 MyClass MyObj; 5664 MyObj.setField(true); 5665 bool Foo = MyObj.Field; 5666 // [[p]] 5667 } 5668 )"; 5669 runDataflow( 5670 Code, 5671 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5672 ASTContext &ASTCtx) { 5673 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5674 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5675 5676 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5677 ASSERT_THAT(FooDecl, NotNull()); 5678 5679 auto &FooVal = getFormula(*FooDecl, Env); 5680 EXPECT_TRUE(Env.proves(FooVal)); 5681 }, 5682 {BuiltinOptions{ContextSensitiveOptions{}}}); 5683 } 5684 5685 TEST(TransferTest, ContextSensitiveMethodGetterAndSetter) { 5686 std::string Code = R"( 5687 class MyClass { 5688 public: 5689 bool getField() { return Field; } 5690 void setField(bool Val) { Field = Val; } 5691 5692 private: 5693 bool Field; 5694 }; 5695 5696 void target() { 5697 MyClass MyObj; 5698 MyObj.setField(true); 5699 bool Foo = MyObj.getField(); 5700 // [[p]] 5701 } 5702 )"; 5703 runDataflow( 5704 Code, 5705 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5706 ASTContext &ASTCtx) { 5707 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5708 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5709 5710 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5711 ASSERT_THAT(FooDecl, NotNull()); 5712 5713 auto &FooVal = getFormula(*FooDecl, Env); 5714 EXPECT_TRUE(Env.proves(FooVal)); 5715 }, 5716 {BuiltinOptions{ContextSensitiveOptions{}}}); 5717 } 5718 5719 5720 TEST(TransferTest, ContextSensitiveMethodTwoLayersVoid) { 5721 std::string Code = R"( 5722 class MyClass { 5723 public: 5724 void Inner() { MyField = true; } 5725 void Outer() { Inner(); } 5726 5727 bool MyField; 5728 }; 5729 5730 void target() { 5731 MyClass MyObj; 5732 MyObj.Outer(); 5733 bool Foo = MyObj.MyField; 5734 // [[p]] 5735 } 5736 )"; 5737 runDataflow( 5738 Code, 5739 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5740 ASTContext &ASTCtx) { 5741 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5742 ; 5743 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5744 5745 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5746 ASSERT_THAT(FooDecl, NotNull()); 5747 5748 auto &FooVal = getFormula(*FooDecl, Env); 5749 EXPECT_TRUE(Env.proves(FooVal)); 5750 }, 5751 {BuiltinOptions{ContextSensitiveOptions{}}}); 5752 } 5753 5754 TEST(TransferTest, ContextSensitiveMethodTwoLayersReturn) { 5755 std::string Code = R"( 5756 class MyClass { 5757 public: 5758 bool Inner() { return MyField; } 5759 bool Outer() { return Inner(); } 5760 5761 bool MyField; 5762 }; 5763 5764 void target() { 5765 MyClass MyObj; 5766 MyObj.MyField = true; 5767 bool Foo = MyObj.Outer(); 5768 // [[p]] 5769 } 5770 )"; 5771 runDataflow( 5772 Code, 5773 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5774 ASTContext &ASTCtx) { 5775 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5776 ; 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, ContextSensitiveConstructorBody) { 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, ContextSensitiveConstructorInitializer) { 5820 std::string Code = R"( 5821 class MyClass { 5822 public: 5823 MyClass() : MyField(true) {} 5824 5825 bool MyField; 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, ContextSensitiveConstructorDefault) { 5851 std::string Code = R"( 5852 class MyClass { 5853 public: 5854 MyClass() = default; 5855 5856 bool MyField = true; 5857 }; 5858 5859 void target() { 5860 MyClass MyObj; 5861 bool Foo = MyObj.MyField; 5862 // [[p]] 5863 } 5864 )"; 5865 runDataflow( 5866 Code, 5867 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5868 ASTContext &ASTCtx) { 5869 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5870 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5871 5872 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5873 ASSERT_THAT(FooDecl, NotNull()); 5874 5875 auto &FooVal = getFormula(*FooDecl, Env); 5876 EXPECT_TRUE(Env.proves(FooVal)); 5877 }, 5878 {BuiltinOptions{ContextSensitiveOptions{}}}); 5879 } 5880 5881 TEST(TransferTest, ContextSensitiveSelfReferentialClass) { 5882 // Test that the `this` pointer seen in the constructor has the same value 5883 // as the address of the variable the object is constructed into. 5884 std::string Code = R"( 5885 class MyClass { 5886 public: 5887 MyClass() : Self(this) {} 5888 MyClass *Self; 5889 }; 5890 5891 void target() { 5892 MyClass MyObj; 5893 MyClass *SelfPtr = MyObj.Self; 5894 // [[p]] 5895 } 5896 )"; 5897 runDataflow( 5898 Code, 5899 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5900 ASTContext &ASTCtx) { 5901 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5902 5903 const ValueDecl *MyObjDecl = findValueDecl(ASTCtx, "MyObj"); 5904 ASSERT_THAT(MyObjDecl, NotNull()); 5905 5906 const ValueDecl *SelfDecl = findValueDecl(ASTCtx, "SelfPtr"); 5907 ASSERT_THAT(SelfDecl, NotNull()); 5908 5909 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5910 auto &SelfVal = *cast<PointerValue>(Env.getValue(*SelfDecl)); 5911 EXPECT_EQ(Env.getStorageLocation(*MyObjDecl), &SelfVal.getPointeeLoc()); 5912 }, 5913 {BuiltinOptions{ContextSensitiveOptions{}}}); 5914 } 5915 5916 TEST(TransferTest, UnnamedBitfieldInitializer) { 5917 std::string Code = R"( 5918 struct B {}; 5919 struct A { 5920 unsigned a; 5921 unsigned : 4; 5922 unsigned c; 5923 B b; 5924 }; 5925 void target() { 5926 A a = {}; 5927 A test = a; 5928 (void)test.c; 5929 } 5930 )"; 5931 runDataflow( 5932 Code, 5933 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5934 ASTContext &ASTCtx) { 5935 // This doesn't need a body because this test was crashing the framework 5936 // before handling correctly Unnamed bitfields in `InitListExpr`. 5937 }); 5938 } 5939 5940 // Repro for a crash that used to occur with chained short-circuiting logical 5941 // operators. 5942 TEST(TransferTest, ChainedLogicalOps) { 5943 std::string Code = R"( 5944 bool target() { 5945 bool b = true || false || false || false; 5946 // [[p]] 5947 return b; 5948 } 5949 )"; 5950 runDataflow( 5951 Code, 5952 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5953 ASTContext &ASTCtx) { 5954 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5955 auto &B = getValueForDecl<BoolValue>(ASTCtx, Env, "b").formula(); 5956 EXPECT_TRUE(Env.proves(B)); 5957 }); 5958 } 5959 5960 // Repro for a crash that used to occur when we call a `noreturn` function 5961 // within one of the operands of a `&&` or `||` operator. 5962 TEST(TransferTest, NoReturnFunctionInsideShortCircuitedBooleanOp) { 5963 std::string Code = R"( 5964 __attribute__((noreturn)) int doesnt_return(); 5965 bool some_condition(); 5966 void target(bool b1, bool b2) { 5967 // Neither of these should crash. In addition, if we don't terminate the 5968 // program, we know that the operators need to trigger the short-circuit 5969 // logic, so `NoreturnOnRhsOfAnd` will be false and `NoreturnOnRhsOfOr` 5970 // will be true. 5971 bool NoreturnOnRhsOfAnd = b1 && doesnt_return() > 0; 5972 bool NoreturnOnRhsOfOr = b2 || doesnt_return() > 0; 5973 5974 // Calling a `noreturn` function on the LHS of an `&&` or `||` makes the 5975 // entire expression unreachable. So we know that in both of the following 5976 // cases, if `target()` terminates, the `else` branch was taken. 5977 bool NoreturnOnLhsMakesAndUnreachable = false; 5978 if (some_condition()) 5979 doesnt_return() > 0 && some_condition(); 5980 else 5981 NoreturnOnLhsMakesAndUnreachable = true; 5982 5983 bool NoreturnOnLhsMakesOrUnreachable = false; 5984 if (some_condition()) 5985 doesnt_return() > 0 || some_condition(); 5986 else 5987 NoreturnOnLhsMakesOrUnreachable = true; 5988 5989 // [[p]] 5990 } 5991 )"; 5992 runDataflow( 5993 Code, 5994 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5995 ASTContext &ASTCtx) { 5996 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5997 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5998 auto &A = Env.arena(); 5999 6000 // Check that [[p]] is reachable with a non-false flow condition. 6001 EXPECT_FALSE(Env.proves(A.makeLiteral(false))); 6002 6003 auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, "b1").formula(); 6004 EXPECT_TRUE(Env.proves(A.makeNot(B1))); 6005 6006 auto &NoreturnOnRhsOfAnd = 6007 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfAnd").formula(); 6008 EXPECT_TRUE(Env.proves(A.makeNot(NoreturnOnRhsOfAnd))); 6009 6010 auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, "b2").formula(); 6011 EXPECT_TRUE(Env.proves(B2)); 6012 6013 auto &NoreturnOnRhsOfOr = 6014 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfOr") 6015 .formula(); 6016 EXPECT_TRUE(Env.proves(NoreturnOnRhsOfOr)); 6017 6018 auto &NoreturnOnLhsMakesAndUnreachable = getValueForDecl<BoolValue>( 6019 ASTCtx, Env, "NoreturnOnLhsMakesAndUnreachable").formula(); 6020 EXPECT_TRUE(Env.proves(NoreturnOnLhsMakesAndUnreachable)); 6021 6022 auto &NoreturnOnLhsMakesOrUnreachable = getValueForDecl<BoolValue>( 6023 ASTCtx, Env, "NoreturnOnLhsMakesOrUnreachable").formula(); 6024 EXPECT_TRUE(Env.proves(NoreturnOnLhsMakesOrUnreachable)); 6025 }); 6026 } 6027 6028 TEST(TransferTest, NewExpressions) { 6029 std::string Code = R"( 6030 void target() { 6031 int *p = new int(42); 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 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p"); 6043 6044 EXPECT_THAT(Env.getValue(P.getPointeeLoc()), NotNull()); 6045 }); 6046 } 6047 6048 TEST(TransferTest, NewExpressions_Structs) { 6049 std::string Code = R"( 6050 struct Inner { 6051 int InnerField; 6052 }; 6053 6054 struct Outer { 6055 Inner OuterField; 6056 }; 6057 6058 void target() { 6059 Outer *p = new Outer; 6060 // Access the fields to make sure the analysis actually generates children 6061 // for them in the `RecordStorageLocation` and `RecordValue`. 6062 p->OuterField.InnerField; 6063 // [[after_new]] 6064 } 6065 )"; 6066 runDataflow( 6067 Code, 6068 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6069 ASTContext &ASTCtx) { 6070 const Environment &Env = 6071 getEnvironmentAtAnnotation(Results, "after_new"); 6072 6073 const ValueDecl *OuterField = findValueDecl(ASTCtx, "OuterField"); 6074 const ValueDecl *InnerField = findValueDecl(ASTCtx, "InnerField"); 6075 6076 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p"); 6077 6078 auto &OuterLoc = cast<RecordStorageLocation>(P.getPointeeLoc()); 6079 auto &OuterFieldLoc = 6080 *cast<RecordStorageLocation>(OuterLoc.getChild(*OuterField)); 6081 auto &InnerFieldLoc = *OuterFieldLoc.getChild(*InnerField); 6082 6083 // Values for the struct and all fields exist after the new. 6084 EXPECT_THAT(Env.getValue(OuterLoc), NotNull()); 6085 EXPECT_THAT(Env.getValue(OuterFieldLoc), NotNull()); 6086 EXPECT_THAT(Env.getValue(InnerFieldLoc), NotNull()); 6087 }); 6088 } 6089 6090 TEST(TransferTest, FunctionToPointerDecayHasValue) { 6091 std::string Code = R"( 6092 struct A { static void static_member_func(); }; 6093 void target() { 6094 // To check that we're treating function-to-pointer decay correctly, 6095 // create two pointers, then verify they refer to the same storage 6096 // location. 6097 // We need to do the test this way because even if an initializer (in this 6098 // case, the function-to-pointer decay) does not create a value, we still 6099 // create a value for the variable. 6100 void (*non_member_p1)() = target; 6101 void (*non_member_p2)() = target; 6102 6103 // Do the same thing but for a static member function. 6104 void (*member_p1)() = A::static_member_func; 6105 void (*member_p2)() = A::static_member_func; 6106 // [[p]] 6107 } 6108 )"; 6109 runDataflow( 6110 Code, 6111 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6112 ASTContext &ASTCtx) { 6113 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6114 6115 auto &NonMemberP1 = 6116 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p1"); 6117 auto &NonMemberP2 = 6118 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p2"); 6119 EXPECT_EQ(&NonMemberP1.getPointeeLoc(), &NonMemberP2.getPointeeLoc()); 6120 6121 auto &MemberP1 = 6122 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p1"); 6123 auto &MemberP2 = 6124 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p2"); 6125 EXPECT_EQ(&MemberP1.getPointeeLoc(), &MemberP2.getPointeeLoc()); 6126 }); 6127 } 6128 6129 // Check that a builtin function is not associated with a value. (It's only 6130 // possible to call builtin functions directly, not take their address.) 6131 TEST(TransferTest, BuiltinFunctionModeled) { 6132 std::string Code = R"( 6133 void target() { 6134 __builtin_expect(0, 0); 6135 // [[p]] 6136 } 6137 )"; 6138 runDataflow( 6139 Code, 6140 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6141 ASTContext &ASTCtx) { 6142 using ast_matchers::selectFirst; 6143 using ast_matchers::match; 6144 using ast_matchers::traverse; 6145 using ast_matchers::implicitCastExpr; 6146 using ast_matchers::hasCastKind; 6147 6148 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6149 6150 auto *ImplicitCast = selectFirst<ImplicitCastExpr>( 6151 "implicit_cast", 6152 match(traverse(TK_AsIs, 6153 implicitCastExpr(hasCastKind(CK_BuiltinFnToFnPtr)) 6154 .bind("implicit_cast")), 6155 ASTCtx)); 6156 6157 ASSERT_THAT(ImplicitCast, NotNull()); 6158 EXPECT_THAT(Env.getValue(*ImplicitCast), IsNull()); 6159 }); 6160 } 6161 6162 // Check that a callee of a member operator call is modeled as a `PointerValue`. 6163 // Member operator calls are unusual in that their callee is a pointer that 6164 // stems from a `FunctionToPointerDecay`. In calls to non-operator non-static 6165 // member functions, the callee is a `MemberExpr` (which does not have pointer 6166 // type). 6167 // We want to make sure that we produce a pointer value for the callee in this 6168 // specific scenario and that its storage location is durable (for convergence). 6169 TEST(TransferTest, MemberOperatorCallModelsPointerForCallee) { 6170 std::string Code = R"( 6171 struct S { 6172 bool operator!=(S s); 6173 }; 6174 void target() { 6175 S s; 6176 (void)(s != s); 6177 (void)(s != s); 6178 // [[p]] 6179 } 6180 )"; 6181 runDataflow( 6182 Code, 6183 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6184 ASTContext &ASTCtx) { 6185 using ast_matchers::selectFirst; 6186 using ast_matchers::match; 6187 using ast_matchers::traverse; 6188 using ast_matchers::cxxOperatorCallExpr; 6189 6190 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6191 6192 auto Matches = match( 6193 traverse(TK_AsIs, cxxOperatorCallExpr().bind("call")), ASTCtx); 6194 6195 ASSERT_EQ(Matches.size(), 2UL); 6196 6197 auto *Call1 = Matches[0].getNodeAs<CXXOperatorCallExpr>("call"); 6198 auto *Call2 = Matches[1].getNodeAs<CXXOperatorCallExpr>("call"); 6199 6200 ASSERT_THAT(Call1, NotNull()); 6201 ASSERT_THAT(Call2, NotNull()); 6202 6203 EXPECT_EQ(cast<ImplicitCastExpr>(Call1->getCallee())->getCastKind(), 6204 CK_FunctionToPointerDecay); 6205 EXPECT_EQ(cast<ImplicitCastExpr>(Call2->getCallee())->getCastKind(), 6206 CK_FunctionToPointerDecay); 6207 6208 auto *Ptr1 = cast<PointerValue>(Env.getValue(*Call1->getCallee())); 6209 auto *Ptr2 = cast<PointerValue>(Env.getValue(*Call2->getCallee())); 6210 6211 ASSERT_EQ(&Ptr1->getPointeeLoc(), &Ptr2->getPointeeLoc()); 6212 }); 6213 } 6214 6215 // Check that fields of anonymous records are modeled. 6216 TEST(TransferTest, AnonymousStruct) { 6217 std::string Code = R"( 6218 struct S { 6219 struct { 6220 bool b; 6221 }; 6222 }; 6223 void target() { 6224 S s; 6225 s.b = true; 6226 // [[p]] 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 *SDecl = findValueDecl(ASTCtx, "s"); 6235 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b"); 6236 const IndirectFieldDecl *IndirectField = 6237 findIndirectFieldDecl(ASTCtx, "b"); 6238 6239 auto *S = cast<RecordStorageLocation>(Env.getStorageLocation(*SDecl)); 6240 auto &AnonStruct = *cast<RecordStorageLocation>( 6241 S->getChild(*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, AnonymousStructWithInitializer) { 6249 std::string Code = R"( 6250 struct target { 6251 target() { 6252 (void)0; 6253 // [[p]] 6254 } 6255 struct { 6256 bool b = true; 6257 }; 6258 }; 6259 )"; 6260 runDataflow( 6261 Code, 6262 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6263 ASTContext &ASTCtx) { 6264 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6265 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b"); 6266 const IndirectFieldDecl *IndirectField = 6267 findIndirectFieldDecl(ASTCtx, "b"); 6268 6269 auto *ThisLoc = 6270 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation()); 6271 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild( 6272 *cast<ValueDecl>(IndirectField->chain().front()))); 6273 6274 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env)); 6275 ASSERT_TRUE(Env.proves(B->formula())); 6276 }); 6277 } 6278 6279 TEST(TransferTest, AnonymousStructWithReferenceField) { 6280 std::string Code = R"( 6281 int global_i = 0; 6282 struct target { 6283 target() { 6284 (void)0; 6285 // [[p]] 6286 } 6287 struct { 6288 int &i = global_i; 6289 }; 6290 }; 6291 )"; 6292 runDataflow( 6293 Code, 6294 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6295 ASTContext &ASTCtx) { 6296 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6297 const ValueDecl *GlobalIDecl = findValueDecl(ASTCtx, "global_i"); 6298 const ValueDecl *IDecl = findValueDecl(ASTCtx, "i"); 6299 const IndirectFieldDecl *IndirectField = 6300 findIndirectFieldDecl(ASTCtx, "i"); 6301 6302 auto *ThisLoc = 6303 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation()); 6304 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild( 6305 *cast<ValueDecl>(IndirectField->chain().front()))); 6306 6307 ASSERT_EQ(AnonStruct.getChild(*IDecl), 6308 Env.getStorageLocation(*GlobalIDecl)); 6309 }); 6310 } 6311 6312 TEST(TransferTest, EvaluateBlockWithUnreachablePreds) { 6313 // This is a crash repro. 6314 // `false` block may not have been processed when we try to evaluate the `||` 6315 // after visiting `true`, because it is not necessary (and therefore the edge 6316 // is marked unreachable). Trying to get the analysis state via 6317 // `getEnvironment` for the subexpression still should not crash. 6318 std::string Code = R"( 6319 int target(int i) { 6320 if ((i < 0 && true) || false) { 6321 return 0; 6322 } 6323 return 0; 6324 } 6325 )"; 6326 runDataflow( 6327 Code, 6328 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6329 ASTContext &ASTCtx) {}); 6330 } 6331 6332 TEST(TransferTest, LambdaCaptureByCopy) { 6333 std::string Code = R"( 6334 void target(int Foo, int Bar) { 6335 [Foo]() { 6336 (void)0; 6337 // [[p]] 6338 }(); 6339 } 6340 )"; 6341 runDataflowOnLambda( 6342 Code, 6343 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6344 ASTContext &ASTCtx) { 6345 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6346 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6347 6348 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6349 ASSERT_THAT(FooDecl, NotNull()); 6350 6351 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6352 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6353 6354 const Value *FooVal = Env.getValue(*FooLoc); 6355 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6356 6357 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6358 ASSERT_THAT(BarDecl, NotNull()); 6359 6360 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6361 EXPECT_THAT(BarLoc, IsNull()); 6362 }); 6363 } 6364 6365 TEST(TransferTest, LambdaCaptureByReference) { 6366 std::string Code = R"( 6367 void target(int Foo, int Bar) { 6368 [&Foo]() { 6369 (void)0; 6370 // [[p]] 6371 }(); 6372 } 6373 )"; 6374 runDataflowOnLambda( 6375 Code, 6376 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6377 ASTContext &ASTCtx) { 6378 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6379 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6380 6381 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6382 ASSERT_THAT(FooDecl, NotNull()); 6383 6384 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6385 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6386 6387 const Value *FooVal = Env.getValue(*FooLoc); 6388 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6389 6390 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6391 ASSERT_THAT(BarDecl, NotNull()); 6392 6393 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6394 EXPECT_THAT(BarLoc, IsNull()); 6395 }); 6396 } 6397 6398 TEST(TransferTest, LambdaCaptureWithInitializer) { 6399 std::string Code = R"( 6400 void target(int Bar) { 6401 [Foo=Bar]() { 6402 (void)0; 6403 // [[p]] 6404 }(); 6405 } 6406 )"; 6407 runDataflowOnLambda( 6408 Code, 6409 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6410 ASTContext &ASTCtx) { 6411 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6412 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6413 6414 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6415 ASSERT_THAT(FooDecl, NotNull()); 6416 6417 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6418 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6419 6420 const Value *FooVal = Env.getValue(*FooLoc); 6421 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6422 6423 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6424 ASSERT_THAT(BarDecl, NotNull()); 6425 6426 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6427 EXPECT_THAT(BarLoc, IsNull()); 6428 }); 6429 } 6430 6431 TEST(TransferTest, LambdaCaptureByCopyImplicit) { 6432 std::string Code = R"( 6433 void target(int Foo, int Bar) { 6434 [=]() { 6435 Foo; 6436 // [[p]] 6437 }(); 6438 } 6439 )"; 6440 runDataflowOnLambda( 6441 Code, 6442 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6443 ASTContext &ASTCtx) { 6444 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6445 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6446 6447 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6448 ASSERT_THAT(FooDecl, NotNull()); 6449 6450 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6451 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6452 6453 const Value *FooVal = Env.getValue(*FooLoc); 6454 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6455 6456 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6457 ASSERT_THAT(BarDecl, NotNull()); 6458 6459 // There is no storage location for `Bar` because it isn't used in the 6460 // body of the lambda. 6461 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6462 EXPECT_THAT(BarLoc, IsNull()); 6463 }); 6464 } 6465 6466 TEST(TransferTest, LambdaCaptureByReferenceImplicit) { 6467 std::string Code = R"( 6468 void target(int Foo, int Bar) { 6469 [&]() { 6470 Foo; 6471 // [[p]] 6472 }(); 6473 } 6474 )"; 6475 runDataflowOnLambda( 6476 Code, 6477 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6478 ASTContext &ASTCtx) { 6479 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6480 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6481 6482 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6483 ASSERT_THAT(FooDecl, NotNull()); 6484 6485 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6486 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6487 6488 const Value *FooVal = Env.getValue(*FooLoc); 6489 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6490 6491 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6492 ASSERT_THAT(BarDecl, NotNull()); 6493 6494 // There is no storage location for `Bar` because it isn't used in the 6495 // body of the lambda. 6496 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6497 EXPECT_THAT(BarLoc, IsNull()); 6498 }); 6499 } 6500 6501 TEST(TransferTest, LambdaCaptureThis) { 6502 std::string Code = R"( 6503 struct Bar { 6504 int Foo; 6505 6506 void target() { 6507 [this]() { 6508 Foo; 6509 // [[p]] 6510 }(); 6511 } 6512 }; 6513 )"; 6514 runDataflowOnLambda( 6515 Code, 6516 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6517 ASTContext &ASTCtx) { 6518 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6519 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6520 6521 const RecordStorageLocation *ThisPointeeLoc = 6522 Env.getThisPointeeStorageLocation(); 6523 ASSERT_THAT(ThisPointeeLoc, NotNull()); 6524 6525 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6526 ASSERT_THAT(FooDecl, NotNull()); 6527 6528 const StorageLocation *FooLoc = ThisPointeeLoc->getChild(*FooDecl); 6529 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6530 6531 const Value *FooVal = Env.getValue(*FooLoc); 6532 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6533 }); 6534 } 6535 6536 TEST(TransferTest, DifferentReferenceLocInJoin) { 6537 // This test triggers a case where the storage location for a reference-type 6538 // variable is different for two states being joined. We used to believe this 6539 // could not happen and therefore had an assertion disallowing this; this test 6540 // exists to demonstrate that we can handle this condition without a failing 6541 // assertion. See also the discussion here: 6542 // https://discourse.llvm.org/t/70086/6 6543 std::string Code = R"( 6544 namespace std { 6545 template <class T> struct initializer_list { 6546 const T* begin(); 6547 const T* end(); 6548 }; 6549 } 6550 6551 void target(char* p, char* end) { 6552 while (p != end) { 6553 if (*p == ' ') { 6554 p++; 6555 continue; 6556 } 6557 6558 auto && range = {1, 2}; 6559 for (auto b = range.begin(), e = range.end(); b != e; ++b) { 6560 } 6561 (void)0; 6562 // [[p]] 6563 } 6564 } 6565 )"; 6566 runDataflow( 6567 Code, 6568 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6569 ASTContext &ASTCtx) { 6570 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6571 6572 // Joining environments with different storage locations for the same 6573 // declaration results in the declaration being removed from the joined 6574 // environment. 6575 const ValueDecl *VD = findValueDecl(ASTCtx, "range"); 6576 ASSERT_EQ(Env.getStorageLocation(*VD), nullptr); 6577 }); 6578 } 6579 6580 // This test verifies correct modeling of a relational dependency that goes 6581 // through unmodeled functions (the simple `cond()` in this case). 6582 TEST(TransferTest, ConditionalRelation) { 6583 std::string Code = R"( 6584 bool cond(); 6585 void target() { 6586 bool a = true; 6587 bool b = true; 6588 if (cond()) { 6589 a = false; 6590 if (cond()) { 6591 b = false; 6592 } 6593 } 6594 (void)0; 6595 // [[p]] 6596 } 6597 )"; 6598 runDataflow( 6599 Code, 6600 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6601 ASTContext &ASTCtx) { 6602 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6603 auto &A = Env.arena(); 6604 auto &VarA = getValueForDecl<BoolValue>(ASTCtx, Env, "a").formula(); 6605 auto &VarB = getValueForDecl<BoolValue>(ASTCtx, Env, "b").formula(); 6606 6607 EXPECT_FALSE(Env.allows(A.makeAnd(VarA, A.makeNot(VarB)))); 6608 }); 6609 } 6610 6611 } // namespace 6612