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, CopyConstructor) { 2317 std::string Code = R"( 2318 struct A { 2319 int Baz; 2320 }; 2321 2322 void target() { 2323 A Foo = { 1 }; 2324 A Bar = Foo; 2325 // [[after_copy]] 2326 Foo.Baz = 2; 2327 // [[after_update]] 2328 } 2329 )"; 2330 runDataflow( 2331 Code, 2332 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2333 ASTContext &ASTCtx) { 2334 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2335 ASSERT_THAT(FooDecl, NotNull()); 2336 2337 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2338 ASSERT_THAT(BarDecl, NotNull()); 2339 2340 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2341 ASSERT_THAT(BazDecl, NotNull()); 2342 2343 // after_copy 2344 { 2345 const Environment &Env = 2346 getEnvironmentAtAnnotation(Results, "after_copy"); 2347 2348 const auto *FooLoc = 2349 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2350 const auto *BarLoc = 2351 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2352 2353 // `Foo` and `Bar` have different `RecordValue`s associated with them. 2354 const auto *FooVal = cast<RecordValue>(Env.getValue(*FooLoc)); 2355 const auto *BarVal = cast<RecordValue>(Env.getValue(*BarLoc)); 2356 EXPECT_NE(FooVal, BarVal); 2357 2358 // But the records compare equal. 2359 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env)); 2360 2361 // In particular, the value of `Baz` in both records is the same. 2362 const auto *FooBazVal = 2363 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2364 const auto *BarBazVal = 2365 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2366 EXPECT_EQ(FooBazVal, BarBazVal); 2367 } 2368 2369 // after_update 2370 { 2371 const Environment &Env = 2372 getEnvironmentAtAnnotation(Results, "after_update"); 2373 2374 const auto *FooLoc = 2375 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2376 const auto *BarLoc = 2377 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2378 2379 EXPECT_FALSE(recordsEqual(*FooLoc, *BarLoc, Env)); 2380 2381 const auto *FooBazVal = 2382 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2383 const auto *BarBazVal = 2384 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2385 EXPECT_NE(FooBazVal, BarBazVal); 2386 } 2387 }); 2388 } 2389 2390 TEST(TransferTest, CopyConstructorWithDefaultArgument) { 2391 std::string Code = R"( 2392 struct A { 2393 int Baz; 2394 A() = default; 2395 A(const A& a, bool def = true) { Baz = a.Baz; } 2396 }; 2397 2398 void target() { 2399 A Foo; 2400 (void)Foo.Baz; 2401 A Bar = Foo; 2402 // [[p]] 2403 } 2404 )"; 2405 runDataflow( 2406 Code, 2407 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2408 ASTContext &ASTCtx) { 2409 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2410 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2411 2412 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2413 ASSERT_THAT(FooDecl, NotNull()); 2414 2415 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2416 ASSERT_THAT(BarDecl, NotNull()); 2417 2418 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2419 ASSERT_THAT(BazDecl, NotNull()); 2420 2421 const auto *FooLoc = 2422 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2423 const auto *BarLoc = 2424 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2425 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env)); 2426 2427 const auto *FooBazVal = 2428 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2429 const auto *BarBazVal = 2430 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2431 EXPECT_EQ(FooBazVal, BarBazVal); 2432 }); 2433 } 2434 2435 TEST(TransferTest, CopyConstructorWithParens) { 2436 std::string Code = R"( 2437 struct A { 2438 int Baz; 2439 }; 2440 2441 void target() { 2442 A Foo; 2443 (void)Foo.Baz; 2444 A Bar((A(Foo))); 2445 // [[p]] 2446 } 2447 )"; 2448 runDataflow( 2449 Code, 2450 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2451 ASTContext &ASTCtx) { 2452 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2453 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2454 2455 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2456 ASSERT_THAT(FooDecl, NotNull()); 2457 2458 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2459 ASSERT_THAT(BarDecl, NotNull()); 2460 2461 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2462 ASSERT_THAT(BazDecl, NotNull()); 2463 2464 const auto *FooLoc = 2465 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2466 const auto *BarLoc = 2467 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl)); 2468 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env)); 2469 2470 const auto *FooBazVal = 2471 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env)); 2472 const auto *BarBazVal = 2473 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env)); 2474 EXPECT_EQ(FooBazVal, BarBazVal); 2475 }); 2476 } 2477 2478 TEST(TransferTest, CopyConstructorWithInitializerListAsSyntacticSugar) { 2479 std::string Code = R"( 2480 struct A { 2481 int Baz; 2482 }; 2483 void target() { 2484 A Foo = {3}; 2485 (void)Foo.Baz; 2486 A Bar = {A(Foo)}; 2487 // [[p]] 2488 } 2489 )"; 2490 runDataflow( 2491 Code, 2492 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2493 ASTContext &ASTCtx) { 2494 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2495 2496 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2497 2498 const auto &FooLoc = 2499 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo"); 2500 const auto &BarLoc = 2501 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar"); 2502 2503 const auto *FooBazVal = 2504 cast<IntegerValue>(getFieldValue(&FooLoc, *BazDecl, Env)); 2505 const auto *BarBazVal = 2506 cast<IntegerValue>(getFieldValue(&BarLoc, *BazDecl, Env)); 2507 EXPECT_EQ(FooBazVal, BarBazVal); 2508 }); 2509 } 2510 2511 TEST(TransferTest, CopyConstructorArgIsRefReturnedByFunction) { 2512 // This is a crash repro. 2513 std::string Code = R"( 2514 struct S {}; 2515 const S &returnsSRef(); 2516 void target() { 2517 S s(returnsSRef()); 2518 } 2519 )"; 2520 runDataflow( 2521 Code, 2522 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2523 ASTContext &ASTCtx) {}); 2524 } 2525 2526 TEST(TransferTest, MoveConstructor) { 2527 std::string Code = R"( 2528 namespace std { 2529 2530 template <typename T> struct remove_reference { using type = T; }; 2531 template <typename T> struct remove_reference<T&> { using type = T; }; 2532 template <typename T> struct remove_reference<T&&> { using type = T; }; 2533 2534 template <typename T> 2535 using remove_reference_t = typename remove_reference<T>::type; 2536 2537 template <typename T> 2538 std::remove_reference_t<T>&& move(T&& x); 2539 2540 } // namespace std 2541 2542 struct A { 2543 int Baz; 2544 }; 2545 2546 void target() { 2547 A Foo; 2548 A Bar; 2549 (void)Foo.Baz; 2550 // [[p1]] 2551 Foo = std::move(Bar); 2552 // [[p2]] 2553 } 2554 )"; 2555 runDataflow( 2556 Code, 2557 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2558 ASTContext &ASTCtx) { 2559 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 2560 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 2561 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 2562 2563 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2564 ASSERT_THAT(FooDecl, NotNull()); 2565 2566 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2567 ASSERT_THAT(BarDecl, NotNull()); 2568 2569 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2570 ASSERT_THAT(BazDecl, NotNull()); 2571 2572 const auto *FooLoc1 = 2573 cast<RecordStorageLocation>(Env1.getStorageLocation(*FooDecl)); 2574 const auto *BarLoc1 = 2575 cast<RecordStorageLocation>(Env1.getStorageLocation(*BarDecl)); 2576 2577 EXPECT_FALSE(recordsEqual(*FooLoc1, *BarLoc1, Env1)); 2578 2579 const auto *FooVal1 = cast<RecordValue>(Env1.getValue(*FooLoc1)); 2580 const auto *BarVal1 = cast<RecordValue>(Env1.getValue(*BarLoc1)); 2581 EXPECT_NE(FooVal1, BarVal1); 2582 2583 const auto *FooBazVal1 = 2584 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env1)); 2585 const auto *BarBazVal1 = 2586 cast<IntegerValue>(getFieldValue(BarLoc1, *BazDecl, Env1)); 2587 EXPECT_NE(FooBazVal1, BarBazVal1); 2588 2589 const auto *FooLoc2 = 2590 cast<RecordStorageLocation>(Env2.getStorageLocation(*FooDecl)); 2591 const auto *FooVal2 = cast<RecordValue>(Env2.getValue(*FooLoc2)); 2592 EXPECT_NE(FooVal2, BarVal1); 2593 EXPECT_TRUE(recordsEqual(*FooLoc2, Env2, *BarLoc1, Env1)); 2594 2595 const auto *FooBazVal2 = 2596 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env2)); 2597 EXPECT_EQ(FooBazVal2, BarBazVal1); 2598 }); 2599 } 2600 2601 TEST(TransferTest, BindTemporary) { 2602 std::string Code = R"( 2603 struct A { 2604 virtual ~A() = default; 2605 2606 int Baz; 2607 }; 2608 2609 void target(A Foo) { 2610 int Bar = A(Foo).Baz; 2611 // [[p]] 2612 } 2613 )"; 2614 runDataflow( 2615 Code, 2616 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2617 ASTContext &ASTCtx) { 2618 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2619 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2620 2621 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2622 ASSERT_THAT(FooDecl, NotNull()); 2623 2624 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2625 ASSERT_THAT(BarDecl, NotNull()); 2626 2627 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2628 ASSERT_THAT(BazDecl, NotNull()); 2629 2630 const auto &FooLoc = 2631 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)); 2632 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 2633 EXPECT_EQ(BarVal, getFieldValue(&FooLoc, *BazDecl, Env)); 2634 }); 2635 } 2636 2637 TEST(TransferTest, ResultObjectLocation) { 2638 std::string Code = R"( 2639 struct A { 2640 virtual ~A() = default; 2641 }; 2642 2643 void target() { 2644 0, A(); 2645 (void)0; // [[p]] 2646 } 2647 )"; 2648 using ast_matchers::binaryOperator; 2649 using ast_matchers::cxxBindTemporaryExpr; 2650 using ast_matchers::cxxTemporaryObjectExpr; 2651 using ast_matchers::exprWithCleanups; 2652 using ast_matchers::has; 2653 using ast_matchers::hasOperatorName; 2654 using ast_matchers::hasRHS; 2655 using ast_matchers::match; 2656 using ast_matchers::selectFirst; 2657 using ast_matchers::traverse; 2658 runDataflow( 2659 Code, 2660 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2661 ASTContext &ASTCtx) { 2662 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2663 2664 // The expression `0, A()` in the code above produces the following 2665 // structure, consisting of four prvalues of record type. 2666 // `Env.getResultObjectLocation()` should return the same location for 2667 // all of these. 2668 auto MatchResult = match( 2669 traverse(TK_AsIs, 2670 exprWithCleanups( 2671 has(binaryOperator( 2672 hasOperatorName(","), 2673 hasRHS(cxxBindTemporaryExpr( 2674 has(cxxTemporaryObjectExpr().bind( 2675 "toe"))) 2676 .bind("bte"))) 2677 .bind("comma"))) 2678 .bind("ewc")), 2679 ASTCtx); 2680 auto *TOE = selectFirst<CXXTemporaryObjectExpr>("toe", MatchResult); 2681 ASSERT_NE(TOE, nullptr); 2682 auto *Comma = selectFirst<BinaryOperator>("comma", MatchResult); 2683 ASSERT_NE(Comma, nullptr); 2684 auto *EWC = selectFirst<ExprWithCleanups>("ewc", MatchResult); 2685 ASSERT_NE(EWC, nullptr); 2686 auto *BTE = selectFirst<CXXBindTemporaryExpr>("bte", MatchResult); 2687 ASSERT_NE(BTE, nullptr); 2688 2689 RecordStorageLocation &Loc = Env.getResultObjectLocation(*TOE); 2690 EXPECT_EQ(&Loc, &Env.getResultObjectLocation(*Comma)); 2691 EXPECT_EQ(&Loc, &Env.getResultObjectLocation(*EWC)); 2692 EXPECT_EQ(&Loc, &Env.getResultObjectLocation(*BTE)); 2693 }); 2694 } 2695 2696 TEST(TransferTest, ResultObjectLocationForDefaultInitExpr) { 2697 std::string Code = R"( 2698 struct S {}; 2699 struct target { 2700 target () { 2701 (void)0; 2702 // [[p]] 2703 } 2704 S s = {}; 2705 }; 2706 )"; 2707 2708 using ast_matchers::cxxCtorInitializer; 2709 using ast_matchers::match; 2710 using ast_matchers::selectFirst; 2711 runDataflow( 2712 Code, 2713 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2714 ASTContext &ASTCtx) { 2715 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2716 2717 const ValueDecl *SField = findValueDecl(ASTCtx, "s"); 2718 2719 auto *CtorInit = selectFirst<CXXCtorInitializer>( 2720 "ctor_initializer", 2721 match(cxxCtorInitializer().bind("ctor_initializer"), ASTCtx)); 2722 ASSERT_NE(CtorInit, nullptr); 2723 2724 auto *DefaultInit = cast<CXXDefaultInitExpr>(CtorInit->getInit()); 2725 2726 RecordStorageLocation &Loc = Env.getResultObjectLocation(*DefaultInit); 2727 2728 // FIXME: The result object location for the `CXXDefaultInitExpr` should 2729 // be the location of the member variable being initialized, but we 2730 // don't do this correctly yet; see also comments in 2731 // `builtinTransferInitializer()`. 2732 // For the time being, we just document the current erroneous behavior 2733 // here (this should be `EXPECT_EQ` when the behavior is fixed). 2734 EXPECT_NE(&Loc, Env.getThisPointeeStorageLocation()->getChild(*SField)); 2735 }); 2736 } 2737 2738 TEST(TransferTest, StaticCast) { 2739 std::string Code = R"( 2740 void target(int Foo) { 2741 int Bar = static_cast<int>(Foo); 2742 // [[p]] 2743 } 2744 )"; 2745 runDataflow( 2746 Code, 2747 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2748 ASTContext &ASTCtx) { 2749 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2750 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2751 2752 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2753 ASSERT_THAT(FooDecl, NotNull()); 2754 2755 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2756 ASSERT_THAT(BarDecl, NotNull()); 2757 2758 const auto *FooVal = Env.getValue(*FooDecl); 2759 const auto *BarVal = Env.getValue(*BarDecl); 2760 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 2761 EXPECT_TRUE(isa<IntegerValue>(BarVal)); 2762 EXPECT_EQ(FooVal, BarVal); 2763 }); 2764 } 2765 2766 TEST(TransferTest, IntegralCast) { 2767 std::string Code = R"( 2768 void target(int Foo) { 2769 long Bar = Foo; 2770 // [[p]] 2771 } 2772 )"; 2773 runDataflow( 2774 Code, 2775 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2776 ASTContext &ASTCtx) { 2777 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2778 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2779 2780 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2781 ASSERT_THAT(FooDecl, NotNull()); 2782 2783 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2784 ASSERT_THAT(BarDecl, NotNull()); 2785 2786 const auto *FooVal = Env.getValue(*FooDecl); 2787 const auto *BarVal = Env.getValue(*BarDecl); 2788 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 2789 EXPECT_TRUE(isa<IntegerValue>(BarVal)); 2790 EXPECT_EQ(FooVal, BarVal); 2791 }); 2792 } 2793 2794 TEST(TransferTest, IntegraltoBooleanCast) { 2795 std::string Code = R"( 2796 void target(int Foo) { 2797 bool Bar = Foo; 2798 // [[p]] 2799 } 2800 )"; 2801 runDataflow( 2802 Code, 2803 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2804 ASTContext &ASTCtx) { 2805 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2806 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2807 2808 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2809 ASSERT_THAT(FooDecl, NotNull()); 2810 2811 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2812 ASSERT_THAT(BarDecl, NotNull()); 2813 2814 const auto *FooVal = Env.getValue(*FooDecl); 2815 const auto *BarVal = Env.getValue(*BarDecl); 2816 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 2817 EXPECT_TRUE(isa<BoolValue>(BarVal)); 2818 }); 2819 } 2820 2821 TEST(TransferTest, IntegralToBooleanCastFromBool) { 2822 std::string Code = R"( 2823 void target(bool Foo) { 2824 int Zab = Foo; 2825 bool Bar = Zab; 2826 // [[p]] 2827 } 2828 )"; 2829 runDataflow( 2830 Code, 2831 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2832 ASTContext &ASTCtx) { 2833 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2834 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2835 2836 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2837 ASSERT_THAT(FooDecl, NotNull()); 2838 2839 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2840 ASSERT_THAT(BarDecl, NotNull()); 2841 2842 const auto *FooVal = Env.getValue(*FooDecl); 2843 const auto *BarVal = Env.getValue(*BarDecl); 2844 EXPECT_TRUE(isa<BoolValue>(FooVal)); 2845 EXPECT_TRUE(isa<BoolValue>(BarVal)); 2846 EXPECT_EQ(FooVal, BarVal); 2847 }); 2848 } 2849 2850 TEST(TransferTest, NullToPointerCast) { 2851 std::string Code = R"( 2852 using my_nullptr_t = decltype(nullptr); 2853 struct Baz {}; 2854 void target() { 2855 int *FooX = nullptr; 2856 int *FooY = nullptr; 2857 bool **Bar = nullptr; 2858 Baz *Baz = nullptr; 2859 my_nullptr_t Null = 0; 2860 // [[p]] 2861 } 2862 )"; 2863 runDataflow( 2864 Code, 2865 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2866 ASTContext &ASTCtx) { 2867 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2868 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2869 2870 const ValueDecl *FooXDecl = findValueDecl(ASTCtx, "FooX"); 2871 ASSERT_THAT(FooXDecl, NotNull()); 2872 2873 const ValueDecl *FooYDecl = findValueDecl(ASTCtx, "FooY"); 2874 ASSERT_THAT(FooYDecl, NotNull()); 2875 2876 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2877 ASSERT_THAT(BarDecl, NotNull()); 2878 2879 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2880 ASSERT_THAT(BazDecl, NotNull()); 2881 2882 const ValueDecl *NullDecl = findValueDecl(ASTCtx, "Null"); 2883 ASSERT_THAT(NullDecl, NotNull()); 2884 2885 const auto *FooXVal = cast<PointerValue>(Env.getValue(*FooXDecl)); 2886 const auto *FooYVal = cast<PointerValue>(Env.getValue(*FooYDecl)); 2887 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 2888 const auto *BazVal = cast<PointerValue>(Env.getValue(*BazDecl)); 2889 const auto *NullVal = cast<PointerValue>(Env.getValue(*NullDecl)); 2890 2891 EXPECT_EQ(FooXVal, FooYVal); 2892 EXPECT_NE(FooXVal, BarVal); 2893 EXPECT_NE(FooXVal, BazVal); 2894 EXPECT_NE(BarVal, BazVal); 2895 2896 const StorageLocation &FooPointeeLoc = FooXVal->getPointeeLoc(); 2897 EXPECT_TRUE(isa<ScalarStorageLocation>(FooPointeeLoc)); 2898 EXPECT_THAT(Env.getValue(FooPointeeLoc), IsNull()); 2899 2900 const StorageLocation &BarPointeeLoc = BarVal->getPointeeLoc(); 2901 EXPECT_TRUE(isa<ScalarStorageLocation>(BarPointeeLoc)); 2902 EXPECT_THAT(Env.getValue(BarPointeeLoc), IsNull()); 2903 2904 const StorageLocation &BazPointeeLoc = BazVal->getPointeeLoc(); 2905 EXPECT_TRUE(isa<RecordStorageLocation>(BazPointeeLoc)); 2906 EXPECT_THAT(Env.getValue(BazPointeeLoc), IsNull()); 2907 2908 const StorageLocation &NullPointeeLoc = NullVal->getPointeeLoc(); 2909 EXPECT_TRUE(isa<ScalarStorageLocation>(NullPointeeLoc)); 2910 EXPECT_THAT(Env.getValue(NullPointeeLoc), IsNull()); 2911 }); 2912 } 2913 2914 TEST(TransferTest, PointerToMemberVariable) { 2915 std::string Code = R"( 2916 struct S { 2917 int i; 2918 }; 2919 void target() { 2920 int S::*MemberPointer = &S::i; 2921 // [[p]] 2922 } 2923 )"; 2924 runDataflow( 2925 Code, 2926 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2927 ASTContext &ASTCtx) { 2928 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2929 2930 const ValueDecl *MemberPointerDecl = 2931 findValueDecl(ASTCtx, "MemberPointer"); 2932 ASSERT_THAT(MemberPointerDecl, NotNull()); 2933 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 2934 }); 2935 } 2936 2937 TEST(TransferTest, PointerToMemberFunction) { 2938 std::string Code = R"( 2939 struct S { 2940 void Method(); 2941 }; 2942 void target() { 2943 void (S::*MemberPointer)() = &S::Method; 2944 // [[p]] 2945 } 2946 )"; 2947 runDataflow( 2948 Code, 2949 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2950 ASTContext &ASTCtx) { 2951 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2952 2953 const ValueDecl *MemberPointerDecl = 2954 findValueDecl(ASTCtx, "MemberPointer"); 2955 ASSERT_THAT(MemberPointerDecl, NotNull()); 2956 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 2957 }); 2958 } 2959 2960 TEST(TransferTest, NullToMemberPointerCast) { 2961 std::string Code = R"( 2962 struct Foo {}; 2963 void target() { 2964 int Foo::*MemberPointer = nullptr; 2965 // [[p]] 2966 } 2967 )"; 2968 runDataflow( 2969 Code, 2970 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2971 ASTContext &ASTCtx) { 2972 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2973 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2974 2975 const ValueDecl *MemberPointerDecl = 2976 findValueDecl(ASTCtx, "MemberPointer"); 2977 ASSERT_THAT(MemberPointerDecl, NotNull()); 2978 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull()); 2979 }); 2980 } 2981 2982 TEST(TransferTest, AddrOfValue) { 2983 std::string Code = R"( 2984 void target() { 2985 int Foo; 2986 int *Bar = &Foo; 2987 // [[p]] 2988 } 2989 )"; 2990 runDataflow( 2991 Code, 2992 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2993 ASTContext &ASTCtx) { 2994 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2995 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2996 2997 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2998 ASSERT_THAT(FooDecl, NotNull()); 2999 3000 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3001 ASSERT_THAT(BarDecl, NotNull()); 3002 3003 const auto *FooLoc = 3004 cast<ScalarStorageLocation>(Env.getStorageLocation(*FooDecl)); 3005 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 3006 EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc); 3007 }); 3008 } 3009 3010 TEST(TransferTest, AddrOfReference) { 3011 std::string Code = R"( 3012 void target(int *Foo) { 3013 int *Bar = &(*Foo); 3014 // [[p]] 3015 } 3016 )"; 3017 runDataflow( 3018 Code, 3019 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3020 ASTContext &ASTCtx) { 3021 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3022 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3023 3024 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3025 ASSERT_THAT(FooDecl, NotNull()); 3026 3027 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3028 ASSERT_THAT(BarDecl, NotNull()); 3029 3030 const auto *FooVal = cast<PointerValue>(Env.getValue(*FooDecl)); 3031 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl)); 3032 EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc()); 3033 }); 3034 } 3035 3036 TEST(TransferTest, CannotAnalyzeFunctionTemplate) { 3037 std::string Code = R"( 3038 template <typename T> 3039 void target() {} 3040 )"; 3041 ASSERT_THAT_ERROR( 3042 checkDataflowWithNoopAnalysis(Code), 3043 llvm::FailedWithMessage("Cannot analyze templated declarations")); 3044 } 3045 3046 TEST(TransferTest, CannotAnalyzeMethodOfClassTemplate) { 3047 std::string Code = R"( 3048 template <typename T> 3049 struct A { 3050 void target() {} 3051 }; 3052 )"; 3053 ASSERT_THAT_ERROR( 3054 checkDataflowWithNoopAnalysis(Code), 3055 llvm::FailedWithMessage("Cannot analyze templated declarations")); 3056 } 3057 3058 TEST(TransferTest, VarDeclInitAssignConditionalOperator) { 3059 std::string Code = R"( 3060 struct A {}; 3061 3062 void target(A Foo, A Bar, bool Cond) { 3063 A Baz = Cond ? Foo : Bar; 3064 /*[[p]]*/ 3065 } 3066 )"; 3067 runDataflow( 3068 Code, 3069 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3070 ASTContext &ASTCtx) { 3071 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3072 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3073 3074 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3075 ASSERT_THAT(FooDecl, NotNull()); 3076 3077 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3078 ASSERT_THAT(BarDecl, NotNull()); 3079 3080 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3081 ASSERT_THAT(BazDecl, NotNull()); 3082 3083 const auto *FooVal = cast<RecordValue>(Env.getValue(*FooDecl)); 3084 const auto *BarVal = cast<RecordValue>(Env.getValue(*BarDecl)); 3085 3086 const auto *BazVal = dyn_cast<RecordValue>(Env.getValue(*BazDecl)); 3087 ASSERT_THAT(BazVal, NotNull()); 3088 3089 EXPECT_NE(BazVal, FooVal); 3090 EXPECT_NE(BazVal, BarVal); 3091 }); 3092 } 3093 3094 TEST(TransferTest, VarDeclInDoWhile) { 3095 std::string Code = R"( 3096 void target(int *Foo) { 3097 do { 3098 int Bar = *Foo; 3099 // [[in_loop]] 3100 } while (false); 3101 (void)0; 3102 // [[after_loop]] 3103 } 3104 )"; 3105 runDataflow( 3106 Code, 3107 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3108 ASTContext &ASTCtx) { 3109 const Environment &EnvInLoop = 3110 getEnvironmentAtAnnotation(Results, "in_loop"); 3111 const Environment &EnvAfterLoop = 3112 getEnvironmentAtAnnotation(Results, "after_loop"); 3113 3114 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3115 ASSERT_THAT(FooDecl, NotNull()); 3116 3117 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3118 ASSERT_THAT(BarDecl, NotNull()); 3119 3120 const auto *FooVal = 3121 cast<PointerValue>(EnvAfterLoop.getValue(*FooDecl)); 3122 const auto *FooPointeeVal = 3123 cast<IntegerValue>(EnvAfterLoop.getValue(FooVal->getPointeeLoc())); 3124 3125 const auto *BarVal = cast<IntegerValue>(EnvInLoop.getValue(*BarDecl)); 3126 EXPECT_EQ(BarVal, FooPointeeVal); 3127 3128 ASSERT_THAT(EnvAfterLoop.getValue(*BarDecl), IsNull()); 3129 }); 3130 } 3131 3132 TEST(TransferTest, UnreachableAfterWhileTrue) { 3133 std::string Code = R"( 3134 void target() { 3135 while (true) {} 3136 (void)0; 3137 /*[[p]]*/ 3138 } 3139 )"; 3140 runDataflow( 3141 Code, 3142 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3143 ASTContext &ASTCtx) { 3144 // The node after the while-true is pruned because it is trivially 3145 // known to be unreachable. 3146 ASSERT_TRUE(Results.empty()); 3147 }); 3148 } 3149 3150 TEST(TransferTest, AggregateInitialization) { 3151 std::string BracesCode = R"( 3152 struct A { 3153 int Foo; 3154 }; 3155 3156 struct B { 3157 int Bar; 3158 A Baz; 3159 int Qux; 3160 }; 3161 3162 void target(int BarArg, int FooArg, int QuxArg) { 3163 B Quux{BarArg, {FooArg}, QuxArg}; 3164 B OtherB; 3165 /*[[p]]*/ 3166 } 3167 )"; 3168 std::string BraceElisionCode = R"( 3169 struct A { 3170 int Foo; 3171 }; 3172 3173 struct B { 3174 int Bar; 3175 A Baz; 3176 int Qux; 3177 }; 3178 3179 void target(int BarArg, int FooArg, int QuxArg) { 3180 B Quux = {BarArg, FooArg, QuxArg}; 3181 B OtherB; 3182 /*[[p]]*/ 3183 } 3184 )"; 3185 for (const std::string &Code : {BracesCode, BraceElisionCode}) { 3186 runDataflow( 3187 Code, 3188 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3189 ASTContext &ASTCtx) { 3190 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3191 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3192 3193 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3194 ASSERT_THAT(FooDecl, NotNull()); 3195 3196 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3197 ASSERT_THAT(BarDecl, NotNull()); 3198 3199 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3200 ASSERT_THAT(BazDecl, NotNull()); 3201 3202 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 3203 ASSERT_THAT(QuxDecl, NotNull()); 3204 3205 const ValueDecl *FooArgDecl = findValueDecl(ASTCtx, "FooArg"); 3206 ASSERT_THAT(FooArgDecl, NotNull()); 3207 3208 const ValueDecl *BarArgDecl = findValueDecl(ASTCtx, "BarArg"); 3209 ASSERT_THAT(BarArgDecl, NotNull()); 3210 3211 const ValueDecl *QuxArgDecl = findValueDecl(ASTCtx, "QuxArg"); 3212 ASSERT_THAT(QuxArgDecl, NotNull()); 3213 3214 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 3215 ASSERT_THAT(QuuxDecl, NotNull()); 3216 3217 const auto *FooArgVal = cast<IntegerValue>(Env.getValue(*FooArgDecl)); 3218 const auto *BarArgVal = cast<IntegerValue>(Env.getValue(*BarArgDecl)); 3219 const auto *QuxArgVal = cast<IntegerValue>(Env.getValue(*QuxArgDecl)); 3220 3221 const auto &QuuxLoc = 3222 *cast<RecordStorageLocation>(Env.getStorageLocation(*QuuxDecl)); 3223 const auto &BazLoc = 3224 *cast<RecordStorageLocation>(QuuxLoc.getChild(*BazDecl)); 3225 3226 EXPECT_EQ(getFieldValue(&QuuxLoc, *BarDecl, Env), BarArgVal); 3227 EXPECT_EQ(getFieldValue(&BazLoc, *FooDecl, Env), FooArgVal); 3228 EXPECT_EQ(getFieldValue(&QuuxLoc, *QuxDecl, Env), QuxArgVal); 3229 3230 // Check that fields initialized in an initializer list are always 3231 // modeled in other instances of the same type. 3232 const auto &OtherBLoc = 3233 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "OtherB"); 3234 EXPECT_THAT(OtherBLoc.getChild(*BarDecl), NotNull()); 3235 EXPECT_THAT(OtherBLoc.getChild(*BazDecl), NotNull()); 3236 EXPECT_THAT(OtherBLoc.getChild(*QuxDecl), NotNull()); 3237 }); 3238 } 3239 } 3240 3241 TEST(TransferTest, AggregateInitializationReferenceField) { 3242 std::string Code = R"( 3243 struct S { 3244 int &RefField; 3245 }; 3246 3247 void target(int i) { 3248 S s = { i }; 3249 /*[[p]]*/ 3250 } 3251 )"; 3252 runDataflow( 3253 Code, 3254 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3255 ASTContext &ASTCtx) { 3256 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3257 3258 const ValueDecl *RefFieldDecl = findValueDecl(ASTCtx, "RefField"); 3259 3260 auto &ILoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "i"); 3261 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"); 3262 3263 EXPECT_EQ(SLoc.getChild(*RefFieldDecl), &ILoc); 3264 }); 3265 } 3266 3267 TEST(TransferTest, AggregateInitialization_NotExplicitlyInitializedField) { 3268 std::string Code = R"( 3269 struct S { 3270 int i1; 3271 int i2; 3272 }; 3273 3274 void target(int i) { 3275 S s = { i }; 3276 /*[[p]]*/ 3277 } 3278 )"; 3279 runDataflow( 3280 Code, 3281 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3282 ASTContext &ASTCtx) { 3283 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3284 3285 const ValueDecl *I1FieldDecl = findValueDecl(ASTCtx, "i1"); 3286 const ValueDecl *I2FieldDecl = findValueDecl(ASTCtx, "i2"); 3287 3288 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"); 3289 3290 auto &IValue = getValueForDecl<IntegerValue>(ASTCtx, Env, "i"); 3291 auto &I1Value = 3292 *cast<IntegerValue>(getFieldValue(&SLoc, *I1FieldDecl, Env)); 3293 EXPECT_EQ(&I1Value, &IValue); 3294 auto &I2Value = 3295 *cast<IntegerValue>(getFieldValue(&SLoc, *I2FieldDecl, Env)); 3296 EXPECT_NE(&I2Value, &IValue); 3297 }); 3298 } 3299 3300 TEST(TransferTest, AggregateInitializationFunctionPointer) { 3301 // This is a repro for an assertion failure. 3302 // nullptr takes on the type of a const function pointer, but its type was 3303 // asserted to be equal to the *unqualified* type of Field, which no longer 3304 // included the const. 3305 std::string Code = R"( 3306 struct S { 3307 void (*const Field)(); 3308 }; 3309 3310 void target() { 3311 S s{nullptr}; 3312 } 3313 )"; 3314 runDataflow( 3315 Code, 3316 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3317 ASTContext &ASTCtx) {}); 3318 } 3319 3320 TEST(TransferTest, AssignToUnionMember) { 3321 std::string Code = R"( 3322 union A { 3323 int Foo; 3324 }; 3325 3326 void target(int Bar) { 3327 A Baz; 3328 Baz.Foo = Bar; 3329 // [[p]] 3330 } 3331 )"; 3332 runDataflow( 3333 Code, 3334 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3335 ASTContext &ASTCtx) { 3336 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3337 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3338 3339 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3340 ASSERT_THAT(BazDecl, NotNull()); 3341 ASSERT_TRUE(BazDecl->getType()->isUnionType()); 3342 3343 auto BazFields = BazDecl->getType()->getAsRecordDecl()->fields(); 3344 FieldDecl *FooDecl = nullptr; 3345 for (FieldDecl *Field : BazFields) { 3346 if (Field->getNameAsString() == "Foo") { 3347 FooDecl = Field; 3348 } else { 3349 FAIL() << "Unexpected field: " << Field->getNameAsString(); 3350 } 3351 } 3352 ASSERT_THAT(FooDecl, NotNull()); 3353 3354 const auto *BazLoc = dyn_cast_or_null<RecordStorageLocation>( 3355 Env.getStorageLocation(*BazDecl)); 3356 ASSERT_THAT(BazLoc, NotNull()); 3357 ASSERT_THAT(Env.getValue(*BazLoc), NotNull()); 3358 3359 const auto *FooVal = 3360 cast<IntegerValue>(getFieldValue(BazLoc, *FooDecl, Env)); 3361 3362 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3363 ASSERT_THAT(BarDecl, NotNull()); 3364 const auto *BarLoc = Env.getStorageLocation(*BarDecl); 3365 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 3366 3367 EXPECT_EQ(Env.getValue(*BarLoc), FooVal); 3368 }); 3369 } 3370 3371 TEST(TransferTest, AssignFromBoolLiteral) { 3372 std::string Code = R"( 3373 void target() { 3374 bool Foo = true; 3375 bool Bar = false; 3376 // [[p]] 3377 } 3378 )"; 3379 runDataflow( 3380 Code, 3381 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3382 ASTContext &ASTCtx) { 3383 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3384 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3385 3386 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3387 ASSERT_THAT(FooDecl, NotNull()); 3388 3389 const auto *FooVal = 3390 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3391 ASSERT_THAT(FooVal, NotNull()); 3392 3393 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3394 ASSERT_THAT(BarDecl, NotNull()); 3395 3396 const auto *BarVal = 3397 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 3398 ASSERT_THAT(BarVal, NotNull()); 3399 3400 EXPECT_EQ(FooVal, &Env.getBoolLiteralValue(true)); 3401 EXPECT_EQ(BarVal, &Env.getBoolLiteralValue(false)); 3402 }); 3403 } 3404 3405 TEST(TransferTest, AssignFromCompositeBoolExpression) { 3406 { 3407 std::string Code = R"( 3408 void target(bool Foo, bool Bar, bool Qux) { 3409 bool Baz = (Foo) && (Bar || Qux); 3410 // [[p]] 3411 } 3412 )"; 3413 runDataflow( 3414 Code, 3415 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3416 ASTContext &ASTCtx) { 3417 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3418 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3419 3420 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3421 ASSERT_THAT(FooDecl, NotNull()); 3422 3423 const auto *FooVal = 3424 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3425 ASSERT_THAT(FooVal, NotNull()); 3426 3427 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3428 ASSERT_THAT(BarDecl, NotNull()); 3429 3430 const auto *BarVal = 3431 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 3432 ASSERT_THAT(BarVal, NotNull()); 3433 3434 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 3435 ASSERT_THAT(QuxDecl, NotNull()); 3436 3437 const auto *QuxVal = 3438 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl)); 3439 ASSERT_THAT(QuxVal, NotNull()); 3440 3441 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3442 ASSERT_THAT(BazDecl, NotNull()); 3443 3444 const auto *BazVal = 3445 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl)); 3446 ASSERT_THAT(BazVal, NotNull()); 3447 auto &A = Env.arena(); 3448 EXPECT_EQ(&BazVal->formula(), 3449 &A.makeAnd(FooVal->formula(), 3450 A.makeOr(BarVal->formula(), QuxVal->formula()))); 3451 }); 3452 } 3453 3454 { 3455 std::string Code = R"( 3456 void target(bool Foo, bool Bar, bool Qux) { 3457 bool Baz = (Foo && Qux) || (Bar); 3458 // [[p]] 3459 } 3460 )"; 3461 runDataflow( 3462 Code, 3463 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3464 ASTContext &ASTCtx) { 3465 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3466 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3467 3468 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3469 ASSERT_THAT(FooDecl, NotNull()); 3470 3471 const auto *FooVal = 3472 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3473 ASSERT_THAT(FooVal, NotNull()); 3474 3475 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3476 ASSERT_THAT(BarDecl, NotNull()); 3477 3478 const auto *BarVal = 3479 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 3480 ASSERT_THAT(BarVal, NotNull()); 3481 3482 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 3483 ASSERT_THAT(QuxDecl, NotNull()); 3484 3485 const auto *QuxVal = 3486 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl)); 3487 ASSERT_THAT(QuxVal, NotNull()); 3488 3489 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3490 ASSERT_THAT(BazDecl, NotNull()); 3491 3492 const auto *BazVal = 3493 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl)); 3494 ASSERT_THAT(BazVal, NotNull()); 3495 auto &A = Env.arena(); 3496 EXPECT_EQ(&BazVal->formula(), 3497 &A.makeOr(A.makeAnd(FooVal->formula(), QuxVal->formula()), 3498 BarVal->formula())); 3499 }); 3500 } 3501 3502 { 3503 std::string Code = R"( 3504 void target(bool A, bool B, bool C, bool D) { 3505 bool Foo = ((A && B) && C) && D; 3506 // [[p]] 3507 } 3508 )"; 3509 runDataflow( 3510 Code, 3511 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3512 ASTContext &ASTCtx) { 3513 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3514 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3515 3516 const ValueDecl *ADecl = findValueDecl(ASTCtx, "A"); 3517 ASSERT_THAT(ADecl, NotNull()); 3518 3519 const auto *AVal = dyn_cast_or_null<BoolValue>(Env.getValue(*ADecl)); 3520 ASSERT_THAT(AVal, NotNull()); 3521 3522 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B"); 3523 ASSERT_THAT(BDecl, NotNull()); 3524 3525 const auto *BVal = dyn_cast_or_null<BoolValue>(Env.getValue(*BDecl)); 3526 ASSERT_THAT(BVal, NotNull()); 3527 3528 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C"); 3529 ASSERT_THAT(CDecl, NotNull()); 3530 3531 const auto *CVal = dyn_cast_or_null<BoolValue>(Env.getValue(*CDecl)); 3532 ASSERT_THAT(CVal, NotNull()); 3533 3534 const ValueDecl *DDecl = findValueDecl(ASTCtx, "D"); 3535 ASSERT_THAT(DDecl, NotNull()); 3536 3537 const auto *DVal = dyn_cast_or_null<BoolValue>(Env.getValue(*DDecl)); 3538 ASSERT_THAT(DVal, NotNull()); 3539 3540 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3541 ASSERT_THAT(FooDecl, NotNull()); 3542 3543 const auto *FooVal = 3544 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3545 ASSERT_THAT(FooVal, NotNull()); 3546 auto &A = Env.arena(); 3547 EXPECT_EQ( 3548 &FooVal->formula(), 3549 &A.makeAnd(A.makeAnd(A.makeAnd(AVal->formula(), BVal->formula()), 3550 CVal->formula()), 3551 DVal->formula())); 3552 }); 3553 } 3554 } 3555 3556 TEST(TransferTest, AssignFromBoolNegation) { 3557 std::string Code = R"( 3558 void target() { 3559 bool Foo = true; 3560 bool Bar = !(Foo); 3561 // [[p]] 3562 } 3563 )"; 3564 runDataflow( 3565 Code, 3566 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3567 ASTContext &ASTCtx) { 3568 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3569 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3570 3571 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3572 ASSERT_THAT(FooDecl, NotNull()); 3573 3574 const auto *FooVal = 3575 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl)); 3576 ASSERT_THAT(FooVal, NotNull()); 3577 3578 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3579 ASSERT_THAT(BarDecl, NotNull()); 3580 3581 const auto *BarVal = 3582 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl)); 3583 ASSERT_THAT(BarVal, NotNull()); 3584 auto &A = Env.arena(); 3585 EXPECT_EQ(&BarVal->formula(), &A.makeNot(FooVal->formula())); 3586 }); 3587 } 3588 3589 TEST(TransferTest, BuiltinExpect) { 3590 std::string Code = R"( 3591 void target(long Foo) { 3592 long Bar = __builtin_expect(Foo, true); 3593 /*[[p]]*/ 3594 } 3595 )"; 3596 runDataflow( 3597 Code, 3598 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3599 ASTContext &ASTCtx) { 3600 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3601 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3602 3603 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3604 ASSERT_THAT(FooDecl, NotNull()); 3605 3606 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3607 ASSERT_THAT(BarDecl, NotNull()); 3608 3609 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3610 }); 3611 } 3612 3613 // `__builtin_expect` takes and returns a `long` argument, so other types 3614 // involve casts. This verifies that we identify the input and output in that 3615 // case. 3616 TEST(TransferTest, BuiltinExpectBoolArg) { 3617 std::string Code = R"( 3618 void target(bool Foo) { 3619 bool Bar = __builtin_expect(Foo, true); 3620 /*[[p]]*/ 3621 } 3622 )"; 3623 runDataflow( 3624 Code, 3625 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3626 ASTContext &ASTCtx) { 3627 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3628 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3629 3630 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3631 ASSERT_THAT(FooDecl, NotNull()); 3632 3633 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3634 ASSERT_THAT(BarDecl, NotNull()); 3635 3636 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3637 }); 3638 } 3639 3640 TEST(TransferTest, BuiltinUnreachable) { 3641 std::string Code = R"( 3642 void target(bool Foo) { 3643 bool Bar = false; 3644 if (Foo) 3645 Bar = Foo; 3646 else 3647 __builtin_unreachable(); 3648 (void)0; 3649 /*[[p]]*/ 3650 } 3651 )"; 3652 runDataflow( 3653 Code, 3654 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3655 ASTContext &ASTCtx) { 3656 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3657 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3658 3659 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3660 ASSERT_THAT(FooDecl, NotNull()); 3661 3662 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3663 ASSERT_THAT(BarDecl, NotNull()); 3664 3665 // `__builtin_unreachable` promises that the code is 3666 // unreachable, so the compiler treats the "then" branch as the 3667 // only possible predecessor of this statement. 3668 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3669 }); 3670 } 3671 3672 TEST(TransferTest, BuiltinTrap) { 3673 std::string Code = R"( 3674 void target(bool Foo) { 3675 bool Bar = false; 3676 if (Foo) 3677 Bar = Foo; 3678 else 3679 __builtin_trap(); 3680 (void)0; 3681 /*[[p]]*/ 3682 } 3683 )"; 3684 runDataflow( 3685 Code, 3686 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3687 ASTContext &ASTCtx) { 3688 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3689 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3690 3691 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3692 ASSERT_THAT(FooDecl, NotNull()); 3693 3694 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3695 ASSERT_THAT(BarDecl, NotNull()); 3696 3697 // `__builtin_trap` ensures program termination, so only the 3698 // "then" branch is a predecessor of this statement. 3699 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3700 }); 3701 } 3702 3703 TEST(TransferTest, BuiltinDebugTrap) { 3704 std::string Code = R"( 3705 void target(bool Foo) { 3706 bool Bar = false; 3707 if (Foo) 3708 Bar = Foo; 3709 else 3710 __builtin_debugtrap(); 3711 (void)0; 3712 /*[[p]]*/ 3713 } 3714 )"; 3715 runDataflow( 3716 Code, 3717 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3718 ASTContext &ASTCtx) { 3719 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3720 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3721 3722 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3723 ASSERT_THAT(FooDecl, NotNull()); 3724 3725 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3726 ASSERT_THAT(BarDecl, NotNull()); 3727 3728 // `__builtin_debugtrap` doesn't ensure program termination. 3729 EXPECT_NE(Env.getValue(*FooDecl), Env.getValue(*BarDecl)); 3730 }); 3731 } 3732 3733 TEST(TransferTest, StaticIntSingleVarDecl) { 3734 std::string Code = R"( 3735 void target() { 3736 static int Foo; 3737 // [[p]] 3738 } 3739 )"; 3740 runDataflow( 3741 Code, 3742 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3743 ASTContext &ASTCtx) { 3744 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3745 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3746 3747 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3748 ASSERT_THAT(FooDecl, NotNull()); 3749 3750 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 3751 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 3752 3753 const Value *FooVal = Env.getValue(*FooLoc); 3754 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 3755 }); 3756 } 3757 3758 TEST(TransferTest, StaticIntGroupVarDecl) { 3759 std::string Code = R"( 3760 void target() { 3761 static int Foo, Bar; 3762 (void)0; 3763 // [[p]] 3764 } 3765 )"; 3766 runDataflow( 3767 Code, 3768 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3769 ASTContext &ASTCtx) { 3770 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3771 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3772 3773 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3774 ASSERT_THAT(FooDecl, NotNull()); 3775 3776 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3777 ASSERT_THAT(BarDecl, NotNull()); 3778 3779 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 3780 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 3781 3782 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 3783 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 3784 3785 const Value *FooVal = Env.getValue(*FooLoc); 3786 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 3787 3788 const Value *BarVal = Env.getValue(*BarLoc); 3789 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 3790 3791 EXPECT_NE(FooVal, BarVal); 3792 }); 3793 } 3794 3795 TEST(TransferTest, GlobalIntVarDecl) { 3796 std::string Code = R"( 3797 static int Foo; 3798 3799 void target() { 3800 int Bar = Foo; 3801 int Baz = Foo; 3802 // [[p]] 3803 } 3804 )"; 3805 runDataflow( 3806 Code, 3807 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3808 ASTContext &ASTCtx) { 3809 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3810 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3811 3812 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3813 ASSERT_THAT(BarDecl, NotNull()); 3814 3815 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3816 ASSERT_THAT(BazDecl, NotNull()); 3817 3818 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 3819 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 3820 EXPECT_EQ(BarVal, BazVal); 3821 }); 3822 } 3823 3824 TEST(TransferTest, StaticMemberIntVarDecl) { 3825 std::string Code = R"( 3826 struct A { 3827 static int Foo; 3828 }; 3829 3830 void target(A a) { 3831 int Bar = a.Foo; 3832 int Baz = a.Foo; 3833 // [[p]] 3834 } 3835 )"; 3836 runDataflow( 3837 Code, 3838 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3839 ASTContext &ASTCtx) { 3840 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3841 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3842 3843 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3844 ASSERT_THAT(BarDecl, NotNull()); 3845 3846 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3847 ASSERT_THAT(BazDecl, NotNull()); 3848 3849 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 3850 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 3851 EXPECT_EQ(BarVal, BazVal); 3852 }); 3853 } 3854 3855 TEST(TransferTest, StaticMemberRefVarDecl) { 3856 std::string Code = R"( 3857 struct A { 3858 static int &Foo; 3859 }; 3860 3861 void target(A a) { 3862 int Bar = a.Foo; 3863 int Baz = a.Foo; 3864 // [[p]] 3865 } 3866 )"; 3867 runDataflow( 3868 Code, 3869 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3870 ASTContext &ASTCtx) { 3871 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3872 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3873 3874 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3875 ASSERT_THAT(BarDecl, NotNull()); 3876 3877 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3878 ASSERT_THAT(BazDecl, NotNull()); 3879 3880 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 3881 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl)); 3882 EXPECT_EQ(BarVal, BazVal); 3883 }); 3884 } 3885 3886 TEST(TransferTest, AssignMemberBeforeCopy) { 3887 std::string Code = R"( 3888 struct A { 3889 int Foo; 3890 }; 3891 3892 void target() { 3893 A A1; 3894 A A2; 3895 int Bar; 3896 A1.Foo = Bar; 3897 A2 = A1; 3898 // [[p]] 3899 } 3900 )"; 3901 runDataflow( 3902 Code, 3903 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3904 ASTContext &ASTCtx) { 3905 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3906 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3907 3908 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3909 ASSERT_THAT(FooDecl, NotNull()); 3910 3911 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3912 ASSERT_THAT(BarDecl, NotNull()); 3913 3914 const ValueDecl *A1Decl = findValueDecl(ASTCtx, "A1"); 3915 ASSERT_THAT(A1Decl, NotNull()); 3916 3917 const ValueDecl *A2Decl = findValueDecl(ASTCtx, "A2"); 3918 ASSERT_THAT(A2Decl, NotNull()); 3919 3920 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl)); 3921 3922 const auto &A2Loc = 3923 *cast<RecordStorageLocation>(Env.getStorageLocation(*A2Decl)); 3924 EXPECT_EQ(getFieldValue(&A2Loc, *FooDecl, Env), BarVal); 3925 }); 3926 } 3927 3928 TEST(TransferTest, BooleanEquality) { 3929 std::string Code = R"( 3930 void target(bool Bar) { 3931 bool Foo = true; 3932 if (Bar == Foo) { 3933 (void)0; 3934 /*[[p-then]]*/ 3935 } else { 3936 (void)0; 3937 /*[[p-else]]*/ 3938 } 3939 } 3940 )"; 3941 runDataflow( 3942 Code, 3943 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3944 ASTContext &ASTCtx) { 3945 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else")); 3946 const Environment &EnvThen = 3947 getEnvironmentAtAnnotation(Results, "p-then"); 3948 const Environment &EnvElse = 3949 getEnvironmentAtAnnotation(Results, "p-else"); 3950 3951 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3952 ASSERT_THAT(BarDecl, NotNull()); 3953 3954 auto &BarValThen = getFormula(*BarDecl, EnvThen); 3955 EXPECT_TRUE(EnvThen.proves(BarValThen)); 3956 3957 auto &BarValElse = getFormula(*BarDecl, EnvElse); 3958 EXPECT_TRUE(EnvElse.proves(EnvElse.arena().makeNot(BarValElse))); 3959 }); 3960 } 3961 3962 TEST(TransferTest, BooleanInequality) { 3963 std::string Code = R"( 3964 void target(bool Bar) { 3965 bool Foo = true; 3966 if (Bar != Foo) { 3967 (void)0; 3968 /*[[p-then]]*/ 3969 } else { 3970 (void)0; 3971 /*[[p-else]]*/ 3972 } 3973 } 3974 )"; 3975 runDataflow( 3976 Code, 3977 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3978 ASTContext &ASTCtx) { 3979 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else")); 3980 const Environment &EnvThen = 3981 getEnvironmentAtAnnotation(Results, "p-then"); 3982 const Environment &EnvElse = 3983 getEnvironmentAtAnnotation(Results, "p-else"); 3984 3985 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3986 ASSERT_THAT(BarDecl, NotNull()); 3987 3988 auto &BarValThen = getFormula(*BarDecl, EnvThen); 3989 EXPECT_TRUE(EnvThen.proves(EnvThen.arena().makeNot(BarValThen))); 3990 3991 auto &BarValElse = getFormula(*BarDecl, EnvElse); 3992 EXPECT_TRUE(EnvElse.proves(BarValElse)); 3993 }); 3994 } 3995 3996 TEST(TransferTest, IntegerLiteralEquality) { 3997 std::string Code = R"( 3998 void target() { 3999 bool equal = (42 == 42); 4000 // [[p]] 4001 } 4002 )"; 4003 runDataflow( 4004 Code, 4005 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4006 ASTContext &ASTCtx) { 4007 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4008 4009 auto &Equal = 4010 getValueForDecl<BoolValue>(ASTCtx, Env, "equal").formula(); 4011 EXPECT_TRUE(Env.proves(Equal)); 4012 }); 4013 } 4014 4015 TEST(TransferTest, CorrelatedBranches) { 4016 std::string Code = R"( 4017 void target(bool B, bool C) { 4018 if (B) { 4019 return; 4020 } 4021 (void)0; 4022 /*[[p0]]*/ 4023 if (C) { 4024 B = true; 4025 /*[[p1]]*/ 4026 } 4027 if (B) { 4028 (void)0; 4029 /*[[p2]]*/ 4030 } 4031 } 4032 )"; 4033 runDataflow( 4034 Code, 4035 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4036 ASTContext &ASTCtx) { 4037 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p0", "p1", "p2")); 4038 4039 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C"); 4040 ASSERT_THAT(CDecl, NotNull()); 4041 4042 { 4043 const Environment &Env = getEnvironmentAtAnnotation(Results, "p0"); 4044 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B"); 4045 ASSERT_THAT(BDecl, NotNull()); 4046 auto &BVal = getFormula(*BDecl, Env); 4047 4048 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BVal))); 4049 } 4050 4051 { 4052 const Environment &Env = getEnvironmentAtAnnotation(Results, "p1"); 4053 auto &CVal = getFormula(*CDecl, Env); 4054 EXPECT_TRUE(Env.proves(CVal)); 4055 } 4056 4057 { 4058 const Environment &Env = getEnvironmentAtAnnotation(Results, "p2"); 4059 auto &CVal = getFormula(*CDecl, Env); 4060 EXPECT_TRUE(Env.proves(CVal)); 4061 } 4062 }); 4063 } 4064 4065 TEST(TransferTest, LoopWithAssignmentConverges) { 4066 std::string Code = R"( 4067 bool foo(); 4068 4069 void target() { 4070 do { 4071 bool Bar = foo(); 4072 if (Bar) break; 4073 (void)Bar; 4074 /*[[p]]*/ 4075 } while (true); 4076 } 4077 )"; 4078 // The key property that we are verifying is implicit in `runDataflow` -- 4079 // namely, that the analysis succeeds, rather than hitting the maximum number 4080 // of iterations. 4081 runDataflow( 4082 Code, 4083 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4084 ASTContext &ASTCtx) { 4085 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4086 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4087 4088 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4089 ASSERT_THAT(BarDecl, NotNull()); 4090 4091 auto &BarVal = getFormula(*BarDecl, Env); 4092 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 4093 }); 4094 } 4095 4096 TEST(TransferTest, LoopWithStagedAssignments) { 4097 std::string Code = R"( 4098 bool foo(); 4099 4100 void target() { 4101 bool Bar = false; 4102 bool Err = false; 4103 while (foo()) { 4104 if (Bar) 4105 Err = true; 4106 Bar = true; 4107 /*[[p]]*/ 4108 } 4109 } 4110 )"; 4111 runDataflow( 4112 Code, 4113 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4114 ASTContext &ASTCtx) { 4115 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4116 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4117 4118 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4119 ASSERT_THAT(BarDecl, NotNull()); 4120 const ValueDecl *ErrDecl = findValueDecl(ASTCtx, "Err"); 4121 ASSERT_THAT(ErrDecl, NotNull()); 4122 4123 auto &BarVal = getFormula(*BarDecl, Env); 4124 auto &ErrVal = getFormula(*ErrDecl, Env); 4125 EXPECT_TRUE(Env.proves(BarVal)); 4126 // An unsound analysis, for example only evaluating the loop once, can 4127 // conclude that `Err` is false. So, we test that this conclusion is not 4128 // reached. 4129 EXPECT_FALSE(Env.proves(Env.arena().makeNot(ErrVal))); 4130 }); 4131 } 4132 4133 TEST(TransferTest, LoopWithReferenceAssignmentConverges) { 4134 std::string Code = R"( 4135 bool &foo(); 4136 4137 void target() { 4138 do { 4139 bool& Bar = foo(); 4140 if (Bar) break; 4141 (void)Bar; 4142 /*[[p]]*/ 4143 } while (true); 4144 } 4145 )"; 4146 // The key property that we are verifying is that the analysis succeeds, 4147 // rather than hitting the maximum number of iterations. 4148 runDataflow( 4149 Code, 4150 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4151 ASTContext &ASTCtx) { 4152 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4153 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4154 4155 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4156 ASSERT_THAT(BarDecl, NotNull()); 4157 4158 auto &BarVal = getFormula(*BarDecl, Env); 4159 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 4160 }); 4161 } 4162 4163 TEST(TransferTest, LoopWithStructReferenceAssignmentConverges) { 4164 std::string Code = R"( 4165 struct Lookup { 4166 int x; 4167 }; 4168 4169 void target(Lookup val, bool b) { 4170 const Lookup* l = nullptr; 4171 while (b) { 4172 l = &val; 4173 /*[[p-inner]]*/ 4174 } 4175 (void)0; 4176 /*[[p-outer]]*/ 4177 } 4178 )"; 4179 // The key property that we are verifying is implicit in `runDataflow` -- 4180 // namely, that the analysis succeeds, rather than hitting the maximum number 4181 // of iterations. 4182 runDataflow( 4183 Code, 4184 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4185 ASTContext &ASTCtx) { 4186 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-inner", "p-outer")); 4187 const Environment &InnerEnv = 4188 getEnvironmentAtAnnotation(Results, "p-inner"); 4189 const Environment &OuterEnv = 4190 getEnvironmentAtAnnotation(Results, "p-outer"); 4191 4192 const ValueDecl *ValDecl = findValueDecl(ASTCtx, "val"); 4193 ASSERT_THAT(ValDecl, NotNull()); 4194 4195 const ValueDecl *LDecl = findValueDecl(ASTCtx, "l"); 4196 ASSERT_THAT(LDecl, NotNull()); 4197 4198 // Inner. 4199 auto *LVal = dyn_cast<PointerValue>(InnerEnv.getValue(*LDecl)); 4200 ASSERT_THAT(LVal, NotNull()); 4201 4202 EXPECT_EQ(&LVal->getPointeeLoc(), 4203 InnerEnv.getStorageLocation(*ValDecl)); 4204 4205 // Outer. 4206 LVal = dyn_cast<PointerValue>(OuterEnv.getValue(*LDecl)); 4207 ASSERT_THAT(LVal, NotNull()); 4208 4209 // The loop body may not have been executed, so we should not conclude 4210 // that `l` points to `val`. 4211 EXPECT_NE(&LVal->getPointeeLoc(), 4212 OuterEnv.getStorageLocation(*ValDecl)); 4213 }); 4214 } 4215 4216 TEST(TransferTest, LoopDereferencingChangingPointerConverges) { 4217 std::string Code = R"cc( 4218 bool some_condition(); 4219 4220 void target(int i1, int i2) { 4221 int *p = &i1; 4222 while (true) { 4223 (void)*p; 4224 if (some_condition()) 4225 p = &i1; 4226 else 4227 p = &i2; 4228 } 4229 } 4230 )cc"; 4231 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 4232 } 4233 4234 TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) { 4235 std::string Code = R"cc( 4236 struct Lookup { 4237 int x; 4238 }; 4239 4240 bool some_condition(); 4241 4242 void target(Lookup l1, Lookup l2) { 4243 Lookup *l = &l1; 4244 while (true) { 4245 (void)l->x; 4246 if (some_condition()) 4247 l = &l1; 4248 else 4249 l = &l2; 4250 } 4251 } 4252 )cc"; 4253 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 4254 } 4255 4256 TEST(TransferTest, LoopWithShortCircuitedConditionConverges) { 4257 std::string Code = R"cc( 4258 bool foo(); 4259 4260 void target() { 4261 bool c = false; 4262 while (foo() || foo()) { 4263 c = true; 4264 } 4265 } 4266 )cc"; 4267 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded()); 4268 } 4269 4270 TEST(TransferTest, LoopCanProveInvariantForBoolean) { 4271 // Check that we can prove `b` is always false in the loop. 4272 // This test exercises the logic in `widenDistinctValues()` that preserves 4273 // information if the boolean can be proved to be either true or false in both 4274 // the previous and current iteration. 4275 std::string Code = R"cc( 4276 int return_int(); 4277 void target() { 4278 bool b = return_int() == 0; 4279 if (b) return; 4280 while (true) { 4281 b; 4282 // [[p]] 4283 b = return_int() == 0; 4284 if (b) return; 4285 } 4286 } 4287 )cc"; 4288 runDataflow( 4289 Code, 4290 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4291 ASTContext &ASTCtx) { 4292 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4293 auto &BVal = getValueForDecl<BoolValue>(ASTCtx, Env, "b"); 4294 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BVal.formula()))); 4295 }); 4296 } 4297 4298 TEST(TransferTest, DoesNotCrashOnUnionThisExpr) { 4299 std::string Code = R"( 4300 union Union { 4301 int A; 4302 float B; 4303 }; 4304 4305 void foo() { 4306 Union A; 4307 Union B; 4308 A = B; 4309 } 4310 )"; 4311 // This is a crash regression test when calling the transfer function on a 4312 // `CXXThisExpr` that refers to a union. 4313 runDataflow( 4314 Code, 4315 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &, 4316 ASTContext &) {}, 4317 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator="); 4318 } 4319 4320 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToRefs) { 4321 std::string Code = R"( 4322 struct A { 4323 int Foo; 4324 int Bar; 4325 }; 4326 4327 void target() { 4328 int Qux; 4329 A Baz; 4330 Baz.Foo = Qux; 4331 auto &FooRef = Baz.Foo; 4332 auto &BarRef = Baz.Bar; 4333 auto &[BoundFooRef, BoundBarRef] = Baz; 4334 // [[p]] 4335 } 4336 )"; 4337 runDataflow( 4338 Code, 4339 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4340 ASTContext &ASTCtx) { 4341 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4342 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4343 4344 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 4345 ASSERT_THAT(FooRefDecl, NotNull()); 4346 4347 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 4348 ASSERT_THAT(BarRefDecl, NotNull()); 4349 4350 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4351 ASSERT_THAT(QuxDecl, NotNull()); 4352 4353 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef"); 4354 ASSERT_THAT(BoundFooRefDecl, NotNull()); 4355 4356 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef"); 4357 ASSERT_THAT(BoundBarRefDecl, NotNull()); 4358 4359 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 4360 ASSERT_THAT(FooRefLoc, NotNull()); 4361 4362 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 4363 ASSERT_THAT(BarRefLoc, NotNull()); 4364 4365 const Value *QuxVal = Env.getValue(*QuxDecl); 4366 ASSERT_THAT(QuxVal, NotNull()); 4367 4368 const StorageLocation *BoundFooRefLoc = 4369 Env.getStorageLocation(*BoundFooRefDecl); 4370 EXPECT_EQ(BoundFooRefLoc, FooRefLoc); 4371 4372 const StorageLocation *BoundBarRefLoc = 4373 Env.getStorageLocation(*BoundBarRefDecl); 4374 EXPECT_EQ(BoundBarRefLoc, BarRefLoc); 4375 4376 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal); 4377 }); 4378 } 4379 4380 TEST(TransferTest, StructuredBindingAssignFromStructRefMembersToRefs) { 4381 std::string Code = R"( 4382 struct A { 4383 int &Foo; 4384 int &Bar; 4385 }; 4386 4387 void target(A Baz) { 4388 int Qux; 4389 Baz.Foo = Qux; 4390 auto &FooRef = Baz.Foo; 4391 auto &BarRef = Baz.Bar; 4392 auto &[BoundFooRef, BoundBarRef] = Baz; 4393 // [[p]] 4394 } 4395 )"; 4396 runDataflow( 4397 Code, 4398 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4399 ASTContext &ASTCtx) { 4400 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4401 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4402 4403 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 4404 ASSERT_THAT(FooRefDecl, NotNull()); 4405 4406 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 4407 ASSERT_THAT(BarRefDecl, NotNull()); 4408 4409 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4410 ASSERT_THAT(QuxDecl, NotNull()); 4411 4412 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef"); 4413 ASSERT_THAT(BoundFooRefDecl, NotNull()); 4414 4415 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef"); 4416 ASSERT_THAT(BoundBarRefDecl, NotNull()); 4417 4418 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 4419 ASSERT_THAT(FooRefLoc, NotNull()); 4420 4421 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 4422 ASSERT_THAT(BarRefLoc, NotNull()); 4423 4424 const Value *QuxVal = Env.getValue(*QuxDecl); 4425 ASSERT_THAT(QuxVal, NotNull()); 4426 4427 const StorageLocation *BoundFooRefLoc = 4428 Env.getStorageLocation(*BoundFooRefDecl); 4429 EXPECT_EQ(BoundFooRefLoc, FooRefLoc); 4430 4431 const StorageLocation *BoundBarRefLoc = 4432 Env.getStorageLocation(*BoundBarRefDecl); 4433 EXPECT_EQ(BoundBarRefLoc, BarRefLoc); 4434 4435 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal); 4436 }); 4437 } 4438 4439 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToInts) { 4440 std::string Code = R"( 4441 struct A { 4442 int Foo; 4443 int Bar; 4444 }; 4445 4446 void target() { 4447 int Qux; 4448 A Baz; 4449 Baz.Foo = Qux; 4450 auto &FooRef = Baz.Foo; 4451 auto &BarRef = Baz.Bar; 4452 auto [BoundFoo, BoundBar] = Baz; 4453 // [[p]] 4454 } 4455 )"; 4456 runDataflow( 4457 Code, 4458 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4459 ASTContext &ASTCtx) { 4460 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4461 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4462 4463 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 4464 ASSERT_THAT(FooRefDecl, NotNull()); 4465 4466 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 4467 ASSERT_THAT(BarRefDecl, NotNull()); 4468 4469 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 4470 ASSERT_THAT(BoundFooDecl, NotNull()); 4471 4472 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 4473 ASSERT_THAT(BoundBarDecl, NotNull()); 4474 4475 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 4476 ASSERT_THAT(QuxDecl, NotNull()); 4477 4478 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl); 4479 ASSERT_THAT(FooRefLoc, NotNull()); 4480 4481 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl); 4482 ASSERT_THAT(BarRefLoc, NotNull()); 4483 4484 const Value *QuxVal = Env.getValue(*QuxDecl); 4485 ASSERT_THAT(QuxVal, NotNull()); 4486 4487 const StorageLocation *BoundFooLoc = 4488 Env.getStorageLocation(*BoundFooDecl); 4489 EXPECT_NE(BoundFooLoc, FooRefLoc); 4490 4491 const StorageLocation *BoundBarLoc = 4492 Env.getStorageLocation(*BoundBarDecl); 4493 EXPECT_NE(BoundBarLoc, BarRefLoc); 4494 4495 EXPECT_EQ(Env.getValue(*BoundFooDecl), QuxVal); 4496 }); 4497 } 4498 4499 TEST(TransferTest, StructuredBindingAssignFromTupleLikeType) { 4500 std::string Code = R"( 4501 namespace std { 4502 using size_t = int; 4503 template <class> struct tuple_size; 4504 template <std::size_t, class> struct tuple_element; 4505 template <class...> class tuple; 4506 4507 namespace { 4508 template <class T, T v> 4509 struct size_helper { static const T value = v; }; 4510 } // namespace 4511 4512 template <class... T> 4513 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {}; 4514 4515 template <std::size_t I, class... T> 4516 struct tuple_element<I, tuple<T...>> { 4517 using type = __type_pack_element<I, T...>; 4518 }; 4519 4520 template <class...> class tuple {}; 4521 4522 template <std::size_t I, class... T> 4523 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 4524 } // namespace std 4525 4526 std::tuple<bool, int> makeTuple(); 4527 4528 void target(bool B) { 4529 auto [BoundFoo, BoundBar] = makeTuple(); 4530 bool Baz; 4531 // Include if-then-else to test interaction of `BindingDecl` with join. 4532 if (B) { 4533 Baz = BoundFoo; 4534 (void)BoundBar; 4535 // [[p1]] 4536 } else { 4537 Baz = BoundFoo; 4538 } 4539 (void)0; 4540 // [[p2]] 4541 } 4542 )"; 4543 runDataflow( 4544 Code, 4545 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4546 ASTContext &ASTCtx) { 4547 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 4548 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 4549 4550 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 4551 ASSERT_THAT(BoundFooDecl, NotNull()); 4552 4553 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 4554 ASSERT_THAT(BoundBarDecl, NotNull()); 4555 4556 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4557 ASSERT_THAT(BazDecl, NotNull()); 4558 4559 // BindingDecls always map to references -- either lvalue or rvalue, so 4560 // we still need to skip here. 4561 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl); 4562 ASSERT_THAT(BoundFooValue, NotNull()); 4563 EXPECT_TRUE(isa<BoolValue>(BoundFooValue)); 4564 4565 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl); 4566 ASSERT_THAT(BoundBarValue, NotNull()); 4567 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue)); 4568 4569 // Test that a `DeclRefExpr` to a `BindingDecl` works as expected. 4570 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue); 4571 4572 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 4573 4574 // Test that `BoundFooDecl` retains the value we expect, after the join. 4575 BoundFooValue = Env2.getValue(*BoundFooDecl); 4576 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue); 4577 }); 4578 } 4579 4580 TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) { 4581 std::string Code = R"( 4582 namespace std { 4583 using size_t = int; 4584 template <class> struct tuple_size; 4585 template <std::size_t, class> struct tuple_element; 4586 template <class...> class tuple; 4587 4588 namespace { 4589 template <class T, T v> 4590 struct size_helper { static const T value = v; }; 4591 } // namespace 4592 4593 template <class... T> 4594 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {}; 4595 4596 template <std::size_t I, class... T> 4597 struct tuple_element<I, tuple<T...>> { 4598 using type = __type_pack_element<I, T...>; 4599 }; 4600 4601 template <class...> class tuple {}; 4602 4603 template <std::size_t I, class... T> 4604 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 4605 } // namespace std 4606 4607 std::tuple<bool, int> &getTuple(); 4608 4609 void target(bool B) { 4610 auto &[BoundFoo, BoundBar] = getTuple(); 4611 bool Baz; 4612 // Include if-then-else to test interaction of `BindingDecl` with join. 4613 if (B) { 4614 Baz = BoundFoo; 4615 (void)BoundBar; 4616 // [[p1]] 4617 } else { 4618 Baz = BoundFoo; 4619 } 4620 (void)0; 4621 // [[p2]] 4622 } 4623 )"; 4624 runDataflow( 4625 Code, 4626 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4627 ASTContext &ASTCtx) { 4628 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 4629 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 4630 4631 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 4632 ASSERT_THAT(BoundFooDecl, NotNull()); 4633 4634 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 4635 ASSERT_THAT(BoundBarDecl, NotNull()); 4636 4637 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4638 ASSERT_THAT(BazDecl, NotNull()); 4639 4640 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl); 4641 ASSERT_THAT(BoundFooValue, NotNull()); 4642 EXPECT_TRUE(isa<BoolValue>(BoundFooValue)); 4643 4644 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl); 4645 ASSERT_THAT(BoundBarValue, NotNull()); 4646 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue)); 4647 4648 // Test that a `DeclRefExpr` to a `BindingDecl` (with reference type) 4649 // works as expected. We don't test aliasing properties of the 4650 // reference, because we don't model `std::get` and so have no way to 4651 // equate separate references into the tuple. 4652 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue); 4653 4654 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 4655 4656 // Test that `BoundFooDecl` retains the value we expect, after the join. 4657 BoundFooValue = Env2.getValue(*BoundFooDecl); 4658 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue); 4659 }); 4660 } 4661 4662 TEST(TransferTest, BinaryOperatorComma) { 4663 std::string Code = R"( 4664 void target(int Foo, int Bar) { 4665 int &Baz = (Foo, Bar); 4666 // [[p]] 4667 } 4668 )"; 4669 runDataflow( 4670 Code, 4671 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4672 ASTContext &ASTCtx) { 4673 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4674 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4675 4676 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4677 ASSERT_THAT(BarDecl, NotNull()); 4678 4679 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4680 ASSERT_THAT(BazDecl, NotNull()); 4681 4682 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 4683 ASSERT_THAT(BarLoc, NotNull()); 4684 4685 const StorageLocation *BazLoc = Env.getStorageLocation(*BazDecl); 4686 EXPECT_EQ(BazLoc, BarLoc); 4687 }); 4688 } 4689 4690 TEST(TransferTest, IfStmtBranchExtendsFlowCondition) { 4691 std::string Code = R"( 4692 void target(bool Foo) { 4693 if (Foo) { 4694 (void)0; 4695 // [[if_then]] 4696 } else { 4697 (void)0; 4698 // [[if_else]] 4699 } 4700 } 4701 )"; 4702 runDataflow( 4703 Code, 4704 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4705 ASTContext &ASTCtx) { 4706 ASSERT_THAT(Results.keys(), UnorderedElementsAre("if_then", "if_else")); 4707 const Environment &ThenEnv = 4708 getEnvironmentAtAnnotation(Results, "if_then"); 4709 const Environment &ElseEnv = 4710 getEnvironmentAtAnnotation(Results, "if_else"); 4711 4712 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4713 ASSERT_THAT(FooDecl, NotNull()); 4714 4715 auto &ThenFooVal= getFormula(*FooDecl, ThenEnv); 4716 EXPECT_TRUE(ThenEnv.proves(ThenFooVal)); 4717 4718 auto &ElseFooVal = getFormula(*FooDecl, ElseEnv); 4719 EXPECT_TRUE(ElseEnv.proves(ElseEnv.arena().makeNot(ElseFooVal))); 4720 }); 4721 } 4722 4723 TEST(TransferTest, WhileStmtBranchExtendsFlowCondition) { 4724 std::string Code = R"( 4725 void target(bool Foo) { 4726 while (Foo) { 4727 (void)0; 4728 // [[loop_body]] 4729 } 4730 (void)0; 4731 // [[after_loop]] 4732 } 4733 )"; 4734 runDataflow( 4735 Code, 4736 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4737 ASTContext &ASTCtx) { 4738 ASSERT_THAT(Results.keys(), 4739 UnorderedElementsAre("loop_body", "after_loop")); 4740 const Environment &LoopBodyEnv = 4741 getEnvironmentAtAnnotation(Results, "loop_body"); 4742 const Environment &AfterLoopEnv = 4743 getEnvironmentAtAnnotation(Results, "after_loop"); 4744 4745 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4746 ASSERT_THAT(FooDecl, NotNull()); 4747 4748 auto &LoopBodyFooVal = getFormula(*FooDecl, LoopBodyEnv); 4749 EXPECT_TRUE(LoopBodyEnv.proves(LoopBodyFooVal)); 4750 4751 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 4752 EXPECT_TRUE( 4753 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal))); 4754 }); 4755 } 4756 4757 TEST(TransferTest, DoWhileStmtBranchExtendsFlowCondition) { 4758 std::string Code = R"( 4759 void target(bool Foo) { 4760 bool Bar = true; 4761 do { 4762 (void)0; 4763 // [[loop_body]] 4764 Bar = false; 4765 } while (Foo); 4766 (void)0; 4767 // [[after_loop]] 4768 } 4769 )"; 4770 runDataflow( 4771 Code, 4772 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4773 ASTContext &ASTCtx) { 4774 ASSERT_THAT(Results.keys(), 4775 UnorderedElementsAre("loop_body", "after_loop")); 4776 const Environment &LoopBodyEnv = 4777 getEnvironmentAtAnnotation(Results, "loop_body"); 4778 const Environment &AfterLoopEnv = 4779 getEnvironmentAtAnnotation(Results, "after_loop"); 4780 auto &A = AfterLoopEnv.arena(); 4781 4782 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4783 ASSERT_THAT(FooDecl, NotNull()); 4784 4785 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4786 ASSERT_THAT(BarDecl, NotNull()); 4787 4788 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 4789 auto &LoopBodyBarVal = getFormula(*BarDecl, LoopBodyEnv); 4790 EXPECT_TRUE( 4791 LoopBodyEnv.proves(A.makeOr(LoopBodyBarVal, LoopBodyFooVal))); 4792 4793 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 4794 auto &AfterLoopBarVal = getFormula(*BarDecl, AfterLoopEnv); 4795 EXPECT_TRUE(AfterLoopEnv.proves(A.makeNot(AfterLoopFooVal))); 4796 EXPECT_TRUE(AfterLoopEnv.proves(A.makeNot(AfterLoopBarVal))); 4797 }); 4798 } 4799 4800 TEST(TransferTest, ForStmtBranchExtendsFlowCondition) { 4801 std::string Code = R"( 4802 void target(bool Foo) { 4803 for (; Foo;) { 4804 (void)0; 4805 // [[loop_body]] 4806 } 4807 (void)0; 4808 // [[after_loop]] 4809 } 4810 )"; 4811 runDataflow( 4812 Code, 4813 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4814 ASTContext &ASTCtx) { 4815 ASSERT_THAT(Results.keys(), 4816 UnorderedElementsAre("loop_body", "after_loop")); 4817 const Environment &LoopBodyEnv = 4818 getEnvironmentAtAnnotation(Results, "loop_body"); 4819 const Environment &AfterLoopEnv = 4820 getEnvironmentAtAnnotation(Results, "after_loop"); 4821 4822 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4823 ASSERT_THAT(FooDecl, NotNull()); 4824 4825 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 4826 EXPECT_TRUE(LoopBodyEnv.proves(LoopBodyFooVal)); 4827 4828 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv); 4829 EXPECT_TRUE( 4830 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal))); 4831 }); 4832 } 4833 4834 TEST(TransferTest, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition) { 4835 std::string Code = R"( 4836 void target(bool Foo) { 4837 for (;;) { 4838 (void)0; 4839 // [[loop_body]] 4840 } 4841 } 4842 )"; 4843 runDataflow( 4844 Code, 4845 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4846 ASTContext &ASTCtx) { 4847 ASSERT_THAT(Results.keys(), UnorderedElementsAre("loop_body")); 4848 const Environment &LoopBodyEnv = 4849 getEnvironmentAtAnnotation(Results, "loop_body"); 4850 4851 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4852 ASSERT_THAT(FooDecl, NotNull()); 4853 4854 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv); 4855 EXPECT_FALSE(LoopBodyEnv.proves(LoopBodyFooVal)); 4856 }); 4857 } 4858 4859 TEST(TransferTest, ContextSensitiveOptionDisabled) { 4860 std::string Code = R"( 4861 bool GiveBool(); 4862 void SetBool(bool &Var) { Var = true; } 4863 4864 void target() { 4865 bool Foo = GiveBool(); 4866 SetBool(Foo); 4867 // [[p]] 4868 } 4869 )"; 4870 runDataflow( 4871 Code, 4872 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4873 ASTContext &ASTCtx) { 4874 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4875 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4876 4877 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4878 ASSERT_THAT(FooDecl, NotNull()); 4879 4880 auto &FooVal = getFormula(*FooDecl, Env); 4881 EXPECT_FALSE(Env.proves(FooVal)); 4882 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 4883 }, 4884 {BuiltinOptions{/*.ContextSensitiveOpts=*/std::nullopt}}); 4885 } 4886 4887 TEST(TransferTest, ContextSensitiveReturnReference) { 4888 std::string Code = R"( 4889 class S {}; 4890 S& target(bool b, S &s) { 4891 return s; 4892 // [[p]] 4893 } 4894 )"; 4895 runDataflow( 4896 Code, 4897 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4898 ASTContext &ASTCtx) { 4899 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4900 4901 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 4902 ASSERT_THAT(SDecl, NotNull()); 4903 4904 auto *SLoc = Env.getStorageLocation(*SDecl); 4905 ASSERT_THAT(SLoc, NotNull()); 4906 4907 ASSERT_THAT(Env.getReturnStorageLocation(), Eq(SLoc)); 4908 }, 4909 {BuiltinOptions{ContextSensitiveOptions{}}}); 4910 } 4911 4912 // This test is a regression test, based on a real crash. 4913 TEST(TransferTest, ContextSensitiveReturnReferenceWithConditionalOperator) { 4914 std::string Code = R"( 4915 class S {}; 4916 S& target(bool b, S &s) { 4917 return b ? s : s; 4918 // [[p]] 4919 } 4920 )"; 4921 runDataflow( 4922 Code, 4923 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4924 ASTContext &ASTCtx) { 4925 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4926 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4927 4928 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 4929 ASSERT_THAT(SDecl, NotNull()); 4930 4931 auto *SLoc = Env.getStorageLocation(*SDecl); 4932 ASSERT_THAT(SLoc, NotNull()); 4933 EXPECT_THAT(Env.getValue(*SLoc), NotNull()); 4934 4935 auto *Loc = Env.getReturnStorageLocation(); 4936 ASSERT_THAT(Loc, NotNull()); 4937 EXPECT_THAT(Env.getValue(*Loc), NotNull()); 4938 4939 // TODO: We would really like to make this stronger assertion, but that 4940 // doesn't work because we don't propagate values correctly through 4941 // the conditional operator yet. 4942 // ASSERT_THAT(Loc, Eq(SLoc)); 4943 }, 4944 {BuiltinOptions{ContextSensitiveOptions{}}}); 4945 } 4946 4947 TEST(TransferTest, ContextSensitiveReturnOneOfTwoReferences) { 4948 std::string Code = R"( 4949 class S {}; 4950 S &callee(bool b, S &s1_parm, S &s2_parm) { 4951 if (b) 4952 return s1_parm; 4953 else 4954 return s2_parm; 4955 } 4956 void target(bool b) { 4957 S s1; 4958 S s2; 4959 S &return_s1 = s1; 4960 S &return_s2 = s2; 4961 S &return_dont_know = callee(b, s1, s2); 4962 // [[p]] 4963 } 4964 )"; 4965 runDataflow( 4966 Code, 4967 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4968 ASTContext &ASTCtx) { 4969 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4970 4971 const ValueDecl *S1 = findValueDecl(ASTCtx, "s1"); 4972 ASSERT_THAT(S1, NotNull()); 4973 const ValueDecl *S2 = findValueDecl(ASTCtx, "s2"); 4974 ASSERT_THAT(S2, NotNull()); 4975 const ValueDecl *ReturnS1 = findValueDecl(ASTCtx, "return_s1"); 4976 ASSERT_THAT(ReturnS1, NotNull()); 4977 const ValueDecl *ReturnS2 = findValueDecl(ASTCtx, "return_s2"); 4978 ASSERT_THAT(ReturnS2, NotNull()); 4979 const ValueDecl *ReturnDontKnow = 4980 findValueDecl(ASTCtx, "return_dont_know"); 4981 ASSERT_THAT(ReturnDontKnow, NotNull()); 4982 4983 StorageLocation *S1Loc = Env.getStorageLocation(*S1); 4984 StorageLocation *S2Loc = Env.getStorageLocation(*S2); 4985 4986 EXPECT_THAT(Env.getStorageLocation(*ReturnS1), Eq(S1Loc)); 4987 EXPECT_THAT(Env.getStorageLocation(*ReturnS2), Eq(S2Loc)); 4988 4989 // In the case where we don't have a consistent storage location for 4990 // the return value, the framework creates a new storage location, which 4991 // should be different from the storage locations of `s1` and `s2`. 4992 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S1Loc)); 4993 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S2Loc)); 4994 }, 4995 {BuiltinOptions{ContextSensitiveOptions{}}}); 4996 } 4997 4998 TEST(TransferTest, ContextSensitiveDepthZero) { 4999 std::string Code = R"( 5000 bool GiveBool(); 5001 void SetBool(bool &Var) { Var = true; } 5002 5003 void target() { 5004 bool Foo = GiveBool(); 5005 SetBool(Foo); 5006 // [[p]] 5007 } 5008 )"; 5009 runDataflow( 5010 Code, 5011 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5012 ASTContext &ASTCtx) { 5013 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5014 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5015 5016 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5017 ASSERT_THAT(FooDecl, NotNull()); 5018 5019 auto &FooVal = getFormula(*FooDecl, Env); 5020 EXPECT_FALSE(Env.proves(FooVal)); 5021 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5022 }, 5023 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/0}}}); 5024 } 5025 5026 TEST(TransferTest, ContextSensitiveSetTrue) { 5027 std::string Code = R"( 5028 bool GiveBool(); 5029 void SetBool(bool &Var) { Var = true; } 5030 5031 void target() { 5032 bool Foo = GiveBool(); 5033 SetBool(Foo); 5034 // [[p]] 5035 } 5036 )"; 5037 runDataflow( 5038 Code, 5039 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5040 ASTContext &ASTCtx) { 5041 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5042 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5043 5044 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5045 ASSERT_THAT(FooDecl, NotNull()); 5046 5047 auto &FooVal = getFormula(*FooDecl, Env); 5048 EXPECT_TRUE(Env.proves(FooVal)); 5049 }, 5050 {BuiltinOptions{ContextSensitiveOptions{}}}); 5051 } 5052 5053 TEST(TransferTest, ContextSensitiveSetFalse) { 5054 std::string Code = R"( 5055 bool GiveBool(); 5056 void SetBool(bool &Var) { Var = false; } 5057 5058 void target() { 5059 bool Foo = GiveBool(); 5060 SetBool(Foo); 5061 // [[p]] 5062 } 5063 )"; 5064 runDataflow( 5065 Code, 5066 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5067 ASTContext &ASTCtx) { 5068 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5069 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5070 5071 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5072 ASSERT_THAT(FooDecl, NotNull()); 5073 5074 auto &FooVal = getFormula(*FooDecl, Env); 5075 EXPECT_TRUE(Env.proves(Env.arena().makeNot(FooVal))); 5076 }, 5077 {BuiltinOptions{ContextSensitiveOptions{}}}); 5078 } 5079 5080 TEST(TransferTest, ContextSensitiveSetBothTrueAndFalse) { 5081 std::string Code = R"( 5082 bool GiveBool(); 5083 void SetBool(bool &Var, bool Val) { Var = Val; } 5084 5085 void target() { 5086 bool Foo = GiveBool(); 5087 bool Bar = GiveBool(); 5088 SetBool(Foo, true); 5089 SetBool(Bar, false); 5090 // [[p]] 5091 } 5092 )"; 5093 runDataflow( 5094 Code, 5095 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5096 ASTContext &ASTCtx) { 5097 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5098 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5099 auto &A = Env.arena(); 5100 5101 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5102 ASSERT_THAT(FooDecl, NotNull()); 5103 5104 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5105 ASSERT_THAT(BarDecl, NotNull()); 5106 5107 auto &FooVal = getFormula(*FooDecl, Env); 5108 EXPECT_TRUE(Env.proves(FooVal)); 5109 EXPECT_FALSE(Env.proves(A.makeNot(FooVal))); 5110 5111 auto &BarVal = getFormula(*BarDecl, Env); 5112 EXPECT_FALSE(Env.proves(BarVal)); 5113 EXPECT_TRUE(Env.proves(A.makeNot(BarVal))); 5114 }, 5115 {BuiltinOptions{ContextSensitiveOptions{}}}); 5116 } 5117 5118 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthOne) { 5119 std::string Code = R"( 5120 bool GiveBool(); 5121 void SetBool1(bool &Var) { Var = true; } 5122 void SetBool2(bool &Var) { SetBool1(Var); } 5123 5124 void target() { 5125 bool Foo = GiveBool(); 5126 SetBool2(Foo); 5127 // [[p]] 5128 } 5129 )"; 5130 runDataflow( 5131 Code, 5132 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5133 ASTContext &ASTCtx) { 5134 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5135 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5136 5137 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5138 ASSERT_THAT(FooDecl, NotNull()); 5139 5140 auto &FooVal = getFormula(*FooDecl, Env); 5141 EXPECT_FALSE(Env.proves(FooVal)); 5142 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5143 }, 5144 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/1}}}); 5145 } 5146 5147 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthTwo) { 5148 std::string Code = R"( 5149 bool GiveBool(); 5150 void SetBool1(bool &Var) { Var = true; } 5151 void SetBool2(bool &Var) { SetBool1(Var); } 5152 5153 void target() { 5154 bool Foo = GiveBool(); 5155 SetBool2(Foo); 5156 // [[p]] 5157 } 5158 )"; 5159 runDataflow( 5160 Code, 5161 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5162 ASTContext &ASTCtx) { 5163 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5164 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5165 5166 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5167 ASSERT_THAT(FooDecl, NotNull()); 5168 5169 auto &FooVal = getFormula(*FooDecl, Env); 5170 EXPECT_TRUE(Env.proves(FooVal)); 5171 }, 5172 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}}); 5173 } 5174 5175 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthTwo) { 5176 std::string Code = R"( 5177 bool GiveBool(); 5178 void SetBool1(bool &Var) { Var = true; } 5179 void SetBool2(bool &Var) { SetBool1(Var); } 5180 void SetBool3(bool &Var) { SetBool2(Var); } 5181 5182 void target() { 5183 bool Foo = GiveBool(); 5184 SetBool3(Foo); 5185 // [[p]] 5186 } 5187 )"; 5188 runDataflow( 5189 Code, 5190 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5191 ASTContext &ASTCtx) { 5192 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5193 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5194 5195 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5196 ASSERT_THAT(FooDecl, NotNull()); 5197 5198 auto &FooVal = getFormula(*FooDecl, Env); 5199 EXPECT_FALSE(Env.proves(FooVal)); 5200 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5201 }, 5202 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}}); 5203 } 5204 5205 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthThree) { 5206 std::string Code = R"( 5207 bool GiveBool(); 5208 void SetBool1(bool &Var) { Var = true; } 5209 void SetBool2(bool &Var) { SetBool1(Var); } 5210 void SetBool3(bool &Var) { SetBool2(Var); } 5211 5212 void target() { 5213 bool Foo = GiveBool(); 5214 SetBool3(Foo); 5215 // [[p]] 5216 } 5217 )"; 5218 runDataflow( 5219 Code, 5220 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5221 ASTContext &ASTCtx) { 5222 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5223 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5224 5225 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5226 ASSERT_THAT(FooDecl, NotNull()); 5227 5228 auto &FooVal = getFormula(*FooDecl, Env); 5229 EXPECT_TRUE(Env.proves(FooVal)); 5230 }, 5231 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/3}}}); 5232 } 5233 5234 TEST(TransferTest, ContextSensitiveMutualRecursion) { 5235 std::string Code = R"( 5236 bool Pong(bool X, bool Y); 5237 5238 bool Ping(bool X, bool Y) { 5239 if (X) { 5240 return Y; 5241 } else { 5242 return Pong(!X, Y); 5243 } 5244 } 5245 5246 bool Pong(bool X, bool Y) { 5247 if (Y) { 5248 return X; 5249 } else { 5250 return Ping(X, !Y); 5251 } 5252 } 5253 5254 void target() { 5255 bool Foo = Ping(false, false); 5256 // [[p]] 5257 } 5258 )"; 5259 runDataflow( 5260 Code, 5261 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5262 ASTContext &ASTCtx) { 5263 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5264 // The analysis doesn't crash... 5265 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5266 5267 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5268 ASSERT_THAT(FooDecl, NotNull()); 5269 5270 auto &FooVal = getFormula(*FooDecl, Env); 5271 // ... but it also can't prove anything here. 5272 EXPECT_FALSE(Env.proves(FooVal)); 5273 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5274 }, 5275 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/4}}}); 5276 } 5277 5278 TEST(TransferTest, ContextSensitiveSetMultipleLines) { 5279 std::string Code = R"( 5280 void SetBools(bool &Var1, bool &Var2) { 5281 Var1 = true; 5282 Var2 = false; 5283 } 5284 5285 void target() { 5286 bool Foo = false; 5287 bool Bar = true; 5288 SetBools(Foo, Bar); 5289 // [[p]] 5290 } 5291 )"; 5292 runDataflow( 5293 Code, 5294 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5295 ASTContext &ASTCtx) { 5296 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5297 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5298 5299 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5300 ASSERT_THAT(FooDecl, NotNull()); 5301 5302 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5303 ASSERT_THAT(BarDecl, NotNull()); 5304 5305 auto &FooVal = getFormula(*FooDecl, Env); 5306 EXPECT_TRUE(Env.proves(FooVal)); 5307 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal))); 5308 5309 auto &BarVal = getFormula(*BarDecl, Env); 5310 EXPECT_FALSE(Env.proves(BarVal)); 5311 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 5312 }, 5313 {BuiltinOptions{ContextSensitiveOptions{}}}); 5314 } 5315 5316 TEST(TransferTest, ContextSensitiveSetMultipleBlocks) { 5317 std::string Code = R"( 5318 void IfCond(bool Cond, bool &Then, bool &Else) { 5319 if (Cond) { 5320 Then = true; 5321 } else { 5322 Else = true; 5323 } 5324 } 5325 5326 void target() { 5327 bool Foo = false; 5328 bool Bar = false; 5329 bool Baz = false; 5330 IfCond(Foo, Bar, Baz); 5331 // [[p]] 5332 } 5333 )"; 5334 runDataflow( 5335 Code, 5336 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5337 ASTContext &ASTCtx) { 5338 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5339 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5340 5341 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 5342 ASSERT_THAT(BarDecl, NotNull()); 5343 5344 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5345 ASSERT_THAT(BazDecl, NotNull()); 5346 5347 auto &BarVal = getFormula(*BarDecl, Env); 5348 EXPECT_FALSE(Env.proves(BarVal)); 5349 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal))); 5350 5351 auto &BazVal = getFormula(*BazDecl, Env); 5352 EXPECT_TRUE(Env.proves(BazVal)); 5353 EXPECT_FALSE(Env.proves(Env.arena().makeNot(BazVal))); 5354 }, 5355 {BuiltinOptions{ContextSensitiveOptions{}}}); 5356 } 5357 5358 TEST(TransferTest, ContextSensitiveReturnVoid) { 5359 std::string Code = R"( 5360 void Noop() { return; } 5361 5362 void target() { 5363 Noop(); 5364 // [[p]] 5365 } 5366 )"; 5367 runDataflow( 5368 Code, 5369 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5370 ASTContext &ASTCtx) { 5371 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5372 // This just tests that the analysis doesn't crash. 5373 }, 5374 {BuiltinOptions{ContextSensitiveOptions{}}}); 5375 } 5376 5377 TEST(TransferTest, ContextSensitiveReturnTrue) { 5378 std::string Code = R"( 5379 bool GiveBool() { return true; } 5380 5381 void target() { 5382 bool Foo = GiveBool(); 5383 // [[p]] 5384 } 5385 )"; 5386 runDataflow( 5387 Code, 5388 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5389 ASTContext &ASTCtx) { 5390 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5391 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5392 5393 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5394 ASSERT_THAT(FooDecl, NotNull()); 5395 5396 auto &FooVal = getFormula(*FooDecl, Env); 5397 EXPECT_TRUE(Env.proves(FooVal)); 5398 }, 5399 {BuiltinOptions{ContextSensitiveOptions{}}}); 5400 } 5401 5402 TEST(TransferTest, ContextSensitiveReturnFalse) { 5403 std::string Code = R"( 5404 bool GiveBool() { return false; } 5405 5406 void target() { 5407 bool Foo = GiveBool(); 5408 // [[p]] 5409 } 5410 )"; 5411 runDataflow( 5412 Code, 5413 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5414 ASTContext &ASTCtx) { 5415 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5416 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5417 5418 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5419 ASSERT_THAT(FooDecl, NotNull()); 5420 5421 auto &FooVal = getFormula(*FooDecl, Env); 5422 EXPECT_TRUE(Env.proves(Env.arena().makeNot(FooVal))); 5423 }, 5424 {BuiltinOptions{ContextSensitiveOptions{}}}); 5425 } 5426 5427 TEST(TransferTest, ContextSensitiveReturnArg) { 5428 std::string Code = R"( 5429 bool GiveBool(); 5430 bool GiveBack(bool Arg) { return Arg; } 5431 5432 void target() { 5433 bool Foo = GiveBool(); 5434 bool Bar = GiveBack(Foo); 5435 bool Baz = Foo == Bar; 5436 // [[p]] 5437 } 5438 )"; 5439 runDataflow( 5440 Code, 5441 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5442 ASTContext &ASTCtx) { 5443 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5444 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5445 5446 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 5447 ASSERT_THAT(BazDecl, NotNull()); 5448 5449 auto &BazVal = getFormula(*BazDecl, Env); 5450 EXPECT_TRUE(Env.proves(BazVal)); 5451 }, 5452 {BuiltinOptions{ContextSensitiveOptions{}}}); 5453 } 5454 5455 TEST(TransferTest, ContextSensitiveReturnInt) { 5456 std::string Code = R"( 5457 int identity(int x) { return x; } 5458 5459 void target() { 5460 int y = identity(42); 5461 // [[p]] 5462 } 5463 )"; 5464 runDataflow( 5465 Code, 5466 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5467 ASTContext &ASTCtx) { 5468 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5469 // This just tests that the analysis doesn't crash. 5470 }, 5471 {BuiltinOptions{ContextSensitiveOptions{}}}); 5472 } 5473 5474 TEST(TransferTest, ContextSensitiveMethodLiteral) { 5475 std::string Code = R"( 5476 class MyClass { 5477 public: 5478 bool giveBool() { return true; } 5479 }; 5480 5481 void target() { 5482 MyClass MyObj; 5483 bool Foo = MyObj.giveBool(); 5484 // [[p]] 5485 } 5486 )"; 5487 runDataflow( 5488 Code, 5489 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5490 ASTContext &ASTCtx) { 5491 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5492 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5493 5494 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5495 ASSERT_THAT(FooDecl, NotNull()); 5496 5497 auto &FooVal = getFormula(*FooDecl, Env); 5498 EXPECT_TRUE(Env.proves(FooVal)); 5499 }, 5500 {BuiltinOptions{ContextSensitiveOptions{}}}); 5501 } 5502 5503 TEST(TransferTest, ContextSensitiveMethodGetter) { 5504 std::string Code = R"( 5505 class MyClass { 5506 public: 5507 bool getField() { return Field; } 5508 5509 bool Field; 5510 }; 5511 5512 void target() { 5513 MyClass MyObj; 5514 MyObj.Field = true; 5515 bool Foo = MyObj.getField(); 5516 // [[p]] 5517 } 5518 )"; 5519 runDataflow( 5520 Code, 5521 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5522 ASTContext &ASTCtx) { 5523 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5524 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5525 5526 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5527 ASSERT_THAT(FooDecl, NotNull()); 5528 5529 auto &FooVal = getFormula(*FooDecl, Env); 5530 EXPECT_TRUE(Env.proves(FooVal)); 5531 }, 5532 {BuiltinOptions{ContextSensitiveOptions{}}}); 5533 } 5534 5535 TEST(TransferTest, ContextSensitiveMethodSetter) { 5536 std::string Code = R"( 5537 class MyClass { 5538 public: 5539 void setField(bool Val) { Field = Val; } 5540 5541 bool Field; 5542 }; 5543 5544 void target() { 5545 MyClass MyObj; 5546 MyObj.setField(true); 5547 bool Foo = MyObj.Field; 5548 // [[p]] 5549 } 5550 )"; 5551 runDataflow( 5552 Code, 5553 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5554 ASTContext &ASTCtx) { 5555 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5556 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5557 5558 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5559 ASSERT_THAT(FooDecl, NotNull()); 5560 5561 auto &FooVal = getFormula(*FooDecl, Env); 5562 EXPECT_TRUE(Env.proves(FooVal)); 5563 }, 5564 {BuiltinOptions{ContextSensitiveOptions{}}}); 5565 } 5566 5567 TEST(TransferTest, ContextSensitiveMethodGetterAndSetter) { 5568 std::string Code = R"( 5569 class MyClass { 5570 public: 5571 bool getField() { return Field; } 5572 void setField(bool Val) { Field = Val; } 5573 5574 private: 5575 bool Field; 5576 }; 5577 5578 void target() { 5579 MyClass MyObj; 5580 MyObj.setField(true); 5581 bool Foo = MyObj.getField(); 5582 // [[p]] 5583 } 5584 )"; 5585 runDataflow( 5586 Code, 5587 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5588 ASTContext &ASTCtx) { 5589 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5590 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5591 5592 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5593 ASSERT_THAT(FooDecl, NotNull()); 5594 5595 auto &FooVal = getFormula(*FooDecl, Env); 5596 EXPECT_TRUE(Env.proves(FooVal)); 5597 }, 5598 {BuiltinOptions{ContextSensitiveOptions{}}}); 5599 } 5600 5601 5602 TEST(TransferTest, ContextSensitiveMethodTwoLayersVoid) { 5603 std::string Code = R"( 5604 class MyClass { 5605 public: 5606 void Inner() { MyField = true; } 5607 void Outer() { Inner(); } 5608 5609 bool MyField; 5610 }; 5611 5612 void target() { 5613 MyClass MyObj; 5614 MyObj.Outer(); 5615 bool Foo = MyObj.MyField; 5616 // [[p]] 5617 } 5618 )"; 5619 runDataflow( 5620 Code, 5621 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5622 ASTContext &ASTCtx) { 5623 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5624 ; 5625 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5626 5627 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5628 ASSERT_THAT(FooDecl, NotNull()); 5629 5630 auto &FooVal = getFormula(*FooDecl, Env); 5631 EXPECT_TRUE(Env.proves(FooVal)); 5632 }, 5633 {BuiltinOptions{ContextSensitiveOptions{}}}); 5634 } 5635 5636 TEST(TransferTest, ContextSensitiveMethodTwoLayersReturn) { 5637 std::string Code = R"( 5638 class MyClass { 5639 public: 5640 bool Inner() { return MyField; } 5641 bool Outer() { return Inner(); } 5642 5643 bool MyField; 5644 }; 5645 5646 void target() { 5647 MyClass MyObj; 5648 MyObj.MyField = true; 5649 bool Foo = MyObj.Outer(); 5650 // [[p]] 5651 } 5652 )"; 5653 runDataflow( 5654 Code, 5655 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5656 ASTContext &ASTCtx) { 5657 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5658 ; 5659 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5660 5661 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5662 ASSERT_THAT(FooDecl, NotNull()); 5663 5664 auto &FooVal = getFormula(*FooDecl, Env); 5665 EXPECT_TRUE(Env.proves(FooVal)); 5666 }, 5667 {BuiltinOptions{ContextSensitiveOptions{}}}); 5668 } 5669 5670 TEST(TransferTest, ContextSensitiveConstructorBody) { 5671 std::string Code = R"( 5672 class MyClass { 5673 public: 5674 MyClass() { MyField = true; } 5675 5676 bool MyField; 5677 }; 5678 5679 void target() { 5680 MyClass MyObj; 5681 bool Foo = MyObj.MyField; 5682 // [[p]] 5683 } 5684 )"; 5685 runDataflow( 5686 Code, 5687 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5688 ASTContext &ASTCtx) { 5689 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5690 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5691 5692 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5693 ASSERT_THAT(FooDecl, NotNull()); 5694 5695 auto &FooVal = getFormula(*FooDecl, Env); 5696 EXPECT_TRUE(Env.proves(FooVal)); 5697 }, 5698 {BuiltinOptions{ContextSensitiveOptions{}}}); 5699 } 5700 5701 TEST(TransferTest, ContextSensitiveConstructorInitializer) { 5702 std::string Code = R"( 5703 class MyClass { 5704 public: 5705 MyClass() : MyField(true) {} 5706 5707 bool MyField; 5708 }; 5709 5710 void target() { 5711 MyClass MyObj; 5712 bool Foo = MyObj.MyField; 5713 // [[p]] 5714 } 5715 )"; 5716 runDataflow( 5717 Code, 5718 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5719 ASTContext &ASTCtx) { 5720 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5721 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5722 5723 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5724 ASSERT_THAT(FooDecl, NotNull()); 5725 5726 auto &FooVal = getFormula(*FooDecl, Env); 5727 EXPECT_TRUE(Env.proves(FooVal)); 5728 }, 5729 {BuiltinOptions{ContextSensitiveOptions{}}}); 5730 } 5731 5732 TEST(TransferTest, ContextSensitiveConstructorDefault) { 5733 std::string Code = R"( 5734 class MyClass { 5735 public: 5736 MyClass() = default; 5737 5738 bool MyField = true; 5739 }; 5740 5741 void target() { 5742 MyClass MyObj; 5743 bool Foo = MyObj.MyField; 5744 // [[p]] 5745 } 5746 )"; 5747 runDataflow( 5748 Code, 5749 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5750 ASTContext &ASTCtx) { 5751 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5752 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5753 5754 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 5755 ASSERT_THAT(FooDecl, NotNull()); 5756 5757 auto &FooVal = getFormula(*FooDecl, Env); 5758 EXPECT_TRUE(Env.proves(FooVal)); 5759 }, 5760 {BuiltinOptions{ContextSensitiveOptions{}}}); 5761 } 5762 5763 TEST(TransferTest, ContextSensitiveSelfReferentialClass) { 5764 // Test that the `this` pointer seen in the constructor has the same value 5765 // as the address of the variable the object is constructed into. 5766 std::string Code = R"( 5767 class MyClass { 5768 public: 5769 MyClass() : Self(this) {} 5770 MyClass *Self; 5771 }; 5772 5773 void target() { 5774 MyClass MyObj; 5775 MyClass *SelfPtr = MyObj.Self; 5776 // [[p]] 5777 } 5778 )"; 5779 runDataflow( 5780 Code, 5781 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5782 ASTContext &ASTCtx) { 5783 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5784 5785 const ValueDecl *MyObjDecl = findValueDecl(ASTCtx, "MyObj"); 5786 ASSERT_THAT(MyObjDecl, NotNull()); 5787 5788 const ValueDecl *SelfDecl = findValueDecl(ASTCtx, "SelfPtr"); 5789 ASSERT_THAT(SelfDecl, NotNull()); 5790 5791 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5792 auto &SelfVal = *cast<PointerValue>(Env.getValue(*SelfDecl)); 5793 EXPECT_EQ(Env.getStorageLocation(*MyObjDecl), &SelfVal.getPointeeLoc()); 5794 }, 5795 {BuiltinOptions{ContextSensitiveOptions{}}}); 5796 } 5797 5798 TEST(TransferTest, UnnamedBitfieldInitializer) { 5799 std::string Code = R"( 5800 struct B {}; 5801 struct A { 5802 unsigned a; 5803 unsigned : 4; 5804 unsigned c; 5805 B b; 5806 }; 5807 void target() { 5808 A a = {}; 5809 A test = a; 5810 (void)test.c; 5811 } 5812 )"; 5813 runDataflow( 5814 Code, 5815 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5816 ASTContext &ASTCtx) { 5817 // This doesn't need a body because this test was crashing the framework 5818 // before handling correctly Unnamed bitfields in `InitListExpr`. 5819 }); 5820 } 5821 5822 // Repro for a crash that used to occur with chained short-circuiting logical 5823 // operators. 5824 TEST(TransferTest, ChainedLogicalOps) { 5825 std::string Code = R"( 5826 bool target() { 5827 bool b = true || false || false || false; 5828 // [[p]] 5829 return b; 5830 } 5831 )"; 5832 runDataflow( 5833 Code, 5834 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5835 ASTContext &ASTCtx) { 5836 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5837 auto &B = getValueForDecl<BoolValue>(ASTCtx, Env, "b").formula(); 5838 EXPECT_TRUE(Env.proves(B)); 5839 }); 5840 } 5841 5842 // Repro for a crash that used to occur when we call a `noreturn` function 5843 // within one of the operands of a `&&` or `||` operator. 5844 TEST(TransferTest, NoReturnFunctionInsideShortCircuitedBooleanOp) { 5845 std::string Code = R"( 5846 __attribute__((noreturn)) int doesnt_return(); 5847 bool some_condition(); 5848 void target(bool b1, bool b2) { 5849 // Neither of these should crash. In addition, if we don't terminate the 5850 // program, we know that the operators need to trigger the short-circuit 5851 // logic, so `NoreturnOnRhsOfAnd` will be false and `NoreturnOnRhsOfOr` 5852 // will be true. 5853 bool NoreturnOnRhsOfAnd = b1 && doesnt_return() > 0; 5854 bool NoreturnOnRhsOfOr = b2 || doesnt_return() > 0; 5855 5856 // Calling a `noreturn` function on the LHS of an `&&` or `||` makes the 5857 // entire expression unreachable. So we know that in both of the following 5858 // cases, if `target()` terminates, the `else` branch was taken. 5859 bool NoreturnOnLhsMakesAndUnreachable = false; 5860 if (some_condition()) 5861 doesnt_return() > 0 && some_condition(); 5862 else 5863 NoreturnOnLhsMakesAndUnreachable = true; 5864 5865 bool NoreturnOnLhsMakesOrUnreachable = false; 5866 if (some_condition()) 5867 doesnt_return() > 0 || some_condition(); 5868 else 5869 NoreturnOnLhsMakesOrUnreachable = true; 5870 5871 // [[p]] 5872 } 5873 )"; 5874 runDataflow( 5875 Code, 5876 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5877 ASTContext &ASTCtx) { 5878 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 5879 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5880 auto &A = Env.arena(); 5881 5882 // Check that [[p]] is reachable with a non-false flow condition. 5883 EXPECT_FALSE(Env.proves(A.makeLiteral(false))); 5884 5885 auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, "b1").formula(); 5886 EXPECT_TRUE(Env.proves(A.makeNot(B1))); 5887 5888 auto &NoreturnOnRhsOfAnd = 5889 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfAnd").formula(); 5890 EXPECT_TRUE(Env.proves(A.makeNot(NoreturnOnRhsOfAnd))); 5891 5892 auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, "b2").formula(); 5893 EXPECT_TRUE(Env.proves(B2)); 5894 5895 auto &NoreturnOnRhsOfOr = 5896 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfOr") 5897 .formula(); 5898 EXPECT_TRUE(Env.proves(NoreturnOnRhsOfOr)); 5899 5900 auto &NoreturnOnLhsMakesAndUnreachable = getValueForDecl<BoolValue>( 5901 ASTCtx, Env, "NoreturnOnLhsMakesAndUnreachable").formula(); 5902 EXPECT_TRUE(Env.proves(NoreturnOnLhsMakesAndUnreachable)); 5903 5904 auto &NoreturnOnLhsMakesOrUnreachable = getValueForDecl<BoolValue>( 5905 ASTCtx, Env, "NoreturnOnLhsMakesOrUnreachable").formula(); 5906 EXPECT_TRUE(Env.proves(NoreturnOnLhsMakesOrUnreachable)); 5907 }); 5908 } 5909 5910 TEST(TransferTest, NewExpressions) { 5911 std::string Code = R"( 5912 void target() { 5913 int *p = new int(42); 5914 // [[after_new]] 5915 } 5916 )"; 5917 runDataflow( 5918 Code, 5919 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5920 ASTContext &ASTCtx) { 5921 const Environment &Env = 5922 getEnvironmentAtAnnotation(Results, "after_new"); 5923 5924 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p"); 5925 5926 EXPECT_THAT(Env.getValue(P.getPointeeLoc()), NotNull()); 5927 }); 5928 } 5929 5930 TEST(TransferTest, NewExpressions_Structs) { 5931 std::string Code = R"( 5932 struct Inner { 5933 int InnerField; 5934 }; 5935 5936 struct Outer { 5937 Inner OuterField; 5938 }; 5939 5940 void target() { 5941 Outer *p = new Outer; 5942 // Access the fields to make sure the analysis actually generates children 5943 // for them in the `RecordStorageLocation` and `RecordValue`. 5944 p->OuterField.InnerField; 5945 // [[after_new]] 5946 } 5947 )"; 5948 runDataflow( 5949 Code, 5950 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5951 ASTContext &ASTCtx) { 5952 const Environment &Env = 5953 getEnvironmentAtAnnotation(Results, "after_new"); 5954 5955 const ValueDecl *OuterField = findValueDecl(ASTCtx, "OuterField"); 5956 const ValueDecl *InnerField = findValueDecl(ASTCtx, "InnerField"); 5957 5958 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p"); 5959 5960 auto &OuterLoc = cast<RecordStorageLocation>(P.getPointeeLoc()); 5961 auto &OuterFieldLoc = 5962 *cast<RecordStorageLocation>(OuterLoc.getChild(*OuterField)); 5963 auto &InnerFieldLoc = *OuterFieldLoc.getChild(*InnerField); 5964 5965 // Values for the struct and all fields exist after the new. 5966 EXPECT_THAT(Env.getValue(OuterLoc), NotNull()); 5967 EXPECT_THAT(Env.getValue(OuterFieldLoc), NotNull()); 5968 EXPECT_THAT(Env.getValue(InnerFieldLoc), NotNull()); 5969 }); 5970 } 5971 5972 TEST(TransferTest, FunctionToPointerDecayHasValue) { 5973 std::string Code = R"( 5974 struct A { static void static_member_func(); }; 5975 void target() { 5976 // To check that we're treating function-to-pointer decay correctly, 5977 // create two pointers, then verify they refer to the same storage 5978 // location. 5979 // We need to do the test this way because even if an initializer (in this 5980 // case, the function-to-pointer decay) does not create a value, we still 5981 // create a value for the variable. 5982 void (*non_member_p1)() = target; 5983 void (*non_member_p2)() = target; 5984 5985 // Do the same thing but for a static member function. 5986 void (*member_p1)() = A::static_member_func; 5987 void (*member_p2)() = A::static_member_func; 5988 // [[p]] 5989 } 5990 )"; 5991 runDataflow( 5992 Code, 5993 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 5994 ASTContext &ASTCtx) { 5995 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 5996 5997 auto &NonMemberP1 = 5998 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p1"); 5999 auto &NonMemberP2 = 6000 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p2"); 6001 EXPECT_EQ(&NonMemberP1.getPointeeLoc(), &NonMemberP2.getPointeeLoc()); 6002 6003 auto &MemberP1 = 6004 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p1"); 6005 auto &MemberP2 = 6006 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p2"); 6007 EXPECT_EQ(&MemberP1.getPointeeLoc(), &MemberP2.getPointeeLoc()); 6008 }); 6009 } 6010 6011 // Check that a builtin function is not associated with a value. (It's only 6012 // possible to call builtin functions directly, not take their address.) 6013 TEST(TransferTest, BuiltinFunctionModeled) { 6014 std::string Code = R"( 6015 void target() { 6016 __builtin_expect(0, 0); 6017 // [[p]] 6018 } 6019 )"; 6020 runDataflow( 6021 Code, 6022 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6023 ASTContext &ASTCtx) { 6024 using ast_matchers::selectFirst; 6025 using ast_matchers::match; 6026 using ast_matchers::traverse; 6027 using ast_matchers::implicitCastExpr; 6028 using ast_matchers::hasCastKind; 6029 6030 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6031 6032 auto *ImplicitCast = selectFirst<ImplicitCastExpr>( 6033 "implicit_cast", 6034 match(traverse(TK_AsIs, 6035 implicitCastExpr(hasCastKind(CK_BuiltinFnToFnPtr)) 6036 .bind("implicit_cast")), 6037 ASTCtx)); 6038 6039 ASSERT_THAT(ImplicitCast, NotNull()); 6040 EXPECT_THAT(Env.getValue(*ImplicitCast), IsNull()); 6041 }); 6042 } 6043 6044 // Check that a callee of a member operator call is modeled as a `PointerValue`. 6045 // Member operator calls are unusual in that their callee is a pointer that 6046 // stems from a `FunctionToPointerDecay`. In calls to non-operator non-static 6047 // member functions, the callee is a `MemberExpr` (which does not have pointer 6048 // type). 6049 // We want to make sure that we produce a pointer value for the callee in this 6050 // specific scenario and that its storage location is durable (for convergence). 6051 TEST(TransferTest, MemberOperatorCallModelsPointerForCallee) { 6052 std::string Code = R"( 6053 struct S { 6054 bool operator!=(S s); 6055 }; 6056 void target() { 6057 S s; 6058 (void)(s != s); 6059 (void)(s != s); 6060 // [[p]] 6061 } 6062 )"; 6063 runDataflow( 6064 Code, 6065 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6066 ASTContext &ASTCtx) { 6067 using ast_matchers::selectFirst; 6068 using ast_matchers::match; 6069 using ast_matchers::traverse; 6070 using ast_matchers::cxxOperatorCallExpr; 6071 6072 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6073 6074 auto Matches = match( 6075 traverse(TK_AsIs, cxxOperatorCallExpr().bind("call")), ASTCtx); 6076 6077 ASSERT_EQ(Matches.size(), 2UL); 6078 6079 auto *Call1 = Matches[0].getNodeAs<CXXOperatorCallExpr>("call"); 6080 auto *Call2 = Matches[1].getNodeAs<CXXOperatorCallExpr>("call"); 6081 6082 ASSERT_THAT(Call1, NotNull()); 6083 ASSERT_THAT(Call2, NotNull()); 6084 6085 EXPECT_EQ(cast<ImplicitCastExpr>(Call1->getCallee())->getCastKind(), 6086 CK_FunctionToPointerDecay); 6087 EXPECT_EQ(cast<ImplicitCastExpr>(Call2->getCallee())->getCastKind(), 6088 CK_FunctionToPointerDecay); 6089 6090 auto *Ptr1 = cast<PointerValue>(Env.getValue(*Call1->getCallee())); 6091 auto *Ptr2 = cast<PointerValue>(Env.getValue(*Call2->getCallee())); 6092 6093 ASSERT_EQ(&Ptr1->getPointeeLoc(), &Ptr2->getPointeeLoc()); 6094 }); 6095 } 6096 6097 // Check that fields of anonymous records are modeled. 6098 TEST(TransferTest, AnonymousStruct) { 6099 std::string Code = R"( 6100 struct S { 6101 struct { 6102 bool b; 6103 }; 6104 }; 6105 void target() { 6106 S s; 6107 s.b = true; 6108 // [[p]] 6109 } 6110 )"; 6111 runDataflow( 6112 Code, 6113 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6114 ASTContext &ASTCtx) { 6115 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6116 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s"); 6117 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b"); 6118 const IndirectFieldDecl *IndirectField = 6119 findIndirectFieldDecl(ASTCtx, "b"); 6120 6121 auto *S = cast<RecordStorageLocation>(Env.getStorageLocation(*SDecl)); 6122 auto &AnonStruct = *cast<RecordStorageLocation>( 6123 S->getChild(*cast<ValueDecl>(IndirectField->chain().front()))); 6124 6125 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env)); 6126 ASSERT_TRUE(Env.proves(B->formula())); 6127 }); 6128 } 6129 6130 TEST(TransferTest, AnonymousStructWithInitializer) { 6131 std::string Code = R"( 6132 struct target { 6133 target() { 6134 (void)0; 6135 // [[p]] 6136 } 6137 struct { 6138 bool b = true; 6139 }; 6140 }; 6141 )"; 6142 runDataflow( 6143 Code, 6144 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6145 ASTContext &ASTCtx) { 6146 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6147 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b"); 6148 const IndirectFieldDecl *IndirectField = 6149 findIndirectFieldDecl(ASTCtx, "b"); 6150 6151 auto *ThisLoc = 6152 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation()); 6153 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild( 6154 *cast<ValueDecl>(IndirectField->chain().front()))); 6155 6156 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env)); 6157 ASSERT_TRUE(Env.proves(B->formula())); 6158 }); 6159 } 6160 6161 TEST(TransferTest, AnonymousStructWithReferenceField) { 6162 std::string Code = R"( 6163 int global_i = 0; 6164 struct target { 6165 target() { 6166 (void)0; 6167 // [[p]] 6168 } 6169 struct { 6170 int &i = global_i; 6171 }; 6172 }; 6173 )"; 6174 runDataflow( 6175 Code, 6176 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6177 ASTContext &ASTCtx) { 6178 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6179 const ValueDecl *GlobalIDecl = findValueDecl(ASTCtx, "global_i"); 6180 const ValueDecl *IDecl = findValueDecl(ASTCtx, "i"); 6181 const IndirectFieldDecl *IndirectField = 6182 findIndirectFieldDecl(ASTCtx, "i"); 6183 6184 auto *ThisLoc = 6185 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation()); 6186 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild( 6187 *cast<ValueDecl>(IndirectField->chain().front()))); 6188 6189 ASSERT_EQ(AnonStruct.getChild(*IDecl), 6190 Env.getStorageLocation(*GlobalIDecl)); 6191 }); 6192 } 6193 6194 TEST(TransferTest, EvaluateBlockWithUnreachablePreds) { 6195 // This is a crash repro. 6196 // `false` block may not have been processed when we try to evaluate the `||` 6197 // after visiting `true`, because it is not necessary (and therefore the edge 6198 // is marked unreachable). Trying to get the analysis state via 6199 // `getEnvironment` for the subexpression still should not crash. 6200 std::string Code = R"( 6201 int target(int i) { 6202 if ((i < 0 && true) || false) { 6203 return 0; 6204 } 6205 return 0; 6206 } 6207 )"; 6208 runDataflow( 6209 Code, 6210 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6211 ASTContext &ASTCtx) {}); 6212 } 6213 6214 TEST(TransferTest, LambdaCaptureByCopy) { 6215 std::string Code = R"( 6216 void target(int Foo, int Bar) { 6217 [Foo]() { 6218 (void)0; 6219 // [[p]] 6220 }(); 6221 } 6222 )"; 6223 runDataflowOnLambda( 6224 Code, 6225 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6226 ASTContext &ASTCtx) { 6227 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6228 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6229 6230 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6231 ASSERT_THAT(FooDecl, NotNull()); 6232 6233 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6234 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6235 6236 const Value *FooVal = Env.getValue(*FooLoc); 6237 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6238 6239 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6240 ASSERT_THAT(BarDecl, NotNull()); 6241 6242 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6243 EXPECT_THAT(BarLoc, IsNull()); 6244 }); 6245 } 6246 6247 TEST(TransferTest, LambdaCaptureByReference) { 6248 std::string Code = R"( 6249 void target(int Foo, int Bar) { 6250 [&Foo]() { 6251 (void)0; 6252 // [[p]] 6253 }(); 6254 } 6255 )"; 6256 runDataflowOnLambda( 6257 Code, 6258 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6259 ASTContext &ASTCtx) { 6260 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6261 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6262 6263 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6264 ASSERT_THAT(FooDecl, NotNull()); 6265 6266 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6267 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6268 6269 const Value *FooVal = Env.getValue(*FooLoc); 6270 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6271 6272 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6273 ASSERT_THAT(BarDecl, NotNull()); 6274 6275 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6276 EXPECT_THAT(BarLoc, IsNull()); 6277 }); 6278 } 6279 6280 TEST(TransferTest, LambdaCaptureWithInitializer) { 6281 std::string Code = R"( 6282 void target(int Bar) { 6283 [Foo=Bar]() { 6284 (void)0; 6285 // [[p]] 6286 }(); 6287 } 6288 )"; 6289 runDataflowOnLambda( 6290 Code, 6291 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6292 ASTContext &ASTCtx) { 6293 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6294 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6295 6296 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6297 ASSERT_THAT(FooDecl, NotNull()); 6298 6299 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6300 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6301 6302 const Value *FooVal = Env.getValue(*FooLoc); 6303 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6304 6305 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6306 ASSERT_THAT(BarDecl, NotNull()); 6307 6308 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6309 EXPECT_THAT(BarLoc, IsNull()); 6310 }); 6311 } 6312 6313 TEST(TransferTest, LambdaCaptureByCopyImplicit) { 6314 std::string Code = R"( 6315 void target(int Foo, int Bar) { 6316 [=]() { 6317 Foo; 6318 // [[p]] 6319 }(); 6320 } 6321 )"; 6322 runDataflowOnLambda( 6323 Code, 6324 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6325 ASTContext &ASTCtx) { 6326 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6327 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6328 6329 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6330 ASSERT_THAT(FooDecl, NotNull()); 6331 6332 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6333 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6334 6335 const Value *FooVal = Env.getValue(*FooLoc); 6336 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6337 6338 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6339 ASSERT_THAT(BarDecl, NotNull()); 6340 6341 // There is no storage location for `Bar` because it isn't used in the 6342 // body of the lambda. 6343 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6344 EXPECT_THAT(BarLoc, IsNull()); 6345 }); 6346 } 6347 6348 TEST(TransferTest, LambdaCaptureByReferenceImplicit) { 6349 std::string Code = R"( 6350 void target(int Foo, int Bar) { 6351 [&]() { 6352 Foo; 6353 // [[p]] 6354 }(); 6355 } 6356 )"; 6357 runDataflowOnLambda( 6358 Code, 6359 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6360 ASTContext &ASTCtx) { 6361 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6362 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6363 6364 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6365 ASSERT_THAT(FooDecl, NotNull()); 6366 6367 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl); 6368 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6369 6370 const Value *FooVal = Env.getValue(*FooLoc); 6371 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6372 6373 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 6374 ASSERT_THAT(BarDecl, NotNull()); 6375 6376 // There is no storage location for `Bar` because it isn't used in the 6377 // body of the lambda. 6378 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl); 6379 EXPECT_THAT(BarLoc, IsNull()); 6380 }); 6381 } 6382 6383 TEST(TransferTest, LambdaCaptureThis) { 6384 std::string Code = R"( 6385 struct Bar { 6386 int Foo; 6387 6388 void target() { 6389 [this]() { 6390 Foo; 6391 // [[p]] 6392 }(); 6393 } 6394 }; 6395 )"; 6396 runDataflowOnLambda( 6397 Code, 6398 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6399 ASTContext &ASTCtx) { 6400 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 6401 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6402 6403 const RecordStorageLocation *ThisPointeeLoc = 6404 Env.getThisPointeeStorageLocation(); 6405 ASSERT_THAT(ThisPointeeLoc, NotNull()); 6406 6407 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 6408 ASSERT_THAT(FooDecl, NotNull()); 6409 6410 const StorageLocation *FooLoc = ThisPointeeLoc->getChild(*FooDecl); 6411 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 6412 6413 const Value *FooVal = Env.getValue(*FooLoc); 6414 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 6415 }); 6416 } 6417 6418 TEST(TransferTest, DifferentReferenceLocInJoin) { 6419 // This test triggers a case where the storage location for a reference-type 6420 // variable is different for two states being joined. We used to believe this 6421 // could not happen and therefore had an assertion disallowing this; this test 6422 // exists to demonstrate that we can handle this condition without a failing 6423 // assertion. See also the discussion here: 6424 // https://discourse.llvm.org/t/70086/6 6425 std::string Code = R"( 6426 namespace std { 6427 template <class T> struct initializer_list { 6428 const T* begin(); 6429 const T* end(); 6430 }; 6431 } 6432 6433 void target(char* p, char* end) { 6434 while (p != end) { 6435 if (*p == ' ') { 6436 p++; 6437 continue; 6438 } 6439 6440 auto && range = {1, 2}; 6441 for (auto b = range.begin(), e = range.end(); b != e; ++b) { 6442 } 6443 (void)0; 6444 // [[p]] 6445 } 6446 } 6447 )"; 6448 runDataflow( 6449 Code, 6450 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 6451 ASTContext &ASTCtx) { 6452 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 6453 6454 // Joining environments with different storage locations for the same 6455 // declaration results in the declaration being removed from the joined 6456 // environment. 6457 const ValueDecl *VD = findValueDecl(ASTCtx, "range"); 6458 ASSERT_EQ(Env.getStorageLocation(*VD), nullptr); 6459 }); 6460 } 6461 6462 } // namespace 6463