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