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