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