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