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