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