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