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