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/DataflowEnvironment.h" 14 #include "clang/Analysis/FlowSensitive/NoopAnalysis.h" 15 #include "clang/Analysis/FlowSensitive/StorageLocation.h" 16 #include "clang/Analysis/FlowSensitive/Value.h" 17 #include "clang/Basic/LangStandard.h" 18 #include "llvm/ADT/ArrayRef.h" 19 #include "llvm/ADT/StringRef.h" 20 #include "llvm/Support/Casting.h" 21 #include "llvm/Testing/Support/Error.h" 22 #include "gmock/gmock.h" 23 #include "gtest/gtest.h" 24 #include <string> 25 #include <utility> 26 27 namespace { 28 29 using namespace clang; 30 using namespace dataflow; 31 using namespace test; 32 using ::testing::IsNull; 33 using ::testing::NotNull; 34 using ::testing::UnorderedElementsAre; 35 36 template <typename Matcher> 37 void runDataflow(llvm::StringRef Code, Matcher Match, 38 DataflowAnalysisOptions Options, 39 LangStandard::Kind Std = LangStandard::lang_cxx17, 40 llvm::StringRef TargetFun = "target") { 41 using ast_matchers::hasName; 42 ASSERT_THAT_ERROR( 43 checkDataflow<NoopAnalysis>( 44 AnalysisInputs<NoopAnalysis>(Code, hasName(TargetFun), 45 [Options](ASTContext &C, Environment &) { 46 return NoopAnalysis(C, Options); 47 }) 48 .withASTBuildArgs( 49 {"-fsyntax-only", "-fno-delayed-template-parsing", 50 "-std=" + 51 std::string(LangStandard::getLangStandardForKind(Std) 52 .getName())}), 53 /*VerifyResults=*/ 54 [&Match](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> 55 &Results, 56 const AnalysisOutputs &AO) { Match(Results, AO.ASTCtx); }), 57 llvm::Succeeded()); 58 } 59 60 template <typename Matcher> 61 void runDataflow(llvm::StringRef Code, Matcher Match, 62 LangStandard::Kind Std = LangStandard::lang_cxx17, 63 bool ApplyBuiltinTransfer = true, 64 llvm::StringRef TargetFun = "target") { 65 runDataflow(Code, std::move(Match), 66 {ApplyBuiltinTransfer ? TransferOptions{} 67 : llvm::Optional<TransferOptions>()}, 68 Std, TargetFun); 69 } 70 71 TEST(TransferTest, IntVarDeclNotTrackedWhenTransferDisabled) { 72 std::string Code = R"( 73 void target() { 74 int Foo; 75 // [[p]] 76 } 77 )"; 78 runDataflow( 79 Code, 80 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 81 ASTContext &ASTCtx) { 82 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 83 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 84 85 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 86 ASSERT_THAT(FooDecl, NotNull()); 87 88 EXPECT_EQ(Env.getStorageLocation(*FooDecl, SkipPast::None), nullptr); 89 }, 90 LangStandard::lang_cxx17, 91 /*ApplyBuiltinTransfer=*/false); 92 } 93 94 TEST(TransferTest, BoolVarDecl) { 95 std::string Code = R"( 96 void target() { 97 bool Foo; 98 // [[p]] 99 } 100 )"; 101 runDataflow( 102 Code, 103 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 104 ASTContext &ASTCtx) { 105 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 106 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 107 108 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 109 ASSERT_THAT(FooDecl, NotNull()); 110 111 const StorageLocation *FooLoc = 112 Env.getStorageLocation(*FooDecl, SkipPast::None); 113 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 114 115 const Value *FooVal = Env.getValue(*FooLoc); 116 EXPECT_TRUE(isa_and_nonnull<BoolValue>(FooVal)); 117 }); 118 } 119 120 TEST(TransferTest, IntVarDecl) { 121 std::string Code = R"( 122 void target() { 123 int Foo; 124 // [[p]] 125 } 126 )"; 127 runDataflow( 128 Code, 129 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 130 ASTContext &ASTCtx) { 131 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 132 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 133 134 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 135 ASSERT_THAT(FooDecl, NotNull()); 136 137 const StorageLocation *FooLoc = 138 Env.getStorageLocation(*FooDecl, SkipPast::None); 139 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 140 141 const Value *FooVal = Env.getValue(*FooLoc); 142 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 143 }); 144 } 145 146 TEST(TransferTest, StructVarDecl) { 147 std::string Code = R"( 148 struct A { 149 int Bar; 150 }; 151 152 void target() { 153 A Foo; 154 // [[p]] 155 } 156 )"; 157 runDataflow( 158 Code, 159 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 160 ASTContext &ASTCtx) { 161 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 162 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 163 164 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 165 ASSERT_THAT(FooDecl, NotNull()); 166 167 ASSERT_TRUE(FooDecl->getType()->isStructureType()); 168 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 169 170 FieldDecl *BarDecl = nullptr; 171 for (FieldDecl *Field : FooFields) { 172 if (Field->getNameAsString() == "Bar") { 173 BarDecl = Field; 174 } else { 175 FAIL() << "Unexpected field: " << Field->getNameAsString(); 176 } 177 } 178 ASSERT_THAT(BarDecl, NotNull()); 179 180 const auto *FooLoc = cast<AggregateStorageLocation>( 181 Env.getStorageLocation(*FooDecl, SkipPast::None)); 182 const auto *BarLoc = 183 cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl)); 184 185 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 186 const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl)); 187 EXPECT_EQ(Env.getValue(*BarLoc), BarVal); 188 }); 189 } 190 191 TEST(TransferTest, StructVarDeclWithInit) { 192 std::string Code = R"( 193 struct A { 194 int Bar; 195 }; 196 197 A Gen(); 198 199 void target() { 200 A Foo = Gen(); 201 // [[p]] 202 } 203 )"; 204 runDataflow( 205 Code, 206 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 207 ASTContext &ASTCtx) { 208 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 209 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 210 211 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 212 ASSERT_THAT(FooDecl, NotNull()); 213 214 ASSERT_TRUE(FooDecl->getType()->isStructureType()); 215 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 216 217 FieldDecl *BarDecl = nullptr; 218 for (FieldDecl *Field : FooFields) { 219 if (Field->getNameAsString() == "Bar") { 220 BarDecl = Field; 221 } else { 222 FAIL() << "Unexpected field: " << Field->getNameAsString(); 223 } 224 } 225 ASSERT_THAT(BarDecl, NotNull()); 226 227 const auto *FooLoc = cast<AggregateStorageLocation>( 228 Env.getStorageLocation(*FooDecl, SkipPast::None)); 229 const auto *BarLoc = 230 cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl)); 231 232 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 233 const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl)); 234 EXPECT_EQ(Env.getValue(*BarLoc), BarVal); 235 }); 236 } 237 238 TEST(TransferTest, ClassVarDecl) { 239 std::string Code = R"( 240 class A { 241 int Bar; 242 }; 243 244 void target() { 245 A Foo; 246 // [[p]] 247 } 248 )"; 249 runDataflow( 250 Code, 251 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 252 ASTContext &ASTCtx) { 253 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 254 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 255 256 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 257 ASSERT_THAT(FooDecl, NotNull()); 258 259 ASSERT_TRUE(FooDecl->getType()->isClassType()); 260 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 261 262 FieldDecl *BarDecl = nullptr; 263 for (FieldDecl *Field : FooFields) { 264 if (Field->getNameAsString() == "Bar") { 265 BarDecl = Field; 266 } else { 267 FAIL() << "Unexpected field: " << Field->getNameAsString(); 268 } 269 } 270 ASSERT_THAT(BarDecl, NotNull()); 271 272 const auto *FooLoc = cast<AggregateStorageLocation>( 273 Env.getStorageLocation(*FooDecl, SkipPast::None)); 274 const auto *BarLoc = 275 cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl)); 276 277 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 278 const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl)); 279 EXPECT_EQ(Env.getValue(*BarLoc), BarVal); 280 }); 281 } 282 283 TEST(TransferTest, ReferenceVarDecl) { 284 std::string Code = R"( 285 struct A {}; 286 287 A &getA(); 288 289 void target() { 290 A &Foo = getA(); 291 // [[p]] 292 } 293 )"; 294 runDataflow( 295 Code, 296 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 297 ASTContext &ASTCtx) { 298 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 299 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 300 301 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 302 ASSERT_THAT(FooDecl, NotNull()); 303 304 const StorageLocation *FooLoc = 305 Env.getStorageLocation(*FooDecl, SkipPast::None); 306 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 307 308 const ReferenceValue *FooVal = 309 cast<ReferenceValue>(Env.getValue(*FooLoc)); 310 const StorageLocation &FooReferentLoc = FooVal->getReferentLoc(); 311 EXPECT_TRUE(isa<AggregateStorageLocation>(&FooReferentLoc)); 312 313 const Value *FooReferentVal = Env.getValue(FooReferentLoc); 314 EXPECT_TRUE(isa_and_nonnull<StructValue>(FooReferentVal)); 315 }); 316 } 317 318 TEST(TransferTest, SelfReferentialReferenceVarDecl) { 319 std::string Code = R"( 320 struct A; 321 322 struct B {}; 323 324 struct C { 325 A &FooRef; 326 A *FooPtr; 327 B &BazRef; 328 B *BazPtr; 329 }; 330 331 struct A { 332 C &Bar; 333 }; 334 335 A &getA(); 336 337 void target() { 338 A &Foo = getA(); 339 // [[p]] 340 } 341 )"; 342 runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> 343 &Results, 344 ASTContext &ASTCtx) { 345 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 346 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 347 348 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 349 ASSERT_THAT(FooDecl, NotNull()); 350 351 ASSERT_TRUE(FooDecl->getType()->isReferenceType()); 352 ASSERT_TRUE(FooDecl->getType().getNonReferenceType()->isStructureType()); 353 const auto FooFields = 354 FooDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields(); 355 356 FieldDecl *BarDecl = nullptr; 357 for (FieldDecl *Field : FooFields) { 358 if (Field->getNameAsString() == "Bar") { 359 BarDecl = Field; 360 } else { 361 FAIL() << "Unexpected field: " << Field->getNameAsString(); 362 } 363 } 364 ASSERT_THAT(BarDecl, NotNull()); 365 366 ASSERT_TRUE(BarDecl->getType()->isReferenceType()); 367 ASSERT_TRUE(BarDecl->getType().getNonReferenceType()->isStructureType()); 368 const auto BarFields = 369 BarDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields(); 370 371 FieldDecl *FooRefDecl = nullptr; 372 FieldDecl *FooPtrDecl = nullptr; 373 FieldDecl *BazRefDecl = nullptr; 374 FieldDecl *BazPtrDecl = nullptr; 375 for (FieldDecl *Field : BarFields) { 376 if (Field->getNameAsString() == "FooRef") { 377 FooRefDecl = Field; 378 } else if (Field->getNameAsString() == "FooPtr") { 379 FooPtrDecl = Field; 380 } else if (Field->getNameAsString() == "BazRef") { 381 BazRefDecl = Field; 382 } else if (Field->getNameAsString() == "BazPtr") { 383 BazPtrDecl = Field; 384 } else { 385 FAIL() << "Unexpected field: " << Field->getNameAsString(); 386 } 387 } 388 ASSERT_THAT(FooRefDecl, NotNull()); 389 ASSERT_THAT(FooPtrDecl, NotNull()); 390 ASSERT_THAT(BazRefDecl, NotNull()); 391 ASSERT_THAT(BazPtrDecl, NotNull()); 392 393 const auto *FooLoc = cast<ScalarStorageLocation>( 394 Env.getStorageLocation(*FooDecl, SkipPast::None)); 395 const auto *FooVal = cast<ReferenceValue>(Env.getValue(*FooLoc)); 396 const auto *FooReferentVal = 397 cast<StructValue>(Env.getValue(FooVal->getReferentLoc())); 398 399 const auto *BarVal = 400 cast<ReferenceValue>(FooReferentVal->getChild(*BarDecl)); 401 const auto *BarReferentVal = 402 cast<StructValue>(Env.getValue(BarVal->getReferentLoc())); 403 404 const auto *FooRefVal = 405 cast<ReferenceValue>(BarReferentVal->getChild(*FooRefDecl)); 406 const StorageLocation &FooReferentLoc = FooRefVal->getReferentLoc(); 407 EXPECT_THAT(Env.getValue(FooReferentLoc), IsNull()); 408 409 const auto *FooPtrVal = 410 cast<PointerValue>(BarReferentVal->getChild(*FooPtrDecl)); 411 const StorageLocation &FooPtrPointeeLoc = FooPtrVal->getPointeeLoc(); 412 EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull()); 413 414 const auto *BazRefVal = 415 cast<ReferenceValue>(BarReferentVal->getChild(*BazRefDecl)); 416 const StorageLocation &BazReferentLoc = BazRefVal->getReferentLoc(); 417 EXPECT_THAT(Env.getValue(BazReferentLoc), NotNull()); 418 419 const auto *BazPtrVal = 420 cast<PointerValue>(BarReferentVal->getChild(*BazPtrDecl)); 421 const StorageLocation &BazPtrPointeeLoc = BazPtrVal->getPointeeLoc(); 422 EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull()); 423 }); 424 } 425 426 TEST(TransferTest, PointerVarDecl) { 427 std::string Code = R"( 428 struct A {}; 429 430 A *getA(); 431 432 void target() { 433 A *Foo = getA(); 434 // [[p]] 435 } 436 )"; 437 runDataflow( 438 Code, 439 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 440 ASTContext &ASTCtx) { 441 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 442 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 443 444 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 445 ASSERT_THAT(FooDecl, NotNull()); 446 447 const StorageLocation *FooLoc = 448 Env.getStorageLocation(*FooDecl, SkipPast::None); 449 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 450 451 const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc)); 452 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc(); 453 EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc)); 454 455 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc); 456 EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal)); 457 }); 458 } 459 460 TEST(TransferTest, SelfReferentialPointerVarDecl) { 461 std::string Code = R"( 462 struct A; 463 464 struct B {}; 465 466 struct C { 467 A &FooRef; 468 A *FooPtr; 469 B &BazRef; 470 B *BazPtr; 471 }; 472 473 struct A { 474 C *Bar; 475 }; 476 477 A *getA(); 478 479 void target() { 480 A *Foo = getA(); 481 // [[p]] 482 } 483 )"; 484 runDataflow( 485 Code, 486 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 487 ASTContext &ASTCtx) { 488 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 489 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 490 491 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 492 ASSERT_THAT(FooDecl, NotNull()); 493 494 ASSERT_TRUE(FooDecl->getType()->isPointerType()); 495 ASSERT_TRUE(FooDecl->getType() 496 ->getAs<PointerType>() 497 ->getPointeeType() 498 ->isStructureType()); 499 const auto FooFields = FooDecl->getType() 500 ->getAs<PointerType>() 501 ->getPointeeType() 502 ->getAsRecordDecl() 503 ->fields(); 504 505 FieldDecl *BarDecl = nullptr; 506 for (FieldDecl *Field : FooFields) { 507 if (Field->getNameAsString() == "Bar") { 508 BarDecl = Field; 509 } else { 510 FAIL() << "Unexpected field: " << Field->getNameAsString(); 511 } 512 } 513 ASSERT_THAT(BarDecl, NotNull()); 514 515 ASSERT_TRUE(BarDecl->getType()->isPointerType()); 516 ASSERT_TRUE(BarDecl->getType() 517 ->getAs<PointerType>() 518 ->getPointeeType() 519 ->isStructureType()); 520 const auto BarFields = BarDecl->getType() 521 ->getAs<PointerType>() 522 ->getPointeeType() 523 ->getAsRecordDecl() 524 ->fields(); 525 526 FieldDecl *FooRefDecl = nullptr; 527 FieldDecl *FooPtrDecl = nullptr; 528 FieldDecl *BazRefDecl = nullptr; 529 FieldDecl *BazPtrDecl = nullptr; 530 for (FieldDecl *Field : BarFields) { 531 if (Field->getNameAsString() == "FooRef") { 532 FooRefDecl = Field; 533 } else if (Field->getNameAsString() == "FooPtr") { 534 FooPtrDecl = Field; 535 } else if (Field->getNameAsString() == "BazRef") { 536 BazRefDecl = Field; 537 } else if (Field->getNameAsString() == "BazPtr") { 538 BazPtrDecl = Field; 539 } else { 540 FAIL() << "Unexpected field: " << Field->getNameAsString(); 541 } 542 } 543 ASSERT_THAT(FooRefDecl, NotNull()); 544 ASSERT_THAT(FooPtrDecl, NotNull()); 545 ASSERT_THAT(BazRefDecl, NotNull()); 546 ASSERT_THAT(BazPtrDecl, NotNull()); 547 548 const auto *FooLoc = cast<ScalarStorageLocation>( 549 Env.getStorageLocation(*FooDecl, SkipPast::None)); 550 const auto *FooVal = cast<PointerValue>(Env.getValue(*FooLoc)); 551 const auto *FooPointeeVal = 552 cast<StructValue>(Env.getValue(FooVal->getPointeeLoc())); 553 554 const auto *BarVal = 555 cast<PointerValue>(FooPointeeVal->getChild(*BarDecl)); 556 const auto *BarPointeeVal = 557 cast<StructValue>(Env.getValue(BarVal->getPointeeLoc())); 558 559 const auto *FooRefVal = 560 cast<ReferenceValue>(BarPointeeVal->getChild(*FooRefDecl)); 561 const StorageLocation &FooReferentLoc = FooRefVal->getReferentLoc(); 562 EXPECT_THAT(Env.getValue(FooReferentLoc), IsNull()); 563 564 const auto *FooPtrVal = 565 cast<PointerValue>(BarPointeeVal->getChild(*FooPtrDecl)); 566 const StorageLocation &FooPtrPointeeLoc = FooPtrVal->getPointeeLoc(); 567 EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull()); 568 569 const auto *BazRefVal = 570 cast<ReferenceValue>(BarPointeeVal->getChild(*BazRefDecl)); 571 const StorageLocation &BazReferentLoc = BazRefVal->getReferentLoc(); 572 EXPECT_THAT(Env.getValue(BazReferentLoc), NotNull()); 573 574 const auto *BazPtrVal = 575 cast<PointerValue>(BarPointeeVal->getChild(*BazPtrDecl)); 576 const StorageLocation &BazPtrPointeeLoc = BazPtrVal->getPointeeLoc(); 577 EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull()); 578 }); 579 } 580 581 TEST(TransferTest, MultipleVarsDecl) { 582 std::string Code = R"( 583 void target() { 584 int Foo, Bar; 585 (void)0; 586 // [[p]] 587 } 588 )"; 589 runDataflow( 590 Code, 591 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 592 ASTContext &ASTCtx) { 593 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 594 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 595 596 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 597 ASSERT_THAT(FooDecl, NotNull()); 598 599 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 600 ASSERT_THAT(BarDecl, NotNull()); 601 602 const StorageLocation *FooLoc = 603 Env.getStorageLocation(*FooDecl, SkipPast::None); 604 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 605 606 const StorageLocation *BarLoc = 607 Env.getStorageLocation(*BarDecl, SkipPast::None); 608 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 609 610 const Value *FooVal = Env.getValue(*FooLoc); 611 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 612 613 const Value *BarVal = Env.getValue(*BarLoc); 614 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 615 }); 616 } 617 618 TEST(TransferTest, JoinVarDecl) { 619 std::string Code = R"( 620 void target(bool B) { 621 int Foo; 622 // [[p1]] 623 if (B) { 624 int Bar; 625 // [[p2]] 626 } else { 627 int Baz; 628 // [[p3]] 629 } 630 (void)0; 631 // [[p4]] 632 } 633 )"; 634 runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> 635 &Results, 636 ASTContext &ASTCtx) { 637 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2", "p3", "p4")); 638 639 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 640 ASSERT_THAT(FooDecl, NotNull()); 641 642 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 643 ASSERT_THAT(BarDecl, NotNull()); 644 645 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 646 ASSERT_THAT(BazDecl, NotNull()); 647 648 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 649 650 const StorageLocation *FooLoc = 651 Env1.getStorageLocation(*FooDecl, SkipPast::None); 652 EXPECT_THAT(FooLoc, NotNull()); 653 EXPECT_THAT(Env1.getStorageLocation(*BarDecl, SkipPast::None), IsNull()); 654 EXPECT_THAT(Env1.getStorageLocation(*BazDecl, SkipPast::None), IsNull()); 655 656 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 657 EXPECT_EQ(Env2.getStorageLocation(*FooDecl, SkipPast::None), FooLoc); 658 EXPECT_THAT(Env2.getStorageLocation(*BarDecl, SkipPast::None), NotNull()); 659 EXPECT_THAT(Env2.getStorageLocation(*BazDecl, SkipPast::None), IsNull()); 660 661 const Environment &Env3 = getEnvironmentAtAnnotation(Results, "p3"); 662 EXPECT_EQ(Env3.getStorageLocation(*FooDecl, SkipPast::None), FooLoc); 663 EXPECT_THAT(Env3.getStorageLocation(*BarDecl, SkipPast::None), IsNull()); 664 EXPECT_THAT(Env3.getStorageLocation(*BazDecl, SkipPast::None), NotNull()); 665 666 const Environment &Env4 = getEnvironmentAtAnnotation(Results, "p4"); 667 EXPECT_EQ(Env4.getStorageLocation(*FooDecl, SkipPast::None), FooLoc); 668 EXPECT_THAT(Env4.getStorageLocation(*BarDecl, SkipPast::None), IsNull()); 669 EXPECT_THAT(Env4.getStorageLocation(*BazDecl, SkipPast::None), IsNull()); 670 }); 671 } 672 673 TEST(TransferTest, BinaryOperatorAssign) { 674 std::string Code = R"( 675 void target() { 676 int Foo; 677 int Bar; 678 (Bar) = (Foo); 679 // [[p]] 680 } 681 )"; 682 runDataflow( 683 Code, 684 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 685 ASTContext &ASTCtx) { 686 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 687 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 688 689 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 690 ASSERT_THAT(FooDecl, NotNull()); 691 692 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None); 693 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 694 695 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 696 ASSERT_THAT(BarDecl, NotNull()); 697 698 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal); 699 }); 700 } 701 702 TEST(TransferTest, VarDeclInitAssign) { 703 std::string Code = R"( 704 void target() { 705 int Foo; 706 int Bar = Foo; 707 // [[p]] 708 } 709 )"; 710 runDataflow( 711 Code, 712 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 713 ASTContext &ASTCtx) { 714 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 715 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 716 717 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 718 ASSERT_THAT(FooDecl, NotNull()); 719 720 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None); 721 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 722 723 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 724 ASSERT_THAT(BarDecl, NotNull()); 725 726 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal); 727 }); 728 } 729 730 TEST(TransferTest, VarDeclInitAssignChained) { 731 std::string Code = R"( 732 void target() { 733 int Foo; 734 int Bar; 735 int Baz = (Bar = Foo); 736 // [[p]] 737 } 738 )"; 739 runDataflow( 740 Code, 741 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 742 ASTContext &ASTCtx) { 743 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 744 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 745 746 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 747 ASSERT_THAT(FooDecl, NotNull()); 748 749 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None); 750 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 751 752 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 753 ASSERT_THAT(BarDecl, NotNull()); 754 755 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 756 ASSERT_THAT(BazDecl, NotNull()); 757 758 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal); 759 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), FooVal); 760 }); 761 } 762 763 TEST(TransferTest, VarDeclInitAssignPtrDeref) { 764 std::string Code = R"( 765 void target() { 766 int Foo; 767 int *Bar; 768 *(Bar) = Foo; 769 int Baz = *(Bar); 770 // [[p]] 771 } 772 )"; 773 runDataflow( 774 Code, 775 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 776 ASTContext &ASTCtx) { 777 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 778 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 779 780 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 781 ASSERT_THAT(FooDecl, NotNull()); 782 783 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None); 784 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 785 786 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 787 ASSERT_THAT(BarDecl, NotNull()); 788 789 const auto *BarVal = 790 cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None)); 791 EXPECT_EQ(Env.getValue(BarVal->getPointeeLoc()), FooVal); 792 793 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 794 ASSERT_THAT(BazDecl, NotNull()); 795 796 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), FooVal); 797 }); 798 } 799 800 TEST(TransferTest, AssignToAndFromReference) { 801 std::string Code = R"( 802 void target() { 803 int Foo; 804 int Bar; 805 int &Baz = Foo; 806 // [[p1]] 807 Baz = Bar; 808 int Qux = Baz; 809 int &Quux = Baz; 810 // [[p2]] 811 } 812 )"; 813 runDataflow( 814 Code, 815 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 816 ASTContext &ASTCtx) { 817 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 818 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 819 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 820 821 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 822 ASSERT_THAT(FooDecl, NotNull()); 823 824 const Value *FooVal = Env1.getValue(*FooDecl, SkipPast::None); 825 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 826 827 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 828 ASSERT_THAT(BarDecl, NotNull()); 829 830 const Value *BarVal = Env1.getValue(*BarDecl, SkipPast::None); 831 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 832 833 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 834 ASSERT_THAT(BazDecl, NotNull()); 835 836 EXPECT_EQ(Env1.getValue(*BazDecl, SkipPast::Reference), FooVal); 837 838 EXPECT_EQ(Env2.getValue(*BazDecl, SkipPast::Reference), BarVal); 839 EXPECT_EQ(Env2.getValue(*FooDecl, SkipPast::None), BarVal); 840 841 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 842 ASSERT_THAT(QuxDecl, NotNull()); 843 EXPECT_EQ(Env2.getValue(*QuxDecl, SkipPast::None), BarVal); 844 845 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 846 ASSERT_THAT(QuuxDecl, NotNull()); 847 EXPECT_EQ(Env2.getValue(*QuuxDecl, SkipPast::Reference), BarVal); 848 }); 849 } 850 851 TEST(TransferTest, MultipleParamDecls) { 852 std::string Code = R"( 853 void target(int Foo, int Bar) { 854 (void)0; 855 // [[p]] 856 } 857 )"; 858 runDataflow( 859 Code, 860 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 861 ASTContext &ASTCtx) { 862 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 863 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 864 865 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 866 ASSERT_THAT(FooDecl, NotNull()); 867 868 const StorageLocation *FooLoc = 869 Env.getStorageLocation(*FooDecl, SkipPast::None); 870 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 871 872 const Value *FooVal = Env.getValue(*FooLoc); 873 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 874 875 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 876 ASSERT_THAT(BarDecl, NotNull()); 877 878 const StorageLocation *BarLoc = 879 Env.getStorageLocation(*BarDecl, SkipPast::None); 880 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 881 882 const Value *BarVal = Env.getValue(*BarLoc); 883 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 884 }); 885 } 886 887 TEST(TransferTest, StructParamDecl) { 888 std::string Code = R"( 889 struct A { 890 int Bar; 891 }; 892 893 void target(A Foo) { 894 (void)0; 895 // [[p]] 896 } 897 )"; 898 runDataflow( 899 Code, 900 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 901 ASTContext &ASTCtx) { 902 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 903 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 904 905 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 906 ASSERT_THAT(FooDecl, NotNull()); 907 908 ASSERT_TRUE(FooDecl->getType()->isStructureType()); 909 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 910 911 FieldDecl *BarDecl = nullptr; 912 for (FieldDecl *Field : FooFields) { 913 if (Field->getNameAsString() == "Bar") { 914 BarDecl = Field; 915 } else { 916 FAIL() << "Unexpected field: " << Field->getNameAsString(); 917 } 918 } 919 ASSERT_THAT(BarDecl, NotNull()); 920 921 const auto *FooLoc = cast<AggregateStorageLocation>( 922 Env.getStorageLocation(*FooDecl, SkipPast::None)); 923 const auto *BarLoc = 924 cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl)); 925 926 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 927 const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl)); 928 EXPECT_EQ(Env.getValue(*BarLoc), BarVal); 929 }); 930 } 931 932 TEST(TransferTest, ReferenceParamDecl) { 933 std::string Code = R"( 934 struct A {}; 935 936 void target(A &Foo) { 937 (void)0; 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 StorageLocation *FooLoc = 952 Env.getStorageLocation(*FooDecl, SkipPast::None); 953 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 954 955 const ReferenceValue *FooVal = 956 dyn_cast<ReferenceValue>(Env.getValue(*FooLoc)); 957 ASSERT_THAT(FooVal, NotNull()); 958 959 const StorageLocation &FooReferentLoc = FooVal->getReferentLoc(); 960 EXPECT_TRUE(isa<AggregateStorageLocation>(&FooReferentLoc)); 961 962 const Value *FooReferentVal = Env.getValue(FooReferentLoc); 963 EXPECT_TRUE(isa_and_nonnull<StructValue>(FooReferentVal)); 964 }); 965 } 966 967 TEST(TransferTest, PointerParamDecl) { 968 std::string Code = R"( 969 struct A {}; 970 971 void target(A *Foo) { 972 (void)0; 973 // [[p]] 974 } 975 )"; 976 runDataflow( 977 Code, 978 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 979 ASTContext &ASTCtx) { 980 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 981 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 982 983 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 984 ASSERT_THAT(FooDecl, NotNull()); 985 986 const StorageLocation *FooLoc = 987 Env.getStorageLocation(*FooDecl, SkipPast::None); 988 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 989 990 const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc)); 991 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc(); 992 EXPECT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc)); 993 994 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc); 995 EXPECT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal)); 996 }); 997 } 998 999 TEST(TransferTest, StructMember) { 1000 std::string Code = R"( 1001 struct A { 1002 int Bar; 1003 }; 1004 1005 void target(A Foo) { 1006 int Baz = Foo.Bar; 1007 // [[p]] 1008 } 1009 )"; 1010 runDataflow( 1011 Code, 1012 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1013 ASTContext &ASTCtx) { 1014 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1015 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1016 1017 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1018 ASSERT_THAT(FooDecl, NotNull()); 1019 1020 ASSERT_TRUE(FooDecl->getType()->isStructureType()); 1021 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 1022 1023 FieldDecl *BarDecl = nullptr; 1024 for (FieldDecl *Field : FooFields) { 1025 if (Field->getNameAsString() == "Bar") { 1026 BarDecl = Field; 1027 } else { 1028 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1029 } 1030 } 1031 ASSERT_THAT(BarDecl, NotNull()); 1032 1033 const auto *FooLoc = cast<AggregateStorageLocation>( 1034 Env.getStorageLocation(*FooDecl, SkipPast::None)); 1035 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 1036 const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl)); 1037 1038 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 1039 ASSERT_THAT(BazDecl, NotNull()); 1040 1041 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarVal); 1042 }); 1043 } 1044 1045 TEST(TransferTest, DerivedBaseMemberClass) { 1046 std::string Code = R"( 1047 class A { 1048 int ADefault; 1049 protected: 1050 int AProtected; 1051 private: 1052 int APrivate; 1053 public: 1054 int APublic; 1055 }; 1056 1057 class B : public A { 1058 int BDefault; 1059 protected: 1060 int BProtected; 1061 private: 1062 int BPrivate; 1063 }; 1064 1065 void target() { 1066 B Foo; 1067 // [[p]] 1068 } 1069 )"; 1070 runDataflow( 1071 Code, 1072 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1073 ASTContext &ASTCtx) { 1074 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1075 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1076 1077 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1078 ASSERT_THAT(FooDecl, NotNull()); 1079 ASSERT_TRUE(FooDecl->getType()->isRecordType()); 1080 1081 // Derived-class fields. 1082 const FieldDecl *BDefaultDecl = nullptr; 1083 const FieldDecl *BProtectedDecl = nullptr; 1084 const FieldDecl *BPrivateDecl = nullptr; 1085 for (const FieldDecl *Field : 1086 FooDecl->getType()->getAsRecordDecl()->fields()) { 1087 if (Field->getNameAsString() == "BDefault") { 1088 BDefaultDecl = Field; 1089 } else if (Field->getNameAsString() == "BProtected") { 1090 BProtectedDecl = Field; 1091 } else if (Field->getNameAsString() == "BPrivate") { 1092 BPrivateDecl = Field; 1093 } else { 1094 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1095 } 1096 } 1097 ASSERT_THAT(BDefaultDecl, NotNull()); 1098 ASSERT_THAT(BProtectedDecl, NotNull()); 1099 ASSERT_THAT(BPrivateDecl, NotNull()); 1100 1101 // Base-class fields. 1102 const FieldDecl *ADefaultDecl = nullptr; 1103 const FieldDecl *APrivateDecl = nullptr; 1104 const FieldDecl *AProtectedDecl = nullptr; 1105 const FieldDecl *APublicDecl = nullptr; 1106 for (const clang::CXXBaseSpecifier &Base : 1107 FooDecl->getType()->getAsCXXRecordDecl()->bases()) { 1108 QualType BaseType = Base.getType(); 1109 ASSERT_TRUE(BaseType->isRecordType()); 1110 for (const FieldDecl *Field : BaseType->getAsRecordDecl()->fields()) { 1111 if (Field->getNameAsString() == "ADefault") { 1112 ADefaultDecl = Field; 1113 } else if (Field->getNameAsString() == "AProtected") { 1114 AProtectedDecl = Field; 1115 } else if (Field->getNameAsString() == "APrivate") { 1116 APrivateDecl = Field; 1117 } else if (Field->getNameAsString() == "APublic") { 1118 APublicDecl = Field; 1119 } else { 1120 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1121 } 1122 } 1123 } 1124 ASSERT_THAT(ADefaultDecl, NotNull()); 1125 ASSERT_THAT(AProtectedDecl, NotNull()); 1126 ASSERT_THAT(APrivateDecl, NotNull()); 1127 ASSERT_THAT(APublicDecl, NotNull()); 1128 1129 const auto &FooLoc = *cast<AggregateStorageLocation>( 1130 Env.getStorageLocation(*FooDecl, SkipPast::None)); 1131 const auto &FooVal = *cast<StructValue>(Env.getValue(FooLoc)); 1132 1133 // Note: we can't test presence of children in `FooLoc`, because 1134 // `getChild` requires its argument be present (or fails an assert). So, 1135 // we limit to testing presence in `FooVal` and coherence between the 1136 // two. 1137 1138 // Base-class fields. 1139 EXPECT_THAT(FooVal.getChild(*ADefaultDecl), NotNull()); 1140 EXPECT_THAT(FooVal.getChild(*APrivateDecl), NotNull()); 1141 1142 EXPECT_THAT(FooVal.getChild(*AProtectedDecl), NotNull()); 1143 EXPECT_EQ(Env.getValue(FooLoc.getChild(*APublicDecl)), 1144 FooVal.getChild(*APublicDecl)); 1145 EXPECT_THAT(FooVal.getChild(*APublicDecl), NotNull()); 1146 EXPECT_EQ(Env.getValue(FooLoc.getChild(*AProtectedDecl)), 1147 FooVal.getChild(*AProtectedDecl)); 1148 1149 // Derived-class fields. 1150 EXPECT_THAT(FooVal.getChild(*BDefaultDecl), NotNull()); 1151 EXPECT_EQ(Env.getValue(FooLoc.getChild(*BDefaultDecl)), 1152 FooVal.getChild(*BDefaultDecl)); 1153 EXPECT_THAT(FooVal.getChild(*BProtectedDecl), NotNull()); 1154 EXPECT_EQ(Env.getValue(FooLoc.getChild(*BProtectedDecl)), 1155 FooVal.getChild(*BProtectedDecl)); 1156 EXPECT_THAT(FooVal.getChild(*BPrivateDecl), NotNull()); 1157 EXPECT_EQ(Env.getValue(FooLoc.getChild(*BPrivateDecl)), 1158 FooVal.getChild(*BPrivateDecl)); 1159 }); 1160 } 1161 1162 static void derivedBaseMemberExpectations( 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()->isRecordType()); 1172 const FieldDecl *BarDecl = nullptr; 1173 for (const clang::CXXBaseSpecifier &Base : 1174 FooDecl->getType()->getAsCXXRecordDecl()->bases()) { 1175 QualType BaseType = Base.getType(); 1176 ASSERT_TRUE(BaseType->isStructureType()); 1177 1178 for (const FieldDecl *Field : BaseType->getAsRecordDecl()->fields()) { 1179 if (Field->getNameAsString() == "Bar") { 1180 BarDecl = Field; 1181 } else { 1182 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1183 } 1184 } 1185 } 1186 ASSERT_THAT(BarDecl, NotNull()); 1187 1188 const auto &FooLoc = *cast<AggregateStorageLocation>( 1189 Env.getStorageLocation(*FooDecl, SkipPast::None)); 1190 const auto &FooVal = *cast<StructValue>(Env.getValue(FooLoc)); 1191 EXPECT_THAT(FooVal.getChild(*BarDecl), NotNull()); 1192 EXPECT_EQ(Env.getValue(FooLoc.getChild(*BarDecl)), FooVal.getChild(*BarDecl)); 1193 } 1194 1195 TEST(TransferTest, DerivedBaseMemberStructDefault) { 1196 std::string Code = R"( 1197 struct A { 1198 int Bar; 1199 }; 1200 struct B : public A { 1201 }; 1202 1203 void target() { 1204 B Foo; 1205 // [[p]] 1206 } 1207 )"; 1208 runDataflow(Code, derivedBaseMemberExpectations); 1209 } 1210 1211 TEST(TransferTest, DerivedBaseMemberPrivateFriend) { 1212 // Include an access to `Foo.Bar` to verify the analysis doesn't crash on that 1213 // access. 1214 std::string Code = R"( 1215 struct A { 1216 private: 1217 friend void target(); 1218 int Bar; 1219 }; 1220 struct B : public A { 1221 }; 1222 1223 void target() { 1224 B Foo; 1225 (void)Foo.Bar; 1226 // [[p]] 1227 } 1228 )"; 1229 runDataflow(Code, derivedBaseMemberExpectations); 1230 } 1231 1232 TEST(TransferTest, ClassMember) { 1233 std::string Code = R"( 1234 class A { 1235 public: 1236 int Bar; 1237 }; 1238 1239 void target(A Foo) { 1240 int Baz = Foo.Bar; 1241 // [[p]] 1242 } 1243 )"; 1244 runDataflow( 1245 Code, 1246 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1247 ASTContext &ASTCtx) { 1248 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1249 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1250 1251 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1252 ASSERT_THAT(FooDecl, NotNull()); 1253 1254 ASSERT_TRUE(FooDecl->getType()->isClassType()); 1255 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 1256 1257 FieldDecl *BarDecl = nullptr; 1258 for (FieldDecl *Field : FooFields) { 1259 if (Field->getNameAsString() == "Bar") { 1260 BarDecl = Field; 1261 } else { 1262 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1263 } 1264 } 1265 ASSERT_THAT(BarDecl, NotNull()); 1266 1267 const auto *FooLoc = cast<AggregateStorageLocation>( 1268 Env.getStorageLocation(*FooDecl, SkipPast::None)); 1269 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 1270 const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl)); 1271 1272 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 1273 ASSERT_THAT(BazDecl, NotNull()); 1274 1275 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarVal); 1276 }); 1277 } 1278 1279 TEST(TransferTest, BaseClassInitializer) { 1280 using ast_matchers::cxxConstructorDecl; 1281 using ast_matchers::hasName; 1282 using ast_matchers::ofClass; 1283 1284 std::string Code = R"( 1285 class A { 1286 public: 1287 A(int I) : Bar(I) {} 1288 int Bar; 1289 }; 1290 1291 class B : public A { 1292 public: 1293 B(int I) : A(I) { 1294 (void)0; 1295 // [[p]] 1296 } 1297 }; 1298 )"; 1299 ASSERT_THAT_ERROR( 1300 checkDataflow<NoopAnalysis>( 1301 AnalysisInputs<NoopAnalysis>( 1302 Code, cxxConstructorDecl(ofClass(hasName("B"))), 1303 [](ASTContext &C, Environment &) { 1304 return NoopAnalysis(C, /*ApplyBuiltinTransfer=*/true); 1305 }) 1306 .withASTBuildArgs( 1307 {"-fsyntax-only", "-fno-delayed-template-parsing", 1308 "-std=" + std::string(LangStandard::getLangStandardForKind( 1309 LangStandard::lang_cxx17) 1310 .getName())}), 1311 /*VerifyResults=*/ 1312 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1313 const AnalysisOutputs &) { 1314 // Regression test to verify that base-class initializers do not 1315 // trigger an assertion. If we add support for such initializers in 1316 // the future, we can expand this test to check more specific 1317 // properties. 1318 EXPECT_THAT(Results.keys(), UnorderedElementsAre("p")); 1319 }), 1320 llvm::Succeeded()); 1321 } 1322 1323 TEST(TransferTest, ReferenceMember) { 1324 std::string Code = R"( 1325 struct A { 1326 int &Bar; 1327 }; 1328 1329 void target(A Foo) { 1330 int Baz = Foo.Bar; 1331 // [[p]] 1332 } 1333 )"; 1334 runDataflow( 1335 Code, 1336 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1337 ASTContext &ASTCtx) { 1338 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1339 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1340 1341 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1342 ASSERT_THAT(FooDecl, NotNull()); 1343 1344 ASSERT_TRUE(FooDecl->getType()->isStructureType()); 1345 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 1346 1347 FieldDecl *BarDecl = nullptr; 1348 for (FieldDecl *Field : FooFields) { 1349 if (Field->getNameAsString() == "Bar") { 1350 BarDecl = Field; 1351 } else { 1352 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1353 } 1354 } 1355 ASSERT_THAT(BarDecl, NotNull()); 1356 1357 const auto *FooLoc = cast<AggregateStorageLocation>( 1358 Env.getStorageLocation(*FooDecl, SkipPast::None)); 1359 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 1360 const auto *BarVal = cast<ReferenceValue>(FooVal->getChild(*BarDecl)); 1361 const auto *BarReferentVal = 1362 cast<IntegerValue>(Env.getValue(BarVal->getReferentLoc())); 1363 1364 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 1365 ASSERT_THAT(BazDecl, NotNull()); 1366 1367 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), BarReferentVal); 1368 }); 1369 } 1370 1371 TEST(TransferTest, StructThisMember) { 1372 std::string Code = R"( 1373 struct A { 1374 int Bar; 1375 1376 struct B { 1377 int Baz; 1378 }; 1379 1380 B Qux; 1381 1382 void target() { 1383 int Foo = Bar; 1384 int Quux = Qux.Baz; 1385 // [[p]] 1386 } 1387 }; 1388 )"; 1389 runDataflow( 1390 Code, 1391 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1392 ASTContext &ASTCtx) { 1393 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1394 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1395 1396 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>( 1397 Env.getThisPointeeStorageLocation()); 1398 ASSERT_THAT(ThisLoc, NotNull()); 1399 1400 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1401 ASSERT_THAT(BarDecl, NotNull()); 1402 1403 const auto *BarLoc = 1404 cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl)); 1405 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 1406 1407 const Value *BarVal = Env.getValue(*BarLoc); 1408 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 1409 1410 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1411 ASSERT_THAT(FooDecl, NotNull()); 1412 EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal); 1413 1414 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 1415 ASSERT_THAT(QuxDecl, NotNull()); 1416 1417 ASSERT_TRUE(QuxDecl->getType()->isStructureType()); 1418 auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields(); 1419 1420 FieldDecl *BazDecl = nullptr; 1421 for (FieldDecl *Field : QuxFields) { 1422 if (Field->getNameAsString() == "Baz") { 1423 BazDecl = Field; 1424 } else { 1425 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1426 } 1427 } 1428 ASSERT_THAT(BazDecl, NotNull()); 1429 1430 const auto *QuxLoc = 1431 cast<AggregateStorageLocation>(&ThisLoc->getChild(*QuxDecl)); 1432 const auto *QuxVal = dyn_cast<StructValue>(Env.getValue(*QuxLoc)); 1433 ASSERT_THAT(QuxVal, NotNull()); 1434 1435 const auto *BazLoc = 1436 cast<ScalarStorageLocation>(&QuxLoc->getChild(*BazDecl)); 1437 const auto *BazVal = cast<IntegerValue>(QuxVal->getChild(*BazDecl)); 1438 EXPECT_EQ(Env.getValue(*BazLoc), BazVal); 1439 1440 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 1441 ASSERT_THAT(QuuxDecl, NotNull()); 1442 EXPECT_EQ(Env.getValue(*QuuxDecl, SkipPast::None), BazVal); 1443 }); 1444 } 1445 1446 TEST(TransferTest, ClassThisMember) { 1447 std::string Code = R"( 1448 class A { 1449 int Bar; 1450 1451 class B { 1452 public: 1453 int Baz; 1454 }; 1455 1456 B Qux; 1457 1458 void target() { 1459 int Foo = Bar; 1460 int Quux = Qux.Baz; 1461 // [[p]] 1462 } 1463 }; 1464 )"; 1465 runDataflow( 1466 Code, 1467 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1468 ASTContext &ASTCtx) { 1469 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1470 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1471 1472 const auto *ThisLoc = 1473 cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation()); 1474 1475 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1476 ASSERT_THAT(BarDecl, NotNull()); 1477 1478 const auto *BarLoc = 1479 cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl)); 1480 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 1481 1482 const Value *BarVal = Env.getValue(*BarLoc); 1483 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 1484 1485 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1486 ASSERT_THAT(FooDecl, NotNull()); 1487 EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal); 1488 1489 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 1490 ASSERT_THAT(QuxDecl, NotNull()); 1491 1492 ASSERT_TRUE(QuxDecl->getType()->isClassType()); 1493 auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields(); 1494 1495 FieldDecl *BazDecl = nullptr; 1496 for (FieldDecl *Field : QuxFields) { 1497 if (Field->getNameAsString() == "Baz") { 1498 BazDecl = Field; 1499 } else { 1500 FAIL() << "Unexpected field: " << Field->getNameAsString(); 1501 } 1502 } 1503 ASSERT_THAT(BazDecl, NotNull()); 1504 1505 const auto *QuxLoc = 1506 cast<AggregateStorageLocation>(&ThisLoc->getChild(*QuxDecl)); 1507 const auto *QuxVal = dyn_cast<StructValue>(Env.getValue(*QuxLoc)); 1508 ASSERT_THAT(QuxVal, NotNull()); 1509 1510 const auto *BazLoc = 1511 cast<ScalarStorageLocation>(&QuxLoc->getChild(*BazDecl)); 1512 const auto *BazVal = cast<IntegerValue>(QuxVal->getChild(*BazDecl)); 1513 EXPECT_EQ(Env.getValue(*BazLoc), BazVal); 1514 1515 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 1516 ASSERT_THAT(QuuxDecl, NotNull()); 1517 EXPECT_EQ(Env.getValue(*QuuxDecl, SkipPast::None), BazVal); 1518 }); 1519 } 1520 1521 TEST(TransferTest, StructThisInLambda) { 1522 std::string ThisCaptureCode = R"( 1523 struct A { 1524 void frob() { 1525 [this]() { 1526 int Foo = Bar; 1527 // [[p1]] 1528 }(); 1529 } 1530 1531 int Bar; 1532 }; 1533 )"; 1534 runDataflow( 1535 ThisCaptureCode, 1536 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1537 ASTContext &ASTCtx) { 1538 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1")); 1539 const Environment &Env = getEnvironmentAtAnnotation(Results, "p1"); 1540 1541 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>( 1542 Env.getThisPointeeStorageLocation()); 1543 ASSERT_THAT(ThisLoc, NotNull()); 1544 1545 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1546 ASSERT_THAT(BarDecl, NotNull()); 1547 1548 const auto *BarLoc = 1549 cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl)); 1550 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 1551 1552 const Value *BarVal = Env.getValue(*BarLoc); 1553 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 1554 1555 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1556 ASSERT_THAT(FooDecl, NotNull()); 1557 EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal); 1558 }, 1559 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()"); 1560 1561 std::string RefCaptureDefaultCode = R"( 1562 struct A { 1563 void frob() { 1564 [&]() { 1565 int Foo = Bar; 1566 // [[p2]] 1567 }(); 1568 } 1569 1570 int Bar; 1571 }; 1572 )"; 1573 runDataflow( 1574 RefCaptureDefaultCode, 1575 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1576 ASTContext &ASTCtx) { 1577 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p2")); 1578 const Environment &Env = getEnvironmentAtAnnotation(Results, "p2"); 1579 1580 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>( 1581 Env.getThisPointeeStorageLocation()); 1582 ASSERT_THAT(ThisLoc, NotNull()); 1583 1584 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1585 ASSERT_THAT(BarDecl, NotNull()); 1586 1587 const auto *BarLoc = 1588 cast<ScalarStorageLocation>(&ThisLoc->getChild(*BarDecl)); 1589 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 1590 1591 const Value *BarVal = Env.getValue(*BarLoc); 1592 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 1593 1594 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1595 ASSERT_THAT(FooDecl, NotNull()); 1596 EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), BarVal); 1597 }, 1598 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()"); 1599 1600 std::string FreeFunctionLambdaCode = R"( 1601 void foo() { 1602 int Bar; 1603 [&]() { 1604 int Foo = Bar; 1605 // [[p3]] 1606 }(); 1607 } 1608 )"; 1609 runDataflow( 1610 FreeFunctionLambdaCode, 1611 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1612 ASTContext &ASTCtx) { 1613 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p3")); 1614 const Environment &Env = getEnvironmentAtAnnotation(Results, "p3"); 1615 1616 EXPECT_THAT(Env.getThisPointeeStorageLocation(), IsNull()); 1617 }, 1618 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()"); 1619 } 1620 1621 TEST(TransferTest, ConstructorInitializer) { 1622 std::string Code = R"( 1623 struct target { 1624 int Bar; 1625 1626 target(int Foo) : Bar(Foo) { 1627 int Qux = Bar; 1628 // [[p]] 1629 } 1630 }; 1631 )"; 1632 runDataflow( 1633 Code, 1634 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1635 ASTContext &ASTCtx) { 1636 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1637 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1638 1639 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>( 1640 Env.getThisPointeeStorageLocation()); 1641 ASSERT_THAT(ThisLoc, NotNull()); 1642 1643 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1644 ASSERT_THAT(FooDecl, NotNull()); 1645 1646 const auto *FooVal = 1647 cast<IntegerValue>(Env.getValue(*FooDecl, SkipPast::None)); 1648 1649 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 1650 ASSERT_THAT(QuxDecl, NotNull()); 1651 EXPECT_EQ(Env.getValue(*QuxDecl, SkipPast::None), FooVal); 1652 }); 1653 } 1654 1655 TEST(TransferTest, DefaultInitializer) { 1656 std::string Code = R"( 1657 struct target { 1658 int Bar; 1659 int Baz = Bar; 1660 1661 target(int Foo) : Bar(Foo) { 1662 int Qux = Baz; 1663 // [[p]] 1664 } 1665 }; 1666 )"; 1667 runDataflow( 1668 Code, 1669 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1670 ASTContext &ASTCtx) { 1671 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1672 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1673 1674 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>( 1675 Env.getThisPointeeStorageLocation()); 1676 ASSERT_THAT(ThisLoc, NotNull()); 1677 1678 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1679 ASSERT_THAT(FooDecl, NotNull()); 1680 1681 const auto *FooVal = 1682 cast<IntegerValue>(Env.getValue(*FooDecl, SkipPast::None)); 1683 1684 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 1685 ASSERT_THAT(QuxDecl, NotNull()); 1686 EXPECT_EQ(Env.getValue(*QuxDecl, SkipPast::None), FooVal); 1687 }); 1688 } 1689 1690 TEST(TransferTest, DefaultInitializerReference) { 1691 std::string Code = R"( 1692 struct target { 1693 int &Bar; 1694 int &Baz = Bar; 1695 1696 target(int &Foo) : Bar(Foo) { 1697 int &Qux = Baz; 1698 // [[p]] 1699 } 1700 }; 1701 )"; 1702 runDataflow( 1703 Code, 1704 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1705 ASTContext &ASTCtx) { 1706 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1707 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1708 1709 const auto *ThisLoc = dyn_cast<AggregateStorageLocation>( 1710 Env.getThisPointeeStorageLocation()); 1711 ASSERT_THAT(ThisLoc, NotNull()); 1712 1713 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1714 ASSERT_THAT(FooDecl, NotNull()); 1715 1716 const auto *FooVal = 1717 cast<ReferenceValue>(Env.getValue(*FooDecl, SkipPast::None)); 1718 1719 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 1720 ASSERT_THAT(QuxDecl, NotNull()); 1721 1722 const auto *QuxVal = 1723 cast<ReferenceValue>(Env.getValue(*QuxDecl, SkipPast::None)); 1724 EXPECT_EQ(&QuxVal->getReferentLoc(), &FooVal->getReferentLoc()); 1725 }); 1726 } 1727 1728 TEST(TransferTest, TemporaryObject) { 1729 std::string Code = R"( 1730 struct A { 1731 int Bar; 1732 }; 1733 1734 void target() { 1735 A Foo = A(); 1736 // [[p]] 1737 } 1738 )"; 1739 runDataflow( 1740 Code, 1741 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1742 ASTContext &ASTCtx) { 1743 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1744 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1745 1746 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1747 ASSERT_THAT(FooDecl, NotNull()); 1748 1749 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1750 ASSERT_THAT(BarDecl, NotNull()); 1751 1752 const auto *FooLoc = cast<AggregateStorageLocation>( 1753 Env.getStorageLocation(*FooDecl, SkipPast::None)); 1754 const auto *BarLoc = 1755 cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl)); 1756 1757 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 1758 const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl)); 1759 EXPECT_EQ(Env.getValue(*BarLoc), BarVal); 1760 }); 1761 } 1762 1763 TEST(TransferTest, ElidableConstructor) { 1764 // This test is effectively the same as TransferTest.TemporaryObject, but 1765 // the code is compiled as C++ 14. 1766 std::string Code = R"( 1767 struct A { 1768 int Bar; 1769 }; 1770 1771 void target() { 1772 A Foo = A(); 1773 // [[p]] 1774 } 1775 )"; 1776 runDataflow( 1777 Code, 1778 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1779 ASTContext &ASTCtx) { 1780 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1781 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1782 1783 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1784 ASSERT_THAT(FooDecl, NotNull()); 1785 1786 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1787 ASSERT_THAT(BarDecl, NotNull()); 1788 1789 const auto *FooLoc = cast<AggregateStorageLocation>( 1790 Env.getStorageLocation(*FooDecl, SkipPast::None)); 1791 const auto *BarLoc = 1792 cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl)); 1793 1794 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 1795 const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl)); 1796 EXPECT_EQ(Env.getValue(*BarLoc), BarVal); 1797 }, 1798 LangStandard::lang_cxx14); 1799 } 1800 1801 TEST(TransferTest, AssignmentOperator) { 1802 std::string Code = R"( 1803 struct A { 1804 int Baz; 1805 }; 1806 1807 void target() { 1808 A Foo; 1809 A Bar; 1810 // [[p1]] 1811 Foo = Bar; 1812 // [[p2]] 1813 } 1814 )"; 1815 runDataflow( 1816 Code, 1817 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1818 ASTContext &ASTCtx) { 1819 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 1820 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 1821 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 1822 1823 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1824 ASSERT_THAT(FooDecl, NotNull()); 1825 1826 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1827 ASSERT_THAT(BarDecl, NotNull()); 1828 1829 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 1830 ASSERT_THAT(BazDecl, NotNull()); 1831 1832 const auto *FooLoc1 = cast<AggregateStorageLocation>( 1833 Env1.getStorageLocation(*FooDecl, SkipPast::None)); 1834 const auto *BarLoc1 = cast<AggregateStorageLocation>( 1835 Env1.getStorageLocation(*BarDecl, SkipPast::None)); 1836 1837 const auto *FooVal1 = cast<StructValue>(Env1.getValue(*FooLoc1)); 1838 const auto *BarVal1 = cast<StructValue>(Env1.getValue(*BarLoc1)); 1839 EXPECT_NE(FooVal1, BarVal1); 1840 1841 const auto *FooBazVal1 = 1842 cast<IntegerValue>(Env1.getValue(FooLoc1->getChild(*BazDecl))); 1843 const auto *BarBazVal1 = 1844 cast<IntegerValue>(Env1.getValue(BarLoc1->getChild(*BazDecl))); 1845 EXPECT_NE(FooBazVal1, BarBazVal1); 1846 1847 const auto *FooLoc2 = cast<AggregateStorageLocation>( 1848 Env2.getStorageLocation(*FooDecl, SkipPast::None)); 1849 const auto *BarLoc2 = cast<AggregateStorageLocation>( 1850 Env2.getStorageLocation(*BarDecl, SkipPast::None)); 1851 1852 const auto *FooVal2 = cast<StructValue>(Env2.getValue(*FooLoc2)); 1853 const auto *BarVal2 = cast<StructValue>(Env2.getValue(*BarLoc2)); 1854 EXPECT_EQ(FooVal2, BarVal2); 1855 1856 const auto *FooBazVal2 = 1857 cast<IntegerValue>(Env2.getValue(FooLoc1->getChild(*BazDecl))); 1858 const auto *BarBazVal2 = 1859 cast<IntegerValue>(Env2.getValue(BarLoc1->getChild(*BazDecl))); 1860 EXPECT_EQ(FooBazVal2, BarBazVal2); 1861 }); 1862 } 1863 1864 TEST(TransferTest, CopyConstructor) { 1865 std::string Code = R"( 1866 struct A { 1867 int Baz; 1868 }; 1869 1870 void target() { 1871 A Foo; 1872 A Bar = Foo; 1873 // [[p]] 1874 } 1875 )"; 1876 runDataflow( 1877 Code, 1878 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1879 ASTContext &ASTCtx) { 1880 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1881 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1882 1883 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1884 ASSERT_THAT(FooDecl, NotNull()); 1885 1886 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1887 ASSERT_THAT(BarDecl, NotNull()); 1888 1889 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 1890 ASSERT_THAT(BazDecl, NotNull()); 1891 1892 const auto *FooLoc = cast<AggregateStorageLocation>( 1893 Env.getStorageLocation(*FooDecl, SkipPast::None)); 1894 const auto *BarLoc = cast<AggregateStorageLocation>( 1895 Env.getStorageLocation(*BarDecl, SkipPast::None)); 1896 1897 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 1898 const auto *BarVal = cast<StructValue>(Env.getValue(*BarLoc)); 1899 EXPECT_EQ(FooVal, BarVal); 1900 1901 const auto *FooBazVal = 1902 cast<IntegerValue>(Env.getValue(FooLoc->getChild(*BazDecl))); 1903 const auto *BarBazVal = 1904 cast<IntegerValue>(Env.getValue(BarLoc->getChild(*BazDecl))); 1905 EXPECT_EQ(FooBazVal, BarBazVal); 1906 }); 1907 } 1908 1909 TEST(TransferTest, CopyConstructorWithParens) { 1910 std::string Code = R"( 1911 struct A { 1912 int Baz; 1913 }; 1914 1915 void target() { 1916 A Foo; 1917 A Bar((A(Foo))); 1918 // [[p]] 1919 } 1920 )"; 1921 runDataflow( 1922 Code, 1923 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1924 ASTContext &ASTCtx) { 1925 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 1926 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 1927 1928 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1929 ASSERT_THAT(FooDecl, NotNull()); 1930 1931 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1932 ASSERT_THAT(BarDecl, NotNull()); 1933 1934 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 1935 ASSERT_THAT(BazDecl, NotNull()); 1936 1937 const auto *FooLoc = cast<AggregateStorageLocation>( 1938 Env.getStorageLocation(*FooDecl, SkipPast::None)); 1939 const auto *BarLoc = cast<AggregateStorageLocation>( 1940 Env.getStorageLocation(*BarDecl, SkipPast::None)); 1941 1942 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 1943 const auto *BarVal = cast<StructValue>(Env.getValue(*BarLoc)); 1944 EXPECT_EQ(FooVal, BarVal); 1945 1946 const auto *FooBazVal = 1947 cast<IntegerValue>(Env.getValue(FooLoc->getChild(*BazDecl))); 1948 const auto *BarBazVal = 1949 cast<IntegerValue>(Env.getValue(BarLoc->getChild(*BazDecl))); 1950 EXPECT_EQ(FooBazVal, BarBazVal); 1951 }); 1952 } 1953 1954 TEST(TransferTest, MoveConstructor) { 1955 std::string Code = R"( 1956 namespace std { 1957 1958 template <typename T> struct remove_reference { using type = T; }; 1959 template <typename T> struct remove_reference<T&> { using type = T; }; 1960 template <typename T> struct remove_reference<T&&> { using type = T; }; 1961 1962 template <typename T> 1963 using remove_reference_t = typename remove_reference<T>::type; 1964 1965 template <typename T> 1966 std::remove_reference_t<T>&& move(T&& x); 1967 1968 } // namespace std 1969 1970 struct A { 1971 int Baz; 1972 }; 1973 1974 void target() { 1975 A Foo; 1976 A Bar; 1977 // [[p1]] 1978 Foo = std::move(Bar); 1979 // [[p2]] 1980 } 1981 )"; 1982 runDataflow( 1983 Code, 1984 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 1985 ASTContext &ASTCtx) { 1986 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 1987 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 1988 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 1989 1990 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 1991 ASSERT_THAT(FooDecl, NotNull()); 1992 1993 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 1994 ASSERT_THAT(BarDecl, NotNull()); 1995 1996 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 1997 ASSERT_THAT(BazDecl, NotNull()); 1998 1999 const auto *FooLoc1 = cast<AggregateStorageLocation>( 2000 Env1.getStorageLocation(*FooDecl, SkipPast::None)); 2001 const auto *BarLoc1 = cast<AggregateStorageLocation>( 2002 Env1.getStorageLocation(*BarDecl, SkipPast::None)); 2003 2004 const auto *FooVal1 = cast<StructValue>(Env1.getValue(*FooLoc1)); 2005 const auto *BarVal1 = cast<StructValue>(Env1.getValue(*BarLoc1)); 2006 EXPECT_NE(FooVal1, BarVal1); 2007 2008 const auto *FooBazVal1 = 2009 cast<IntegerValue>(Env1.getValue(FooLoc1->getChild(*BazDecl))); 2010 const auto *BarBazVal1 = 2011 cast<IntegerValue>(Env1.getValue(BarLoc1->getChild(*BazDecl))); 2012 EXPECT_NE(FooBazVal1, BarBazVal1); 2013 2014 const auto *FooLoc2 = cast<AggregateStorageLocation>( 2015 Env2.getStorageLocation(*FooDecl, SkipPast::None)); 2016 const auto *FooVal2 = cast<StructValue>(Env2.getValue(*FooLoc2)); 2017 EXPECT_EQ(FooVal2, BarVal1); 2018 2019 const auto *FooBazVal2 = 2020 cast<IntegerValue>(Env2.getValue(FooLoc1->getChild(*BazDecl))); 2021 EXPECT_EQ(FooBazVal2, BarBazVal1); 2022 }); 2023 } 2024 2025 TEST(TransferTest, BindTemporary) { 2026 std::string Code = R"( 2027 struct A { 2028 virtual ~A() = default; 2029 2030 int Baz; 2031 }; 2032 2033 void target(A Foo) { 2034 int Bar = A(Foo).Baz; 2035 // [[p]] 2036 } 2037 )"; 2038 runDataflow( 2039 Code, 2040 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2041 ASTContext &ASTCtx) { 2042 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2043 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2044 2045 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2046 ASSERT_THAT(FooDecl, NotNull()); 2047 2048 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2049 ASSERT_THAT(BarDecl, NotNull()); 2050 2051 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2052 ASSERT_THAT(BazDecl, NotNull()); 2053 2054 const auto &FooVal = 2055 *cast<StructValue>(Env.getValue(*FooDecl, SkipPast::None)); 2056 const auto *BarVal = 2057 cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None)); 2058 EXPECT_EQ(BarVal, FooVal.getChild(*BazDecl)); 2059 }); 2060 } 2061 2062 TEST(TransferTest, StaticCast) { 2063 std::string Code = R"( 2064 void target(int Foo) { 2065 int Bar = static_cast<int>(Foo); 2066 // [[p]] 2067 } 2068 )"; 2069 runDataflow( 2070 Code, 2071 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2072 ASTContext &ASTCtx) { 2073 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2074 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2075 2076 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2077 ASSERT_THAT(FooDecl, NotNull()); 2078 2079 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2080 ASSERT_THAT(BarDecl, NotNull()); 2081 2082 const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None); 2083 const auto *BarVal = Env.getValue(*BarDecl, SkipPast::None); 2084 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 2085 EXPECT_TRUE(isa<IntegerValue>(BarVal)); 2086 EXPECT_EQ(FooVal, BarVal); 2087 }); 2088 } 2089 2090 TEST(TransferTest, IntegralCast) { 2091 std::string Code = R"( 2092 void target(int Foo) { 2093 long Bar = Foo; 2094 // [[p]] 2095 } 2096 )"; 2097 runDataflow( 2098 Code, 2099 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2100 ASTContext &ASTCtx) { 2101 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2102 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2103 2104 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2105 ASSERT_THAT(FooDecl, NotNull()); 2106 2107 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2108 ASSERT_THAT(BarDecl, NotNull()); 2109 2110 const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None); 2111 const auto *BarVal = Env.getValue(*BarDecl, SkipPast::None); 2112 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 2113 EXPECT_TRUE(isa<IntegerValue>(BarVal)); 2114 EXPECT_EQ(FooVal, BarVal); 2115 }); 2116 } 2117 2118 TEST(TransferTest, IntegraltoBooleanCast) { 2119 std::string Code = R"( 2120 void target(int Foo) { 2121 bool Bar = Foo; 2122 // [[p]] 2123 } 2124 )"; 2125 runDataflow( 2126 Code, 2127 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2128 ASTContext &ASTCtx) { 2129 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2130 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2131 2132 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2133 ASSERT_THAT(FooDecl, NotNull()); 2134 2135 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2136 ASSERT_THAT(BarDecl, NotNull()); 2137 2138 const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None); 2139 const auto *BarVal = Env.getValue(*BarDecl, SkipPast::None); 2140 EXPECT_TRUE(isa<IntegerValue>(FooVal)); 2141 EXPECT_TRUE(isa<BoolValue>(BarVal)); 2142 }); 2143 } 2144 2145 TEST(TransferTest, IntegralToBooleanCastFromBool) { 2146 std::string Code = R"( 2147 void target(bool Foo) { 2148 int Zab = Foo; 2149 bool Bar = Zab; 2150 // [[p]] 2151 } 2152 )"; 2153 runDataflow( 2154 Code, 2155 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2156 ASTContext &ASTCtx) { 2157 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2158 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2159 2160 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2161 ASSERT_THAT(FooDecl, NotNull()); 2162 2163 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2164 ASSERT_THAT(BarDecl, NotNull()); 2165 2166 const auto *FooVal = Env.getValue(*FooDecl, SkipPast::None); 2167 const auto *BarVal = Env.getValue(*BarDecl, SkipPast::None); 2168 EXPECT_TRUE(isa<BoolValue>(FooVal)); 2169 EXPECT_TRUE(isa<BoolValue>(BarVal)); 2170 EXPECT_EQ(FooVal, BarVal); 2171 }); 2172 } 2173 2174 TEST(TransferTest, NullToPointerCast) { 2175 std::string Code = R"( 2176 using my_nullptr_t = decltype(nullptr); 2177 struct Baz {}; 2178 void target() { 2179 int *FooX = nullptr; 2180 int *FooY = nullptr; 2181 bool **Bar = nullptr; 2182 Baz *Baz = nullptr; 2183 my_nullptr_t Null = 0; 2184 // [[p]] 2185 } 2186 )"; 2187 runDataflow( 2188 Code, 2189 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2190 ASTContext &ASTCtx) { 2191 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2192 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2193 2194 const ValueDecl *FooXDecl = findValueDecl(ASTCtx, "FooX"); 2195 ASSERT_THAT(FooXDecl, NotNull()); 2196 2197 const ValueDecl *FooYDecl = findValueDecl(ASTCtx, "FooY"); 2198 ASSERT_THAT(FooYDecl, NotNull()); 2199 2200 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2201 ASSERT_THAT(BarDecl, NotNull()); 2202 2203 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2204 ASSERT_THAT(BazDecl, NotNull()); 2205 2206 const ValueDecl *NullDecl = findValueDecl(ASTCtx, "Null"); 2207 ASSERT_THAT(NullDecl, NotNull()); 2208 2209 const auto *FooXVal = 2210 cast<PointerValue>(Env.getValue(*FooXDecl, SkipPast::None)); 2211 const auto *FooYVal = 2212 cast<PointerValue>(Env.getValue(*FooYDecl, SkipPast::None)); 2213 const auto *BarVal = 2214 cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None)); 2215 const auto *BazVal = 2216 cast<PointerValue>(Env.getValue(*BazDecl, SkipPast::None)); 2217 const auto *NullVal = 2218 cast<PointerValue>(Env.getValue(*NullDecl, SkipPast::None)); 2219 2220 EXPECT_EQ(FooXVal, FooYVal); 2221 EXPECT_NE(FooXVal, BarVal); 2222 EXPECT_NE(FooXVal, BazVal); 2223 EXPECT_NE(BarVal, BazVal); 2224 2225 const StorageLocation &FooPointeeLoc = FooXVal->getPointeeLoc(); 2226 EXPECT_TRUE(isa<ScalarStorageLocation>(FooPointeeLoc)); 2227 EXPECT_THAT(Env.getValue(FooPointeeLoc), IsNull()); 2228 2229 const StorageLocation &BarPointeeLoc = BarVal->getPointeeLoc(); 2230 EXPECT_TRUE(isa<ScalarStorageLocation>(BarPointeeLoc)); 2231 EXPECT_THAT(Env.getValue(BarPointeeLoc), IsNull()); 2232 2233 const StorageLocation &BazPointeeLoc = BazVal->getPointeeLoc(); 2234 EXPECT_TRUE(isa<AggregateStorageLocation>(BazPointeeLoc)); 2235 EXPECT_THAT(Env.getValue(BazPointeeLoc), IsNull()); 2236 2237 const StorageLocation &NullPointeeLoc = NullVal->getPointeeLoc(); 2238 EXPECT_TRUE(isa<ScalarStorageLocation>(NullPointeeLoc)); 2239 EXPECT_THAT(Env.getValue(NullPointeeLoc), IsNull()); 2240 }); 2241 } 2242 2243 TEST(TransferTest, NullToMemberPointerCast) { 2244 std::string Code = R"( 2245 struct Foo {}; 2246 void target(Foo *Foo) { 2247 int Foo::*MemberPointer = nullptr; 2248 // [[p]] 2249 } 2250 )"; 2251 runDataflow( 2252 Code, 2253 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2254 ASTContext &ASTCtx) { 2255 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2256 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2257 2258 const ValueDecl *MemberPointerDecl = 2259 findValueDecl(ASTCtx, "MemberPointer"); 2260 ASSERT_THAT(MemberPointerDecl, NotNull()); 2261 2262 const auto *MemberPointerVal = cast<PointerValue>( 2263 Env.getValue(*MemberPointerDecl, SkipPast::None)); 2264 2265 const StorageLocation &MemberLoc = MemberPointerVal->getPointeeLoc(); 2266 EXPECT_THAT(Env.getValue(MemberLoc), IsNull()); 2267 }); 2268 } 2269 2270 TEST(TransferTest, AddrOfValue) { 2271 std::string Code = R"( 2272 void target() { 2273 int Foo; 2274 int *Bar = &Foo; 2275 // [[p]] 2276 } 2277 )"; 2278 runDataflow( 2279 Code, 2280 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2281 ASTContext &ASTCtx) { 2282 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2283 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2284 2285 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2286 ASSERT_THAT(FooDecl, NotNull()); 2287 2288 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2289 ASSERT_THAT(BarDecl, NotNull()); 2290 2291 const auto *FooLoc = cast<ScalarStorageLocation>( 2292 Env.getStorageLocation(*FooDecl, SkipPast::None)); 2293 const auto *BarVal = 2294 cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None)); 2295 EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc); 2296 }); 2297 } 2298 2299 TEST(TransferTest, AddrOfReference) { 2300 std::string Code = R"( 2301 void target(int *Foo) { 2302 int *Bar = &(*Foo); 2303 // [[p]] 2304 } 2305 )"; 2306 runDataflow( 2307 Code, 2308 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2309 ASTContext &ASTCtx) { 2310 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2311 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2312 2313 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2314 ASSERT_THAT(FooDecl, NotNull()); 2315 2316 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2317 ASSERT_THAT(BarDecl, NotNull()); 2318 2319 const auto *FooVal = 2320 cast<PointerValue>(Env.getValue(*FooDecl, SkipPast::None)); 2321 const auto *BarVal = 2322 cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None)); 2323 EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc()); 2324 }); 2325 } 2326 2327 TEST(TransferTest, DerefDependentPtr) { 2328 std::string Code = R"( 2329 template <typename T> 2330 void target(T *Foo) { 2331 T &Bar = *Foo; 2332 /*[[p]]*/ 2333 } 2334 )"; 2335 runDataflow( 2336 Code, 2337 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2338 ASTContext &ASTCtx) { 2339 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2340 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2341 2342 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2343 ASSERT_THAT(FooDecl, NotNull()); 2344 2345 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2346 ASSERT_THAT(BarDecl, NotNull()); 2347 2348 const auto *FooVal = 2349 cast<PointerValue>(Env.getValue(*FooDecl, SkipPast::None)); 2350 const auto *BarVal = 2351 cast<ReferenceValue>(Env.getValue(*BarDecl, SkipPast::None)); 2352 EXPECT_EQ(&BarVal->getReferentLoc(), &FooVal->getPointeeLoc()); 2353 }); 2354 } 2355 2356 TEST(TransferTest, VarDeclInitAssignConditionalOperator) { 2357 std::string Code = R"( 2358 struct A {}; 2359 2360 void target(A Foo, A Bar, bool Cond) { 2361 A Baz = Cond ? Foo : Bar; 2362 /*[[p]]*/ 2363 } 2364 )"; 2365 runDataflow( 2366 Code, 2367 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2368 ASTContext &ASTCtx) { 2369 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2370 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2371 2372 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2373 ASSERT_THAT(FooDecl, NotNull()); 2374 2375 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2376 ASSERT_THAT(BarDecl, NotNull()); 2377 2378 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2379 ASSERT_THAT(BazDecl, NotNull()); 2380 2381 const auto *FooVal = 2382 cast<StructValue>(Env.getValue(*FooDecl, SkipPast::None)); 2383 const auto *BarVal = 2384 cast<StructValue>(Env.getValue(*BarDecl, SkipPast::None)); 2385 2386 const auto *BazVal = 2387 dyn_cast<StructValue>(Env.getValue(*BazDecl, SkipPast::None)); 2388 ASSERT_THAT(BazVal, NotNull()); 2389 2390 EXPECT_NE(BazVal, FooVal); 2391 EXPECT_NE(BazVal, BarVal); 2392 }); 2393 } 2394 2395 TEST(TransferTest, VarDeclInDoWhile) { 2396 std::string Code = R"( 2397 void target(int *Foo) { 2398 do { 2399 int Bar = *Foo; 2400 } while (true); 2401 (void)0; 2402 /*[[p]]*/ 2403 } 2404 )"; 2405 runDataflow( 2406 Code, 2407 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2408 ASTContext &ASTCtx) { 2409 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2410 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2411 2412 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2413 ASSERT_THAT(FooDecl, NotNull()); 2414 2415 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2416 ASSERT_THAT(BarDecl, NotNull()); 2417 2418 const auto *FooVal = 2419 cast<PointerValue>(Env.getValue(*FooDecl, SkipPast::None)); 2420 const auto *FooPointeeVal = 2421 cast<IntegerValue>(Env.getValue(FooVal->getPointeeLoc())); 2422 2423 const auto *BarVal = dyn_cast_or_null<IntegerValue>( 2424 Env.getValue(*BarDecl, SkipPast::None)); 2425 ASSERT_THAT(BarVal, NotNull()); 2426 2427 EXPECT_EQ(BarVal, FooPointeeVal); 2428 }); 2429 } 2430 2431 TEST(TransferTest, AggregateInitialization) { 2432 std::string BracesCode = R"( 2433 struct A { 2434 int Foo; 2435 }; 2436 2437 struct B { 2438 int Bar; 2439 A Baz; 2440 int Qux; 2441 }; 2442 2443 void target(int BarArg, int FooArg, int QuxArg) { 2444 B Quux{BarArg, {FooArg}, QuxArg}; 2445 /*[[p]]*/ 2446 } 2447 )"; 2448 std::string BraceEllisionCode = R"( 2449 struct A { 2450 int Foo; 2451 }; 2452 2453 struct B { 2454 int Bar; 2455 A Baz; 2456 int Qux; 2457 }; 2458 2459 void target(int BarArg, int FooArg, int QuxArg) { 2460 B Quux = {BarArg, FooArg, QuxArg}; 2461 /*[[p]]*/ 2462 } 2463 )"; 2464 for (const std::string &Code : {BracesCode, BraceEllisionCode}) { 2465 runDataflow( 2466 Code, 2467 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2468 ASTContext &ASTCtx) { 2469 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2470 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2471 2472 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2473 ASSERT_THAT(FooDecl, NotNull()); 2474 2475 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2476 ASSERT_THAT(BarDecl, NotNull()); 2477 2478 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2479 ASSERT_THAT(BazDecl, NotNull()); 2480 2481 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 2482 ASSERT_THAT(QuxDecl, NotNull()); 2483 2484 const ValueDecl *FooArgDecl = findValueDecl(ASTCtx, "FooArg"); 2485 ASSERT_THAT(FooArgDecl, NotNull()); 2486 2487 const ValueDecl *BarArgDecl = findValueDecl(ASTCtx, "BarArg"); 2488 ASSERT_THAT(BarArgDecl, NotNull()); 2489 2490 const ValueDecl *QuxArgDecl = findValueDecl(ASTCtx, "QuxArg"); 2491 ASSERT_THAT(QuxArgDecl, NotNull()); 2492 2493 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); 2494 ASSERT_THAT(QuuxDecl, NotNull()); 2495 2496 const auto *FooArgVal = 2497 cast<IntegerValue>(Env.getValue(*FooArgDecl, SkipPast::None)); 2498 const auto *BarArgVal = 2499 cast<IntegerValue>(Env.getValue(*BarArgDecl, SkipPast::None)); 2500 const auto *QuxArgVal = 2501 cast<IntegerValue>(Env.getValue(*QuxArgDecl, SkipPast::None)); 2502 2503 const auto *QuuxVal = 2504 cast<StructValue>(Env.getValue(*QuuxDecl, SkipPast::None)); 2505 ASSERT_THAT(QuuxVal, NotNull()); 2506 2507 const auto *BazVal = cast<StructValue>(QuuxVal->getChild(*BazDecl)); 2508 ASSERT_THAT(BazVal, NotNull()); 2509 2510 EXPECT_EQ(QuuxVal->getChild(*BarDecl), BarArgVal); 2511 EXPECT_EQ(BazVal->getChild(*FooDecl), FooArgVal); 2512 EXPECT_EQ(QuuxVal->getChild(*QuxDecl), QuxArgVal); 2513 }); 2514 } 2515 } 2516 2517 TEST(TransferTest, AssignToUnionMember) { 2518 std::string Code = R"( 2519 union A { 2520 int Foo; 2521 }; 2522 2523 void target(int Bar) { 2524 A Baz; 2525 Baz.Foo = Bar; 2526 // [[p]] 2527 } 2528 )"; 2529 runDataflow( 2530 Code, 2531 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2532 ASTContext &ASTCtx) { 2533 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2534 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2535 2536 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2537 ASSERT_THAT(BazDecl, NotNull()); 2538 ASSERT_TRUE(BazDecl->getType()->isUnionType()); 2539 2540 const auto *BazLoc = dyn_cast_or_null<AggregateStorageLocation>( 2541 Env.getStorageLocation(*BazDecl, SkipPast::None)); 2542 ASSERT_THAT(BazLoc, NotNull()); 2543 2544 // FIXME: Add support for union types. 2545 EXPECT_THAT(Env.getValue(*BazLoc), IsNull()); 2546 }); 2547 } 2548 2549 TEST(TransferTest, AssignFromBoolLiteral) { 2550 std::string Code = R"( 2551 void target() { 2552 bool Foo = true; 2553 bool Bar = false; 2554 // [[p]] 2555 } 2556 )"; 2557 runDataflow( 2558 Code, 2559 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2560 ASTContext &ASTCtx) { 2561 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2562 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2563 2564 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2565 ASSERT_THAT(FooDecl, NotNull()); 2566 2567 const auto *FooVal = dyn_cast_or_null<AtomicBoolValue>( 2568 Env.getValue(*FooDecl, SkipPast::None)); 2569 ASSERT_THAT(FooVal, NotNull()); 2570 2571 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2572 ASSERT_THAT(BarDecl, NotNull()); 2573 2574 const auto *BarVal = dyn_cast_or_null<AtomicBoolValue>( 2575 Env.getValue(*BarDecl, SkipPast::None)); 2576 ASSERT_THAT(BarVal, NotNull()); 2577 2578 EXPECT_EQ(FooVal, &Env.getBoolLiteralValue(true)); 2579 EXPECT_EQ(BarVal, &Env.getBoolLiteralValue(false)); 2580 }); 2581 } 2582 2583 TEST(TransferTest, AssignFromCompositeBoolExpression) { 2584 { 2585 std::string Code = R"( 2586 void target(bool Foo, bool Bar, bool Qux) { 2587 bool Baz = (Foo) && (Bar || Qux); 2588 // [[p]] 2589 } 2590 )"; 2591 runDataflow( 2592 Code, 2593 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2594 ASTContext &ASTCtx) { 2595 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2596 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2597 2598 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2599 ASSERT_THAT(FooDecl, NotNull()); 2600 2601 const auto *FooVal = dyn_cast_or_null<BoolValue>( 2602 Env.getValue(*FooDecl, SkipPast::None)); 2603 ASSERT_THAT(FooVal, NotNull()); 2604 2605 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2606 ASSERT_THAT(BarDecl, NotNull()); 2607 2608 const auto *BarVal = dyn_cast_or_null<BoolValue>( 2609 Env.getValue(*BarDecl, SkipPast::None)); 2610 ASSERT_THAT(BarVal, NotNull()); 2611 2612 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 2613 ASSERT_THAT(QuxDecl, NotNull()); 2614 2615 const auto *QuxVal = dyn_cast_or_null<BoolValue>( 2616 Env.getValue(*QuxDecl, SkipPast::None)); 2617 ASSERT_THAT(QuxVal, NotNull()); 2618 2619 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2620 ASSERT_THAT(BazDecl, NotNull()); 2621 2622 const auto *BazVal = dyn_cast_or_null<ConjunctionValue>( 2623 Env.getValue(*BazDecl, SkipPast::None)); 2624 ASSERT_THAT(BazVal, NotNull()); 2625 EXPECT_EQ(&BazVal->getLeftSubValue(), FooVal); 2626 2627 const auto *BazRightSubValVal = 2628 cast<DisjunctionValue>(&BazVal->getRightSubValue()); 2629 EXPECT_EQ(&BazRightSubValVal->getLeftSubValue(), BarVal); 2630 EXPECT_EQ(&BazRightSubValVal->getRightSubValue(), QuxVal); 2631 }); 2632 } 2633 2634 { 2635 std::string Code = R"( 2636 void target(bool Foo, bool Bar, bool Qux) { 2637 bool Baz = (Foo && Qux) || (Bar); 2638 // [[p]] 2639 } 2640 )"; 2641 runDataflow( 2642 Code, 2643 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2644 ASTContext &ASTCtx) { 2645 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2646 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2647 2648 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2649 ASSERT_THAT(FooDecl, NotNull()); 2650 2651 const auto *FooVal = dyn_cast_or_null<BoolValue>( 2652 Env.getValue(*FooDecl, SkipPast::None)); 2653 ASSERT_THAT(FooVal, NotNull()); 2654 2655 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2656 ASSERT_THAT(BarDecl, NotNull()); 2657 2658 const auto *BarVal = dyn_cast_or_null<BoolValue>( 2659 Env.getValue(*BarDecl, SkipPast::None)); 2660 ASSERT_THAT(BarVal, NotNull()); 2661 2662 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 2663 ASSERT_THAT(QuxDecl, NotNull()); 2664 2665 const auto *QuxVal = dyn_cast_or_null<BoolValue>( 2666 Env.getValue(*QuxDecl, SkipPast::None)); 2667 ASSERT_THAT(QuxVal, NotNull()); 2668 2669 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 2670 ASSERT_THAT(BazDecl, NotNull()); 2671 2672 const auto *BazVal = dyn_cast_or_null<DisjunctionValue>( 2673 Env.getValue(*BazDecl, SkipPast::None)); 2674 ASSERT_THAT(BazVal, NotNull()); 2675 2676 const auto *BazLeftSubValVal = 2677 cast<ConjunctionValue>(&BazVal->getLeftSubValue()); 2678 EXPECT_EQ(&BazLeftSubValVal->getLeftSubValue(), FooVal); 2679 EXPECT_EQ(&BazLeftSubValVal->getRightSubValue(), QuxVal); 2680 2681 EXPECT_EQ(&BazVal->getRightSubValue(), BarVal); 2682 }); 2683 } 2684 2685 { 2686 std::string Code = R"( 2687 void target(bool A, bool B, bool C, bool D) { 2688 bool Foo = ((A && B) && C) && D; 2689 // [[p]] 2690 } 2691 )"; 2692 runDataflow( 2693 Code, 2694 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2695 ASTContext &ASTCtx) { 2696 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2697 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2698 2699 const ValueDecl *ADecl = findValueDecl(ASTCtx, "A"); 2700 ASSERT_THAT(ADecl, NotNull()); 2701 2702 const auto *AVal = 2703 dyn_cast_or_null<BoolValue>(Env.getValue(*ADecl, SkipPast::None)); 2704 ASSERT_THAT(AVal, NotNull()); 2705 2706 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B"); 2707 ASSERT_THAT(BDecl, NotNull()); 2708 2709 const auto *BVal = 2710 dyn_cast_or_null<BoolValue>(Env.getValue(*BDecl, SkipPast::None)); 2711 ASSERT_THAT(BVal, NotNull()); 2712 2713 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C"); 2714 ASSERT_THAT(CDecl, NotNull()); 2715 2716 const auto *CVal = 2717 dyn_cast_or_null<BoolValue>(Env.getValue(*CDecl, SkipPast::None)); 2718 ASSERT_THAT(CVal, NotNull()); 2719 2720 const ValueDecl *DDecl = findValueDecl(ASTCtx, "D"); 2721 ASSERT_THAT(DDecl, NotNull()); 2722 2723 const auto *DVal = 2724 dyn_cast_or_null<BoolValue>(Env.getValue(*DDecl, SkipPast::None)); 2725 ASSERT_THAT(DVal, NotNull()); 2726 2727 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2728 ASSERT_THAT(FooDecl, NotNull()); 2729 2730 const auto *FooVal = dyn_cast_or_null<ConjunctionValue>( 2731 Env.getValue(*FooDecl, SkipPast::None)); 2732 ASSERT_THAT(FooVal, NotNull()); 2733 2734 const auto &FooLeftSubVal = 2735 cast<ConjunctionValue>(FooVal->getLeftSubValue()); 2736 const auto &FooLeftLeftSubVal = 2737 cast<ConjunctionValue>(FooLeftSubVal.getLeftSubValue()); 2738 EXPECT_EQ(&FooLeftLeftSubVal.getLeftSubValue(), AVal); 2739 EXPECT_EQ(&FooLeftLeftSubVal.getRightSubValue(), BVal); 2740 EXPECT_EQ(&FooLeftSubVal.getRightSubValue(), CVal); 2741 EXPECT_EQ(&FooVal->getRightSubValue(), DVal); 2742 }); 2743 } 2744 } 2745 2746 TEST(TransferTest, AssignFromBoolNegation) { 2747 std::string Code = R"( 2748 void target() { 2749 bool Foo = true; 2750 bool Bar = !(Foo); 2751 // [[p]] 2752 } 2753 )"; 2754 runDataflow( 2755 Code, 2756 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2757 ASTContext &ASTCtx) { 2758 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2759 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2760 2761 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2762 ASSERT_THAT(FooDecl, NotNull()); 2763 2764 const auto *FooVal = dyn_cast_or_null<AtomicBoolValue>( 2765 Env.getValue(*FooDecl, SkipPast::None)); 2766 ASSERT_THAT(FooVal, NotNull()); 2767 2768 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2769 ASSERT_THAT(BarDecl, NotNull()); 2770 2771 const auto *BarVal = dyn_cast_or_null<NegationValue>( 2772 Env.getValue(*BarDecl, SkipPast::None)); 2773 ASSERT_THAT(BarVal, NotNull()); 2774 2775 EXPECT_EQ(&BarVal->getSubVal(), FooVal); 2776 }); 2777 } 2778 2779 TEST(TransferTest, BuiltinExpect) { 2780 std::string Code = R"( 2781 void target(long Foo) { 2782 long Bar = __builtin_expect(Foo, true); 2783 /*[[p]]*/ 2784 } 2785 )"; 2786 runDataflow( 2787 Code, 2788 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2789 ASTContext &ASTCtx) { 2790 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2791 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2792 2793 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2794 ASSERT_THAT(FooDecl, NotNull()); 2795 2796 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2797 ASSERT_THAT(BarDecl, NotNull()); 2798 2799 EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), 2800 Env.getValue(*BarDecl, SkipPast::None)); 2801 }); 2802 } 2803 2804 // `__builtin_expect` takes and returns a `long` argument, so other types 2805 // involve casts. This verifies that we identify the input and output in that 2806 // case. 2807 TEST(TransferTest, BuiltinExpectBoolArg) { 2808 std::string Code = R"( 2809 void target(bool Foo) { 2810 bool Bar = __builtin_expect(Foo, true); 2811 /*[[p]]*/ 2812 } 2813 )"; 2814 runDataflow( 2815 Code, 2816 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2817 ASTContext &ASTCtx) { 2818 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2819 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2820 2821 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2822 ASSERT_THAT(FooDecl, NotNull()); 2823 2824 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2825 ASSERT_THAT(BarDecl, NotNull()); 2826 2827 EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), 2828 Env.getValue(*BarDecl, SkipPast::None)); 2829 }); 2830 } 2831 2832 TEST(TransferTest, BuiltinUnreachable) { 2833 std::string Code = R"( 2834 void target(bool Foo) { 2835 bool Bar = false; 2836 if (Foo) 2837 Bar = Foo; 2838 else 2839 __builtin_unreachable(); 2840 (void)0; 2841 /*[[p]]*/ 2842 } 2843 )"; 2844 runDataflow( 2845 Code, 2846 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2847 ASTContext &ASTCtx) { 2848 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2849 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2850 2851 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2852 ASSERT_THAT(FooDecl, NotNull()); 2853 2854 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2855 ASSERT_THAT(BarDecl, NotNull()); 2856 2857 // `__builtin_unreachable` promises that the code is 2858 // unreachable, so the compiler treats the "then" branch as the 2859 // only possible predecessor of this statement. 2860 EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), 2861 Env.getValue(*BarDecl, SkipPast::None)); 2862 }); 2863 } 2864 2865 TEST(TransferTest, BuiltinTrap) { 2866 std::string Code = R"( 2867 void target(bool Foo) { 2868 bool Bar = false; 2869 if (Foo) 2870 Bar = Foo; 2871 else 2872 __builtin_trap(); 2873 (void)0; 2874 /*[[p]]*/ 2875 } 2876 )"; 2877 runDataflow( 2878 Code, 2879 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2880 ASTContext &ASTCtx) { 2881 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2882 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2883 2884 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2885 ASSERT_THAT(FooDecl, NotNull()); 2886 2887 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2888 ASSERT_THAT(BarDecl, NotNull()); 2889 2890 // `__builtin_trap` ensures program termination, so only the 2891 // "then" branch is a predecessor of this statement. 2892 EXPECT_EQ(Env.getValue(*FooDecl, SkipPast::None), 2893 Env.getValue(*BarDecl, SkipPast::None)); 2894 }); 2895 } 2896 2897 TEST(TransferTest, BuiltinDebugTrap) { 2898 std::string Code = R"( 2899 void target(bool Foo) { 2900 bool Bar = false; 2901 if (Foo) 2902 Bar = Foo; 2903 else 2904 __builtin_debugtrap(); 2905 (void)0; 2906 /*[[p]]*/ 2907 } 2908 )"; 2909 runDataflow( 2910 Code, 2911 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2912 ASTContext &ASTCtx) { 2913 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2914 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2915 2916 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2917 ASSERT_THAT(FooDecl, NotNull()); 2918 2919 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2920 ASSERT_THAT(BarDecl, NotNull()); 2921 2922 // `__builtin_debugtrap` doesn't ensure program termination. 2923 EXPECT_NE(Env.getValue(*FooDecl, SkipPast::None), 2924 Env.getValue(*BarDecl, SkipPast::None)); 2925 }); 2926 } 2927 2928 TEST(TransferTest, StaticIntSingleVarDecl) { 2929 std::string Code = R"( 2930 void target() { 2931 static int Foo; 2932 // [[p]] 2933 } 2934 )"; 2935 runDataflow( 2936 Code, 2937 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2938 ASTContext &ASTCtx) { 2939 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2940 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2941 2942 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2943 ASSERT_THAT(FooDecl, NotNull()); 2944 2945 const StorageLocation *FooLoc = 2946 Env.getStorageLocation(*FooDecl, SkipPast::None); 2947 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 2948 2949 const Value *FooVal = Env.getValue(*FooLoc); 2950 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 2951 }); 2952 } 2953 2954 TEST(TransferTest, StaticIntGroupVarDecl) { 2955 std::string Code = R"( 2956 void target() { 2957 static int Foo, Bar; 2958 (void)0; 2959 // [[p]] 2960 } 2961 )"; 2962 runDataflow( 2963 Code, 2964 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 2965 ASTContext &ASTCtx) { 2966 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 2967 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 2968 2969 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 2970 ASSERT_THAT(FooDecl, NotNull()); 2971 2972 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 2973 ASSERT_THAT(BarDecl, NotNull()); 2974 2975 const StorageLocation *FooLoc = 2976 Env.getStorageLocation(*FooDecl, SkipPast::None); 2977 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 2978 2979 const StorageLocation *BarLoc = 2980 Env.getStorageLocation(*BarDecl, SkipPast::None); 2981 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc)); 2982 2983 const Value *FooVal = Env.getValue(*FooLoc); 2984 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 2985 2986 const Value *BarVal = Env.getValue(*BarLoc); 2987 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 2988 2989 EXPECT_NE(FooVal, BarVal); 2990 }); 2991 } 2992 2993 TEST(TransferTest, GlobalIntVarDecl) { 2994 std::string Code = R"( 2995 static int Foo; 2996 2997 void target() { 2998 int Bar = Foo; 2999 int Baz = Foo; 3000 // [[p]] 3001 } 3002 )"; 3003 runDataflow( 3004 Code, 3005 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3006 ASTContext &ASTCtx) { 3007 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3008 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3009 3010 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3011 ASSERT_THAT(BarDecl, NotNull()); 3012 3013 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3014 ASSERT_THAT(BazDecl, NotNull()); 3015 3016 const Value *BarVal = 3017 cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None)); 3018 const Value *BazVal = 3019 cast<IntegerValue>(Env.getValue(*BazDecl, SkipPast::None)); 3020 EXPECT_EQ(BarVal, BazVal); 3021 }); 3022 } 3023 3024 TEST(TransferTest, StaticMemberIntVarDecl) { 3025 std::string Code = R"( 3026 struct A { 3027 static int Foo; 3028 }; 3029 3030 void target(A a) { 3031 int Bar = a.Foo; 3032 int Baz = a.Foo; 3033 // [[p]] 3034 } 3035 )"; 3036 runDataflow( 3037 Code, 3038 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3039 ASTContext &ASTCtx) { 3040 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3041 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3042 3043 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3044 ASSERT_THAT(BarDecl, NotNull()); 3045 3046 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3047 ASSERT_THAT(BazDecl, NotNull()); 3048 3049 const Value *BarVal = 3050 cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None)); 3051 const Value *BazVal = 3052 cast<IntegerValue>(Env.getValue(*BazDecl, SkipPast::None)); 3053 EXPECT_EQ(BarVal, BazVal); 3054 }); 3055 } 3056 3057 TEST(TransferTest, StaticMemberRefVarDecl) { 3058 std::string Code = R"( 3059 struct A { 3060 static int &Foo; 3061 }; 3062 3063 void target(A a) { 3064 int Bar = a.Foo; 3065 int Baz = a.Foo; 3066 // [[p]] 3067 } 3068 )"; 3069 runDataflow( 3070 Code, 3071 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3072 ASTContext &ASTCtx) { 3073 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3074 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3075 3076 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3077 ASSERT_THAT(BarDecl, NotNull()); 3078 3079 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3080 ASSERT_THAT(BazDecl, NotNull()); 3081 3082 const Value *BarVal = 3083 cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None)); 3084 const Value *BazVal = 3085 cast<IntegerValue>(Env.getValue(*BazDecl, SkipPast::None)); 3086 EXPECT_EQ(BarVal, BazVal); 3087 }); 3088 } 3089 3090 TEST(TransferTest, AssignMemberBeforeCopy) { 3091 std::string Code = R"( 3092 struct A { 3093 int Foo; 3094 }; 3095 3096 void target() { 3097 A A1; 3098 A A2; 3099 int Bar; 3100 A1.Foo = Bar; 3101 A2 = A1; 3102 // [[p]] 3103 } 3104 )"; 3105 runDataflow( 3106 Code, 3107 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3108 ASTContext &ASTCtx) { 3109 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3110 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3111 3112 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3113 ASSERT_THAT(FooDecl, NotNull()); 3114 3115 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3116 ASSERT_THAT(BarDecl, NotNull()); 3117 3118 const ValueDecl *A1Decl = findValueDecl(ASTCtx, "A1"); 3119 ASSERT_THAT(A1Decl, NotNull()); 3120 3121 const ValueDecl *A2Decl = findValueDecl(ASTCtx, "A2"); 3122 ASSERT_THAT(A2Decl, NotNull()); 3123 3124 const auto *BarVal = 3125 cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None)); 3126 3127 const auto *A2Val = 3128 cast<StructValue>(Env.getValue(*A2Decl, SkipPast::None)); 3129 EXPECT_EQ(A2Val->getChild(*FooDecl), BarVal); 3130 }); 3131 } 3132 3133 TEST(TransferTest, BooleanEquality) { 3134 std::string Code = R"( 3135 void target(bool Bar) { 3136 bool Foo = true; 3137 if (Bar == Foo) { 3138 (void)0; 3139 /*[[p-then]]*/ 3140 } else { 3141 (void)0; 3142 /*[[p-else]]*/ 3143 } 3144 } 3145 )"; 3146 runDataflow( 3147 Code, 3148 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3149 ASTContext &ASTCtx) { 3150 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else")); 3151 const Environment &EnvThen = 3152 getEnvironmentAtAnnotation(Results, "p-then"); 3153 const Environment &EnvElse = 3154 getEnvironmentAtAnnotation(Results, "p-else"); 3155 3156 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3157 ASSERT_THAT(BarDecl, NotNull()); 3158 3159 auto &BarValThen = 3160 *cast<BoolValue>(EnvThen.getValue(*BarDecl, SkipPast::None)); 3161 EXPECT_TRUE(EnvThen.flowConditionImplies(BarValThen)); 3162 3163 auto &BarValElse = 3164 *cast<BoolValue>(EnvElse.getValue(*BarDecl, SkipPast::None)); 3165 EXPECT_FALSE(EnvElse.flowConditionImplies(BarValElse)); 3166 }); 3167 } 3168 3169 TEST(TransferTest, BooleanInequality) { 3170 std::string Code = R"( 3171 void target(bool Bar) { 3172 bool Foo = true; 3173 if (Bar != Foo) { 3174 (void)0; 3175 /*[[p-then]]*/ 3176 } else { 3177 (void)0; 3178 /*[[p-else]]*/ 3179 } 3180 } 3181 )"; 3182 runDataflow( 3183 Code, 3184 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3185 ASTContext &ASTCtx) { 3186 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else")); 3187 const Environment &EnvThen = 3188 getEnvironmentAtAnnotation(Results, "p-then"); 3189 const Environment &EnvElse = 3190 getEnvironmentAtAnnotation(Results, "p-else"); 3191 3192 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3193 ASSERT_THAT(BarDecl, NotNull()); 3194 3195 auto &BarValThen = 3196 *cast<BoolValue>(EnvThen.getValue(*BarDecl, SkipPast::None)); 3197 EXPECT_FALSE(EnvThen.flowConditionImplies(BarValThen)); 3198 3199 auto &BarValElse = 3200 *cast<BoolValue>(EnvElse.getValue(*BarDecl, SkipPast::None)); 3201 EXPECT_TRUE(EnvElse.flowConditionImplies(BarValElse)); 3202 }); 3203 } 3204 3205 TEST(TransferTest, CorrelatedBranches) { 3206 std::string Code = R"( 3207 void target(bool B, bool C) { 3208 if (B) { 3209 return; 3210 } 3211 (void)0; 3212 /*[[p0]]*/ 3213 if (C) { 3214 B = true; 3215 /*[[p1]]*/ 3216 } 3217 if (B) { 3218 (void)0; 3219 /*[[p2]]*/ 3220 } 3221 } 3222 )"; 3223 runDataflow( 3224 Code, 3225 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3226 ASTContext &ASTCtx) { 3227 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p0", "p1", "p2")); 3228 3229 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C"); 3230 ASSERT_THAT(CDecl, NotNull()); 3231 3232 { 3233 const Environment &Env = getEnvironmentAtAnnotation(Results, "p0"); 3234 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B"); 3235 ASSERT_THAT(BDecl, NotNull()); 3236 auto &BVal = *cast<BoolValue>(Env.getValue(*BDecl, SkipPast::None)); 3237 3238 EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(BVal))); 3239 } 3240 3241 { 3242 const Environment &Env = getEnvironmentAtAnnotation(Results, "p1"); 3243 auto &CVal = *cast<BoolValue>(Env.getValue(*CDecl, SkipPast::None)); 3244 EXPECT_TRUE(Env.flowConditionImplies(CVal)); 3245 } 3246 3247 { 3248 const Environment &Env = getEnvironmentAtAnnotation(Results, "p2"); 3249 auto &CVal = *cast<BoolValue>(Env.getValue(*CDecl, SkipPast::None)); 3250 EXPECT_TRUE(Env.flowConditionImplies(CVal)); 3251 } 3252 }); 3253 } 3254 3255 TEST(TransferTest, LoopWithAssignmentConverges) { 3256 std::string Code = R"( 3257 bool foo(); 3258 3259 void target() { 3260 do { 3261 bool Bar = foo(); 3262 if (Bar) break; 3263 (void)Bar; 3264 /*[[p]]*/ 3265 } while (true); 3266 } 3267 )"; 3268 // The key property that we are verifying is implicit in `runDataflow` -- 3269 // namely, that the analysis succeeds, rather than hitting the maximum number 3270 // of iterations. 3271 runDataflow( 3272 Code, 3273 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3274 ASTContext &ASTCtx) { 3275 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3276 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3277 3278 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3279 ASSERT_THAT(BarDecl, NotNull()); 3280 3281 auto &BarVal = *cast<BoolValue>(Env.getValue(*BarDecl, SkipPast::None)); 3282 EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(BarVal))); 3283 }); 3284 } 3285 3286 TEST(TransferTest, LoopWithStagedAssignments) { 3287 std::string Code = R"( 3288 bool foo(); 3289 3290 void target() { 3291 bool Bar = false; 3292 bool Err = false; 3293 while (foo()) { 3294 if (Bar) 3295 Err = true; 3296 Bar = true; 3297 /*[[p]]*/ 3298 } 3299 } 3300 )"; 3301 runDataflow( 3302 Code, 3303 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3304 ASTContext &ASTCtx) { 3305 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3306 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3307 3308 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3309 ASSERT_THAT(BarDecl, NotNull()); 3310 const ValueDecl *ErrDecl = findValueDecl(ASTCtx, "Err"); 3311 ASSERT_THAT(ErrDecl, NotNull()); 3312 3313 auto &BarVal = *cast<BoolValue>(Env.getValue(*BarDecl, SkipPast::None)); 3314 auto &ErrVal = *cast<BoolValue>(Env.getValue(*ErrDecl, SkipPast::None)); 3315 EXPECT_TRUE(Env.flowConditionImplies(BarVal)); 3316 // An unsound analysis, for example only evaluating the loop once, can 3317 // conclude that `Err` is false. So, we test that this conclusion is not 3318 // reached. 3319 EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(ErrVal))); 3320 }); 3321 } 3322 3323 TEST(TransferTest, LoopWithReferenceAssignmentConverges) { 3324 std::string Code = R"( 3325 bool &foo(); 3326 3327 void target() { 3328 do { 3329 bool& Bar = foo(); 3330 if (Bar) break; 3331 (void)Bar; 3332 /*[[p]]*/ 3333 } while (true); 3334 } 3335 )"; 3336 // The key property that we are verifying is that the analysis succeeds, 3337 // rather than hitting the maximum number of iterations. 3338 runDataflow( 3339 Code, 3340 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3341 ASTContext &ASTCtx) { 3342 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3343 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3344 3345 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3346 ASSERT_THAT(BarDecl, NotNull()); 3347 3348 auto &BarVal = 3349 *cast<BoolValue>(Env.getValue(*BarDecl, SkipPast::Reference)); 3350 EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(BarVal))); 3351 }); 3352 } 3353 3354 TEST(TransferTest, LoopWithStructReferenceAssignmentConverges) { 3355 std::string Code = R"( 3356 struct Lookup { 3357 int x; 3358 }; 3359 3360 void target(Lookup val, bool b) { 3361 const Lookup* l = nullptr; 3362 while (b) { 3363 l = &val; 3364 /*[[p-inner]]*/ 3365 } 3366 (void)0; 3367 /*[[p-outer]]*/ 3368 } 3369 )"; 3370 // The key property that we are verifying is implicit in `runDataflow` -- 3371 // namely, that the analysis succeeds, rather than hitting the maximum number 3372 // of iterations. 3373 runDataflow( 3374 Code, 3375 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3376 ASTContext &ASTCtx) { 3377 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-inner", "p-outer")); 3378 const Environment &InnerEnv = 3379 getEnvironmentAtAnnotation(Results, "p-inner"); 3380 const Environment &OuterEnv = 3381 getEnvironmentAtAnnotation(Results, "p-outer"); 3382 3383 const ValueDecl *ValDecl = findValueDecl(ASTCtx, "val"); 3384 ASSERT_THAT(ValDecl, NotNull()); 3385 3386 const ValueDecl *LDecl = findValueDecl(ASTCtx, "l"); 3387 ASSERT_THAT(LDecl, NotNull()); 3388 3389 // Inner. 3390 auto *LVal = 3391 dyn_cast<PointerValue>(InnerEnv.getValue(*LDecl, SkipPast::None)); 3392 ASSERT_THAT(LVal, NotNull()); 3393 3394 EXPECT_EQ(&LVal->getPointeeLoc(), 3395 InnerEnv.getStorageLocation(*ValDecl, SkipPast::Reference)); 3396 3397 // Outer. 3398 LVal = 3399 dyn_cast<PointerValue>(OuterEnv.getValue(*LDecl, SkipPast::None)); 3400 ASSERT_THAT(LVal, NotNull()); 3401 3402 // The loop body may not have been executed, so we should not conclude 3403 // that `l` points to `val`. 3404 EXPECT_NE(&LVal->getPointeeLoc(), 3405 OuterEnv.getStorageLocation(*ValDecl, SkipPast::Reference)); 3406 }); 3407 } 3408 3409 TEST(TransferTest, DoesNotCrashOnUnionThisExpr) { 3410 std::string Code = R"( 3411 union Union { 3412 int A; 3413 float B; 3414 }; 3415 3416 void foo() { 3417 Union A; 3418 Union B; 3419 A = B; 3420 } 3421 )"; 3422 // This is a crash regression test when calling the transfer function on a 3423 // `CXXThisExpr` that refers to a union. 3424 runDataflow( 3425 Code, 3426 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &, 3427 ASTContext &) {}, 3428 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator="); 3429 } 3430 3431 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToRefs) { 3432 std::string Code = R"( 3433 struct A { 3434 int Foo; 3435 int Bar; 3436 }; 3437 3438 void target() { 3439 int Qux; 3440 A Baz; 3441 Baz.Foo = Qux; 3442 auto &FooRef = Baz.Foo; 3443 auto &BarRef = Baz.Bar; 3444 auto &[BoundFooRef, BoundBarRef] = Baz; 3445 // [[p]] 3446 } 3447 )"; 3448 runDataflow( 3449 Code, 3450 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3451 ASTContext &ASTCtx) { 3452 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3453 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3454 3455 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 3456 ASSERT_THAT(FooRefDecl, NotNull()); 3457 3458 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 3459 ASSERT_THAT(BarRefDecl, NotNull()); 3460 3461 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 3462 ASSERT_THAT(QuxDecl, NotNull()); 3463 3464 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef"); 3465 ASSERT_THAT(BoundFooRefDecl, NotNull()); 3466 3467 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef"); 3468 ASSERT_THAT(BoundBarRefDecl, NotNull()); 3469 3470 const StorageLocation *FooRefLoc = 3471 Env.getStorageLocation(*FooRefDecl, SkipPast::Reference); 3472 ASSERT_THAT(FooRefLoc, NotNull()); 3473 3474 const StorageLocation *BarRefLoc = 3475 Env.getStorageLocation(*BarRefDecl, SkipPast::Reference); 3476 ASSERT_THAT(BarRefLoc, NotNull()); 3477 3478 const Value *QuxVal = Env.getValue(*QuxDecl, SkipPast::None); 3479 ASSERT_THAT(QuxVal, NotNull()); 3480 3481 const StorageLocation *BoundFooRefLoc = 3482 Env.getStorageLocation(*BoundFooRefDecl, SkipPast::Reference); 3483 EXPECT_EQ(BoundFooRefLoc, FooRefLoc); 3484 3485 const StorageLocation *BoundBarRefLoc = 3486 Env.getStorageLocation(*BoundBarRefDecl, SkipPast::Reference); 3487 EXPECT_EQ(BoundBarRefLoc, BarRefLoc); 3488 3489 EXPECT_EQ(Env.getValue(*BoundFooRefDecl, SkipPast::Reference), QuxVal); 3490 }); 3491 } 3492 3493 TEST(TransferTest, StructuredBindingAssignFromStructRefMembersToRefs) { 3494 std::string Code = R"( 3495 struct A { 3496 int &Foo; 3497 int &Bar; 3498 }; 3499 3500 void target(A Baz) { 3501 int Qux; 3502 Baz.Foo = Qux; 3503 auto &FooRef = Baz.Foo; 3504 auto &BarRef = Baz.Bar; 3505 auto &[BoundFooRef, BoundBarRef] = Baz; 3506 // [[p]] 3507 } 3508 )"; 3509 runDataflow( 3510 Code, 3511 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3512 ASTContext &ASTCtx) { 3513 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3514 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3515 3516 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 3517 ASSERT_THAT(FooRefDecl, NotNull()); 3518 3519 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 3520 ASSERT_THAT(BarRefDecl, NotNull()); 3521 3522 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 3523 ASSERT_THAT(QuxDecl, NotNull()); 3524 3525 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef"); 3526 ASSERT_THAT(BoundFooRefDecl, NotNull()); 3527 3528 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef"); 3529 ASSERT_THAT(BoundBarRefDecl, NotNull()); 3530 3531 const StorageLocation *FooRefLoc = 3532 Env.getStorageLocation(*FooRefDecl, SkipPast::Reference); 3533 ASSERT_THAT(FooRefLoc, NotNull()); 3534 3535 const StorageLocation *BarRefLoc = 3536 Env.getStorageLocation(*BarRefDecl, SkipPast::Reference); 3537 ASSERT_THAT(BarRefLoc, NotNull()); 3538 3539 const Value *QuxVal = Env.getValue(*QuxDecl, SkipPast::None); 3540 ASSERT_THAT(QuxVal, NotNull()); 3541 3542 const StorageLocation *BoundFooRefLoc = 3543 Env.getStorageLocation(*BoundFooRefDecl, SkipPast::Reference); 3544 EXPECT_EQ(BoundFooRefLoc, FooRefLoc); 3545 3546 const StorageLocation *BoundBarRefLoc = 3547 Env.getStorageLocation(*BoundBarRefDecl, SkipPast::Reference); 3548 EXPECT_EQ(BoundBarRefLoc, BarRefLoc); 3549 3550 EXPECT_EQ(Env.getValue(*BoundFooRefDecl, SkipPast::Reference), QuxVal); 3551 }); 3552 } 3553 3554 TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToInts) { 3555 std::string Code = R"( 3556 struct A { 3557 int Foo; 3558 int Bar; 3559 }; 3560 3561 void target() { 3562 int Qux; 3563 A Baz; 3564 Baz.Foo = Qux; 3565 auto &FooRef = Baz.Foo; 3566 auto &BarRef = Baz.Bar; 3567 auto [BoundFoo, BoundBar] = Baz; 3568 // [[p]] 3569 } 3570 )"; 3571 runDataflow( 3572 Code, 3573 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3574 ASTContext &ASTCtx) { 3575 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3576 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3577 3578 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef"); 3579 ASSERT_THAT(FooRefDecl, NotNull()); 3580 3581 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef"); 3582 ASSERT_THAT(BarRefDecl, NotNull()); 3583 3584 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 3585 ASSERT_THAT(BoundFooDecl, NotNull()); 3586 3587 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 3588 ASSERT_THAT(BoundBarDecl, NotNull()); 3589 3590 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux"); 3591 ASSERT_THAT(QuxDecl, NotNull()); 3592 3593 const StorageLocation *FooRefLoc = 3594 Env.getStorageLocation(*FooRefDecl, SkipPast::Reference); 3595 ASSERT_THAT(FooRefLoc, NotNull()); 3596 3597 const StorageLocation *BarRefLoc = 3598 Env.getStorageLocation(*BarRefDecl, SkipPast::Reference); 3599 ASSERT_THAT(BarRefLoc, NotNull()); 3600 3601 const Value *QuxVal = Env.getValue(*QuxDecl, SkipPast::None); 3602 ASSERT_THAT(QuxVal, NotNull()); 3603 3604 const StorageLocation *BoundFooLoc = 3605 Env.getStorageLocation(*BoundFooDecl, SkipPast::Reference); 3606 EXPECT_NE(BoundFooLoc, FooRefLoc); 3607 3608 const StorageLocation *BoundBarLoc = 3609 Env.getStorageLocation(*BoundBarDecl, SkipPast::Reference); 3610 EXPECT_NE(BoundBarLoc, BarRefLoc); 3611 3612 EXPECT_EQ(Env.getValue(*BoundFooDecl, SkipPast::Reference), QuxVal); 3613 }); 3614 } 3615 3616 TEST(TransferTest, StructuredBindingAssignFromTupleLikeType) { 3617 std::string Code = R"( 3618 namespace std { 3619 using size_t = int; 3620 template <class> struct tuple_size; 3621 template <std::size_t, class> struct tuple_element; 3622 template <class...> class tuple; 3623 3624 namespace { 3625 template <class T, T v> 3626 struct size_helper { static const T value = v; }; 3627 } // namespace 3628 3629 template <class... T> 3630 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {}; 3631 3632 template <std::size_t I, class... T> 3633 struct tuple_element<I, tuple<T...>> { 3634 using type = __type_pack_element<I, T...>; 3635 }; 3636 3637 template <class...> class tuple {}; 3638 3639 template <std::size_t I, class... T> 3640 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 3641 } // namespace std 3642 3643 std::tuple<bool, int> makeTuple(); 3644 3645 void target(bool B) { 3646 auto [BoundFoo, BoundBar] = makeTuple(); 3647 bool Baz; 3648 // Include if-then-else to test interaction of `BindingDecl` with join. 3649 if (B) { 3650 Baz = BoundFoo; 3651 (void)BoundBar; 3652 // [[p1]] 3653 } else { 3654 Baz = BoundFoo; 3655 } 3656 (void)0; 3657 // [[p2]] 3658 } 3659 )"; 3660 runDataflow( 3661 Code, 3662 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3663 ASTContext &ASTCtx) { 3664 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 3665 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 3666 3667 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 3668 ASSERT_THAT(BoundFooDecl, NotNull()); 3669 3670 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 3671 ASSERT_THAT(BoundBarDecl, NotNull()); 3672 3673 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3674 ASSERT_THAT(BazDecl, NotNull()); 3675 3676 const Value *BoundFooValue = 3677 Env1.getValue(*BoundFooDecl, SkipPast::Reference); 3678 ASSERT_THAT(BoundFooValue, NotNull()); 3679 EXPECT_TRUE(isa<BoolValue>(BoundFooValue)); 3680 3681 const Value *BoundBarValue = 3682 Env1.getValue(*BoundBarDecl, SkipPast::Reference); 3683 ASSERT_THAT(BoundBarValue, NotNull()); 3684 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue)); 3685 3686 // Test that a `DeclRefExpr` to a `BindingDecl` works as expected. 3687 EXPECT_EQ(Env1.getValue(*BazDecl, SkipPast::Reference), BoundFooValue); 3688 3689 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 3690 3691 // Test that `BoundFooDecl` retains the value we expect, after the join. 3692 BoundFooValue = Env2.getValue(*BoundFooDecl, SkipPast::Reference); 3693 EXPECT_EQ(Env2.getValue(*BazDecl, SkipPast::Reference), BoundFooValue); 3694 }); 3695 } 3696 3697 TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) { 3698 std::string Code = R"( 3699 namespace std { 3700 using size_t = int; 3701 template <class> struct tuple_size; 3702 template <std::size_t, class> struct tuple_element; 3703 template <class...> class tuple; 3704 3705 namespace { 3706 template <class T, T v> 3707 struct size_helper { static const T value = v; }; 3708 } // namespace 3709 3710 template <class... T> 3711 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {}; 3712 3713 template <std::size_t I, class... T> 3714 struct tuple_element<I, tuple<T...>> { 3715 using type = __type_pack_element<I, T...>; 3716 }; 3717 3718 template <class...> class tuple {}; 3719 3720 template <std::size_t I, class... T> 3721 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>); 3722 } // namespace std 3723 3724 std::tuple<bool, int> &getTuple(); 3725 3726 void target(bool B) { 3727 auto &[BoundFoo, BoundBar] = getTuple(); 3728 bool Baz; 3729 // Include if-then-else to test interaction of `BindingDecl` with join. 3730 if (B) { 3731 Baz = BoundFoo; 3732 (void)BoundBar; 3733 // [[p1]] 3734 } else { 3735 Baz = BoundFoo; 3736 } 3737 (void)0; 3738 // [[p2]] 3739 } 3740 )"; 3741 runDataflow( 3742 Code, 3743 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3744 ASTContext &ASTCtx) { 3745 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2")); 3746 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1"); 3747 3748 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo"); 3749 ASSERT_THAT(BoundFooDecl, NotNull()); 3750 3751 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar"); 3752 ASSERT_THAT(BoundBarDecl, NotNull()); 3753 3754 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3755 ASSERT_THAT(BazDecl, NotNull()); 3756 3757 const Value *BoundFooValue = 3758 Env1.getValue(*BoundFooDecl, SkipPast::Reference); 3759 ASSERT_THAT(BoundFooValue, NotNull()); 3760 EXPECT_TRUE(isa<BoolValue>(BoundFooValue)); 3761 3762 const Value *BoundBarValue = 3763 Env1.getValue(*BoundBarDecl, SkipPast::Reference); 3764 ASSERT_THAT(BoundBarValue, NotNull()); 3765 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue)); 3766 3767 // Test that a `DeclRefExpr` to a `BindingDecl` (with reference type) 3768 // works as expected. We don't test aliasing properties of the 3769 // reference, because we don't model `std::get` and so have no way to 3770 // equate separate references into the tuple. 3771 EXPECT_EQ(Env1.getValue(*BazDecl, SkipPast::Reference), BoundFooValue); 3772 3773 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2"); 3774 3775 // Test that `BoundFooDecl` retains the value we expect, after the join. 3776 BoundFooValue = Env2.getValue(*BoundFooDecl, SkipPast::Reference); 3777 EXPECT_EQ(Env2.getValue(*BazDecl, SkipPast::Reference), BoundFooValue); 3778 }); 3779 } 3780 // TODO: ref binding 3781 3782 TEST(TransferTest, BinaryOperatorComma) { 3783 std::string Code = R"( 3784 void target(int Foo, int Bar) { 3785 int &Baz = (Foo, Bar); 3786 // [[p]] 3787 } 3788 )"; 3789 runDataflow( 3790 Code, 3791 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3792 ASTContext &ASTCtx) { 3793 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 3794 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 3795 3796 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3797 ASSERT_THAT(BarDecl, NotNull()); 3798 3799 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 3800 ASSERT_THAT(BazDecl, NotNull()); 3801 3802 const StorageLocation *BarLoc = 3803 Env.getStorageLocation(*BarDecl, SkipPast::Reference); 3804 ASSERT_THAT(BarLoc, NotNull()); 3805 3806 const StorageLocation *BazLoc = 3807 Env.getStorageLocation(*BazDecl, SkipPast::Reference); 3808 EXPECT_EQ(BazLoc, BarLoc); 3809 }); 3810 } 3811 3812 TEST(TransferTest, IfStmtBranchExtendsFlowCondition) { 3813 std::string Code = R"( 3814 void target(bool Foo) { 3815 if (Foo) { 3816 (void)0; 3817 // [[if_then]] 3818 } else { 3819 (void)0; 3820 // [[if_else]] 3821 } 3822 } 3823 )"; 3824 runDataflow( 3825 Code, 3826 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3827 ASTContext &ASTCtx) { 3828 ASSERT_THAT(Results.keys(), UnorderedElementsAre("if_then", "if_else")); 3829 const Environment &ThenEnv = 3830 getEnvironmentAtAnnotation(Results, "if_then"); 3831 const Environment &ElseEnv = 3832 getEnvironmentAtAnnotation(Results, "if_else"); 3833 3834 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3835 ASSERT_THAT(FooDecl, NotNull()); 3836 3837 BoolValue &ThenFooVal = 3838 *cast<BoolValue>(ThenEnv.getValue(*FooDecl, SkipPast::None)); 3839 EXPECT_TRUE(ThenEnv.flowConditionImplies(ThenFooVal)); 3840 3841 BoolValue &ElseFooVal = 3842 *cast<BoolValue>(ElseEnv.getValue(*FooDecl, SkipPast::None)); 3843 EXPECT_TRUE(ElseEnv.flowConditionImplies(ElseEnv.makeNot(ElseFooVal))); 3844 }); 3845 } 3846 3847 TEST(TransferTest, WhileStmtBranchExtendsFlowCondition) { 3848 std::string Code = R"( 3849 void target(bool Foo) { 3850 while (Foo) { 3851 (void)0; 3852 // [[loop_body]] 3853 } 3854 (void)0; 3855 // [[after_loop]] 3856 } 3857 )"; 3858 runDataflow( 3859 Code, 3860 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3861 ASTContext &ASTCtx) { 3862 ASSERT_THAT(Results.keys(), 3863 UnorderedElementsAre("loop_body", "after_loop")); 3864 const Environment &LoopBodyEnv = 3865 getEnvironmentAtAnnotation(Results, "loop_body"); 3866 const Environment &AfterLoopEnv = 3867 getEnvironmentAtAnnotation(Results, "after_loop"); 3868 3869 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3870 ASSERT_THAT(FooDecl, NotNull()); 3871 3872 BoolValue &LoopBodyFooVal = 3873 *cast<BoolValue>(LoopBodyEnv.getValue(*FooDecl, SkipPast::None)); 3874 EXPECT_TRUE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal)); 3875 3876 BoolValue &AfterLoopFooVal = 3877 *cast<BoolValue>(AfterLoopEnv.getValue(*FooDecl, SkipPast::None)); 3878 EXPECT_TRUE(AfterLoopEnv.flowConditionImplies( 3879 AfterLoopEnv.makeNot(AfterLoopFooVal))); 3880 }); 3881 } 3882 3883 TEST(TransferTest, DoWhileStmtBranchExtendsFlowCondition) { 3884 std::string Code = R"( 3885 void target(bool Foo) { 3886 bool Bar = true; 3887 do { 3888 (void)0; 3889 // [[loop_body]] 3890 Bar = false; 3891 } while (Foo); 3892 (void)0; 3893 // [[after_loop]] 3894 } 3895 )"; 3896 runDataflow( 3897 Code, 3898 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3899 ASTContext &ASTCtx) { 3900 ASSERT_THAT(Results.keys(), 3901 UnorderedElementsAre("loop_body", "after_loop")); 3902 const Environment &LoopBodyEnv = 3903 getEnvironmentAtAnnotation(Results, "loop_body"); 3904 const Environment &AfterLoopEnv = 3905 getEnvironmentAtAnnotation(Results, "after_loop"); 3906 3907 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3908 ASSERT_THAT(FooDecl, NotNull()); 3909 3910 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 3911 ASSERT_THAT(BarDecl, NotNull()); 3912 3913 BoolValue &LoopBodyFooVal = 3914 *cast<BoolValue>(LoopBodyEnv.getValue(*FooDecl, SkipPast::None)); 3915 BoolValue &LoopBodyBarVal = 3916 *cast<BoolValue>(LoopBodyEnv.getValue(*BarDecl, SkipPast::None)); 3917 EXPECT_TRUE(LoopBodyEnv.flowConditionImplies( 3918 LoopBodyEnv.makeOr(LoopBodyBarVal, LoopBodyFooVal))); 3919 3920 BoolValue &AfterLoopFooVal = 3921 *cast<BoolValue>(AfterLoopEnv.getValue(*FooDecl, SkipPast::None)); 3922 BoolValue &AfterLoopBarVal = 3923 *cast<BoolValue>(AfterLoopEnv.getValue(*BarDecl, SkipPast::None)); 3924 EXPECT_TRUE(AfterLoopEnv.flowConditionImplies( 3925 AfterLoopEnv.makeNot(AfterLoopFooVal))); 3926 EXPECT_TRUE(AfterLoopEnv.flowConditionImplies( 3927 AfterLoopEnv.makeNot(AfterLoopBarVal))); 3928 }); 3929 } 3930 3931 TEST(TransferTest, ForStmtBranchExtendsFlowCondition) { 3932 std::string Code = R"( 3933 void target(bool Foo) { 3934 for (; Foo;) { 3935 (void)0; 3936 // [[loop_body]] 3937 } 3938 (void)0; 3939 // [[after_loop]] 3940 } 3941 )"; 3942 runDataflow( 3943 Code, 3944 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3945 ASTContext &ASTCtx) { 3946 ASSERT_THAT(Results.keys(), 3947 UnorderedElementsAre("loop_body", "after_loop")); 3948 const Environment &LoopBodyEnv = 3949 getEnvironmentAtAnnotation(Results, "loop_body"); 3950 const Environment &AfterLoopEnv = 3951 getEnvironmentAtAnnotation(Results, "after_loop"); 3952 3953 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3954 ASSERT_THAT(FooDecl, NotNull()); 3955 3956 BoolValue &LoopBodyFooVal = 3957 *cast<BoolValue>(LoopBodyEnv.getValue(*FooDecl, SkipPast::None)); 3958 EXPECT_TRUE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal)); 3959 3960 BoolValue &AfterLoopFooVal = 3961 *cast<BoolValue>(AfterLoopEnv.getValue(*FooDecl, SkipPast::None)); 3962 EXPECT_TRUE(AfterLoopEnv.flowConditionImplies( 3963 AfterLoopEnv.makeNot(AfterLoopFooVal))); 3964 }); 3965 } 3966 3967 TEST(TransferTest, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition) { 3968 std::string Code = R"( 3969 void target(bool Foo) { 3970 for (;;) { 3971 (void)0; 3972 // [[loop_body]] 3973 } 3974 } 3975 )"; 3976 runDataflow( 3977 Code, 3978 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 3979 ASTContext &ASTCtx) { 3980 ASSERT_THAT(Results.keys(), UnorderedElementsAre("loop_body")); 3981 const Environment &LoopBodyEnv = 3982 getEnvironmentAtAnnotation(Results, "loop_body"); 3983 3984 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 3985 ASSERT_THAT(FooDecl, NotNull()); 3986 3987 BoolValue &LoopBodyFooVal = 3988 *cast<BoolValue>(LoopBodyEnv.getValue(*FooDecl, SkipPast::None)); 3989 EXPECT_FALSE(LoopBodyEnv.flowConditionImplies(LoopBodyFooVal)); 3990 }); 3991 } 3992 3993 TEST(TransferTest, ContextSensitiveOptionDisabled) { 3994 std::string Code = R"( 3995 bool GiveBool(); 3996 void SetBool(bool &Var) { Var = true; } 3997 3998 void target() { 3999 bool Foo = GiveBool(); 4000 SetBool(Foo); 4001 // [[p]] 4002 } 4003 )"; 4004 runDataflow( 4005 Code, 4006 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4007 ASTContext &ASTCtx) { 4008 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4009 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4010 4011 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4012 ASSERT_THAT(FooDecl, NotNull()); 4013 4014 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4015 EXPECT_FALSE(Env.flowConditionImplies(FooVal)); 4016 EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(FooVal))); 4017 }, 4018 {TransferOptions{/*.ContextSensitiveOpts=*/std::nullopt}}); 4019 } 4020 4021 TEST(TransferTest, ContextSensitiveDepthZero) { 4022 std::string Code = R"( 4023 bool GiveBool(); 4024 void SetBool(bool &Var) { Var = true; } 4025 4026 void target() { 4027 bool Foo = GiveBool(); 4028 SetBool(Foo); 4029 // [[p]] 4030 } 4031 )"; 4032 runDataflow( 4033 Code, 4034 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4035 ASTContext &ASTCtx) { 4036 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4037 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4038 4039 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4040 ASSERT_THAT(FooDecl, NotNull()); 4041 4042 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4043 EXPECT_FALSE(Env.flowConditionImplies(FooVal)); 4044 EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(FooVal))); 4045 }, 4046 {TransferOptions{ContextSensitiveOptions{/*.Depth=*/0}}}); 4047 } 4048 4049 TEST(TransferTest, ContextSensitiveSetTrue) { 4050 std::string Code = R"( 4051 bool GiveBool(); 4052 void SetBool(bool &Var) { Var = true; } 4053 4054 void target() { 4055 bool Foo = GiveBool(); 4056 SetBool(Foo); 4057 // [[p]] 4058 } 4059 )"; 4060 runDataflow( 4061 Code, 4062 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4063 ASTContext &ASTCtx) { 4064 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4065 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4066 4067 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4068 ASSERT_THAT(FooDecl, NotNull()); 4069 4070 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4071 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4072 }, 4073 {TransferOptions{ContextSensitiveOptions{}}}); 4074 } 4075 4076 TEST(TransferTest, ContextSensitiveSetFalse) { 4077 std::string Code = R"( 4078 bool GiveBool(); 4079 void SetBool(bool &Var) { Var = false; } 4080 4081 void target() { 4082 bool Foo = GiveBool(); 4083 SetBool(Foo); 4084 // [[p]] 4085 } 4086 )"; 4087 runDataflow( 4088 Code, 4089 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4090 ASTContext &ASTCtx) { 4091 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4092 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4093 4094 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4095 ASSERT_THAT(FooDecl, NotNull()); 4096 4097 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4098 EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(FooVal))); 4099 }, 4100 {TransferOptions{ContextSensitiveOptions{}}}); 4101 } 4102 4103 TEST(TransferTest, ContextSensitiveSetBothTrueAndFalse) { 4104 std::string Code = R"( 4105 bool GiveBool(); 4106 void SetBool(bool &Var, bool Val) { Var = Val; } 4107 4108 void target() { 4109 bool Foo = GiveBool(); 4110 bool Bar = GiveBool(); 4111 SetBool(Foo, true); 4112 SetBool(Bar, false); 4113 // [[p]] 4114 } 4115 )"; 4116 runDataflow( 4117 Code, 4118 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4119 ASTContext &ASTCtx) { 4120 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4121 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4122 4123 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4124 ASSERT_THAT(FooDecl, NotNull()); 4125 4126 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4127 ASSERT_THAT(BarDecl, NotNull()); 4128 4129 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4130 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4131 EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(FooVal))); 4132 4133 auto &BarVal = *cast<BoolValue>(Env.getValue(*BarDecl, SkipPast::None)); 4134 EXPECT_FALSE(Env.flowConditionImplies(BarVal)); 4135 EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(BarVal))); 4136 }, 4137 {TransferOptions{ContextSensitiveOptions{}}}); 4138 } 4139 4140 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthOne) { 4141 std::string Code = R"( 4142 bool GiveBool(); 4143 void SetBool1(bool &Var) { Var = true; } 4144 void SetBool2(bool &Var) { SetBool1(Var); } 4145 4146 void target() { 4147 bool Foo = GiveBool(); 4148 SetBool2(Foo); 4149 // [[p]] 4150 } 4151 )"; 4152 runDataflow( 4153 Code, 4154 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4155 ASTContext &ASTCtx) { 4156 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4157 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4158 4159 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4160 ASSERT_THAT(FooDecl, NotNull()); 4161 4162 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4163 EXPECT_FALSE(Env.flowConditionImplies(FooVal)); 4164 EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(FooVal))); 4165 }, 4166 {TransferOptions{ContextSensitiveOptions{/*.Depth=*/1}}}); 4167 } 4168 4169 TEST(TransferTest, ContextSensitiveSetTwoLayersDepthTwo) { 4170 std::string Code = R"( 4171 bool GiveBool(); 4172 void SetBool1(bool &Var) { Var = true; } 4173 void SetBool2(bool &Var) { SetBool1(Var); } 4174 4175 void target() { 4176 bool Foo = GiveBool(); 4177 SetBool2(Foo); 4178 // [[p]] 4179 } 4180 )"; 4181 runDataflow( 4182 Code, 4183 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4184 ASTContext &ASTCtx) { 4185 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4186 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4187 4188 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4189 ASSERT_THAT(FooDecl, NotNull()); 4190 4191 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4192 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4193 }, 4194 {TransferOptions{ContextSensitiveOptions{/*.Depth=*/2}}}); 4195 } 4196 4197 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthTwo) { 4198 std::string Code = R"( 4199 bool GiveBool(); 4200 void SetBool1(bool &Var) { Var = true; } 4201 void SetBool2(bool &Var) { SetBool1(Var); } 4202 void SetBool3(bool &Var) { SetBool2(Var); } 4203 4204 void target() { 4205 bool Foo = GiveBool(); 4206 SetBool3(Foo); 4207 // [[p]] 4208 } 4209 )"; 4210 runDataflow( 4211 Code, 4212 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4213 ASTContext &ASTCtx) { 4214 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4215 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4216 4217 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4218 ASSERT_THAT(FooDecl, NotNull()); 4219 4220 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4221 EXPECT_FALSE(Env.flowConditionImplies(FooVal)); 4222 EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(FooVal))); 4223 }, 4224 {TransferOptions{ContextSensitiveOptions{/*.Depth=*/2}}}); 4225 } 4226 4227 TEST(TransferTest, ContextSensitiveSetThreeLayersDepthThree) { 4228 std::string Code = R"( 4229 bool GiveBool(); 4230 void SetBool1(bool &Var) { Var = true; } 4231 void SetBool2(bool &Var) { SetBool1(Var); } 4232 void SetBool3(bool &Var) { SetBool2(Var); } 4233 4234 void target() { 4235 bool Foo = GiveBool(); 4236 SetBool3(Foo); 4237 // [[p]] 4238 } 4239 )"; 4240 runDataflow( 4241 Code, 4242 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4243 ASTContext &ASTCtx) { 4244 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4245 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4246 4247 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4248 ASSERT_THAT(FooDecl, NotNull()); 4249 4250 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4251 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4252 }, 4253 {TransferOptions{ContextSensitiveOptions{/*.Depth=*/3}}}); 4254 } 4255 4256 TEST(TransferTest, ContextSensitiveMutualRecursion) { 4257 std::string Code = R"( 4258 bool Pong(bool X, bool Y); 4259 4260 bool Ping(bool X, bool Y) { 4261 if (X) { 4262 return Y; 4263 } else { 4264 return Pong(!X, Y); 4265 } 4266 } 4267 4268 bool Pong(bool X, bool Y) { 4269 if (Y) { 4270 return X; 4271 } else { 4272 return Ping(X, !Y); 4273 } 4274 } 4275 4276 void target() { 4277 bool Foo = Ping(false, false); 4278 // [[p]] 4279 } 4280 )"; 4281 runDataflow( 4282 Code, 4283 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4284 ASTContext &ASTCtx) { 4285 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4286 // The analysis doesn't crash... 4287 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4288 4289 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4290 ASSERT_THAT(FooDecl, NotNull()); 4291 4292 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4293 // ... but it also can't prove anything here. 4294 EXPECT_FALSE(Env.flowConditionImplies(FooVal)); 4295 EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(FooVal))); 4296 }, 4297 {TransferOptions{ContextSensitiveOptions{/*.Depth=*/4}}}); 4298 } 4299 4300 TEST(TransferTest, ContextSensitiveSetMultipleLines) { 4301 std::string Code = R"( 4302 void SetBools(bool &Var1, bool &Var2) { 4303 Var1 = true; 4304 Var2 = false; 4305 } 4306 4307 void target() { 4308 bool Foo = false; 4309 bool Bar = true; 4310 SetBools(Foo, Bar); 4311 // [[p]] 4312 } 4313 )"; 4314 runDataflow( 4315 Code, 4316 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4317 ASTContext &ASTCtx) { 4318 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4319 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4320 4321 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4322 ASSERT_THAT(FooDecl, NotNull()); 4323 4324 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4325 ASSERT_THAT(BarDecl, NotNull()); 4326 4327 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4328 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4329 EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(FooVal))); 4330 4331 auto &BarVal = *cast<BoolValue>(Env.getValue(*BarDecl, SkipPast::None)); 4332 EXPECT_FALSE(Env.flowConditionImplies(BarVal)); 4333 EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(BarVal))); 4334 }, 4335 {TransferOptions{ContextSensitiveOptions{}}}); 4336 } 4337 4338 TEST(TransferTest, ContextSensitiveSetMultipleBlocks) { 4339 std::string Code = R"( 4340 void IfCond(bool Cond, bool &Then, bool &Else) { 4341 if (Cond) { 4342 Then = true; 4343 } else { 4344 Else = true; 4345 } 4346 } 4347 4348 void target() { 4349 bool Foo = false; 4350 bool Bar = false; 4351 bool Baz = false; 4352 IfCond(Foo, Bar, Baz); 4353 // [[p]] 4354 } 4355 )"; 4356 runDataflow( 4357 Code, 4358 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4359 ASTContext &ASTCtx) { 4360 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4361 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4362 4363 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar"); 4364 ASSERT_THAT(BarDecl, NotNull()); 4365 4366 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4367 ASSERT_THAT(BazDecl, NotNull()); 4368 4369 auto &BarVal = *cast<BoolValue>(Env.getValue(*BarDecl, SkipPast::None)); 4370 EXPECT_FALSE(Env.flowConditionImplies(BarVal)); 4371 EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(BarVal))); 4372 4373 auto &BazVal = *cast<BoolValue>(Env.getValue(*BazDecl, SkipPast::None)); 4374 EXPECT_TRUE(Env.flowConditionImplies(BazVal)); 4375 EXPECT_FALSE(Env.flowConditionImplies(Env.makeNot(BazVal))); 4376 }, 4377 {TransferOptions{ContextSensitiveOptions{}}}); 4378 } 4379 4380 TEST(TransferTest, ContextSensitiveReturnVoid) { 4381 std::string Code = R"( 4382 void Noop() { return; } 4383 4384 void target() { 4385 Noop(); 4386 // [[p]] 4387 } 4388 )"; 4389 runDataflow( 4390 Code, 4391 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4392 ASTContext &ASTCtx) { 4393 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4394 // This just tests that the analysis doesn't crash. 4395 }, 4396 {TransferOptions{ContextSensitiveOptions{}}}); 4397 } 4398 4399 TEST(TransferTest, ContextSensitiveReturnTrue) { 4400 std::string Code = R"( 4401 bool GiveBool() { return true; } 4402 4403 void target() { 4404 bool Foo = GiveBool(); 4405 // [[p]] 4406 } 4407 )"; 4408 runDataflow( 4409 Code, 4410 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4411 ASTContext &ASTCtx) { 4412 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4413 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4414 4415 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4416 ASSERT_THAT(FooDecl, NotNull()); 4417 4418 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4419 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4420 }, 4421 {TransferOptions{ContextSensitiveOptions{}}}); 4422 } 4423 4424 TEST(TransferTest, ContextSensitiveReturnFalse) { 4425 std::string Code = R"( 4426 bool GiveBool() { return false; } 4427 4428 void target() { 4429 bool Foo = GiveBool(); 4430 // [[p]] 4431 } 4432 )"; 4433 runDataflow( 4434 Code, 4435 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4436 ASTContext &ASTCtx) { 4437 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4438 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4439 4440 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4441 ASSERT_THAT(FooDecl, NotNull()); 4442 4443 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4444 EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(FooVal))); 4445 }, 4446 {TransferOptions{ContextSensitiveOptions{}}}); 4447 } 4448 4449 TEST(TransferTest, ContextSensitiveReturnArg) { 4450 std::string Code = R"( 4451 bool GiveBool(); 4452 bool GiveBack(bool Arg) { return Arg; } 4453 4454 void target() { 4455 bool Foo = GiveBool(); 4456 bool Bar = GiveBack(Foo); 4457 bool Baz = Foo == Bar; 4458 // [[p]] 4459 } 4460 )"; 4461 runDataflow( 4462 Code, 4463 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4464 ASTContext &ASTCtx) { 4465 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4466 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4467 4468 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); 4469 ASSERT_THAT(BazDecl, NotNull()); 4470 4471 auto &BazVal = *cast<BoolValue>(Env.getValue(*BazDecl, SkipPast::None)); 4472 EXPECT_TRUE(Env.flowConditionImplies(BazVal)); 4473 }, 4474 {TransferOptions{ContextSensitiveOptions{}}}); 4475 } 4476 4477 TEST(TransferTest, ContextSensitiveReturnInt) { 4478 std::string Code = R"( 4479 int identity(int x) { return x; } 4480 4481 void target() { 4482 int y = identity(42); 4483 // [[p]] 4484 } 4485 )"; 4486 runDataflow( 4487 Code, 4488 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4489 ASTContext &ASTCtx) { 4490 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4491 // This just tests that the analysis doesn't crash. 4492 }, 4493 {TransferOptions{ContextSensitiveOptions{}}}); 4494 } 4495 4496 TEST(TransferTest, ContextSensitiveMethodLiteral) { 4497 std::string Code = R"( 4498 class MyClass { 4499 public: 4500 bool giveBool() { return true; } 4501 }; 4502 4503 void target() { 4504 MyClass MyObj; 4505 bool Foo = MyObj.giveBool(); 4506 // [[p]] 4507 } 4508 )"; 4509 runDataflow( 4510 Code, 4511 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4512 ASTContext &ASTCtx) { 4513 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4514 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4515 4516 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4517 ASSERT_THAT(FooDecl, NotNull()); 4518 4519 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4520 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4521 }, 4522 {TransferOptions{ContextSensitiveOptions{}}}); 4523 } 4524 4525 TEST(TransferTest, ContextSensitiveMethodGetter) { 4526 std::string Code = R"( 4527 class MyClass { 4528 public: 4529 bool getField() { return Field; } 4530 4531 bool Field; 4532 }; 4533 4534 void target() { 4535 MyClass MyObj; 4536 MyObj.Field = true; 4537 bool Foo = MyObj.getField(); 4538 // [[p]] 4539 } 4540 )"; 4541 runDataflow( 4542 Code, 4543 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4544 ASTContext &ASTCtx) { 4545 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4546 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4547 4548 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4549 ASSERT_THAT(FooDecl, NotNull()); 4550 4551 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4552 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4553 }, 4554 {TransferOptions{ContextSensitiveOptions{}}}); 4555 } 4556 4557 TEST(TransferTest, ContextSensitiveMethodSetter) { 4558 std::string Code = R"( 4559 class MyClass { 4560 public: 4561 void setField(bool Val) { Field = Val; } 4562 4563 bool Field; 4564 }; 4565 4566 void target() { 4567 MyClass MyObj; 4568 MyObj.setField(true); 4569 bool Foo = MyObj.Field; 4570 // [[p]] 4571 } 4572 )"; 4573 runDataflow( 4574 Code, 4575 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4576 ASTContext &ASTCtx) { 4577 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4578 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4579 4580 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4581 ASSERT_THAT(FooDecl, NotNull()); 4582 4583 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4584 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4585 }, 4586 {TransferOptions{ContextSensitiveOptions{}}}); 4587 } 4588 4589 TEST(TransferTest, ContextSensitiveMethodGetterAndSetter) { 4590 std::string Code = R"( 4591 class MyClass { 4592 public: 4593 bool getField() { return Field; } 4594 void setField(bool Val) { Field = Val; } 4595 4596 private: 4597 bool Field; 4598 }; 4599 4600 void target() { 4601 MyClass MyObj; 4602 MyObj.setField(true); 4603 bool Foo = MyObj.getField(); 4604 // [[p]] 4605 } 4606 )"; 4607 runDataflow( 4608 Code, 4609 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4610 ASTContext &ASTCtx) { 4611 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4612 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4613 4614 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4615 ASSERT_THAT(FooDecl, NotNull()); 4616 4617 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4618 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4619 }, 4620 {TransferOptions{ContextSensitiveOptions{}}}); 4621 } 4622 4623 4624 TEST(TransferTest, ContextSensitiveMethodTwoLayersVoid) { 4625 std::string Code = R"( 4626 class MyClass { 4627 public: 4628 void Inner() { MyField = true; } 4629 void Outer() { Inner(); } 4630 4631 bool MyField; 4632 }; 4633 4634 void target() { 4635 MyClass MyObj; 4636 MyObj.Outer(); 4637 bool Foo = MyObj.MyField; 4638 // [[p]] 4639 } 4640 )"; 4641 runDataflow( 4642 Code, 4643 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4644 ASTContext &ASTCtx) { 4645 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));; 4646 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4647 4648 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4649 ASSERT_THAT(FooDecl, NotNull()); 4650 4651 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4652 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4653 }, 4654 {TransferOptions{ContextSensitiveOptions{}}}); 4655 } 4656 4657 TEST(TransferTest, ContextSensitiveMethodTwoLayersReturn) { 4658 std::string Code = R"( 4659 class MyClass { 4660 public: 4661 bool Inner() { return MyField; } 4662 bool Outer() { return Inner(); } 4663 4664 bool MyField; 4665 }; 4666 4667 void target() { 4668 MyClass MyObj; 4669 MyObj.MyField = true; 4670 bool Foo = MyObj.Outer(); 4671 // [[p]] 4672 } 4673 )"; 4674 runDataflow( 4675 Code, 4676 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4677 ASTContext &ASTCtx) { 4678 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));; 4679 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4680 4681 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4682 ASSERT_THAT(FooDecl, NotNull()); 4683 4684 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4685 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4686 }, 4687 {TransferOptions{ContextSensitiveOptions{}}}); 4688 } 4689 4690 TEST(TransferTest, ContextSensitiveConstructorBody) { 4691 std::string Code = R"( 4692 class MyClass { 4693 public: 4694 MyClass() { MyField = true; } 4695 4696 bool MyField; 4697 }; 4698 4699 void target() { 4700 MyClass MyObj; 4701 bool Foo = MyObj.MyField; 4702 // [[p]] 4703 } 4704 )"; 4705 runDataflow( 4706 Code, 4707 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4708 ASTContext &ASTCtx) { 4709 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4710 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4711 4712 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4713 ASSERT_THAT(FooDecl, NotNull()); 4714 4715 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4716 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4717 }, 4718 {TransferOptions{ContextSensitiveOptions{}}}); 4719 } 4720 4721 TEST(TransferTest, ContextSensitiveConstructorInitializer) { 4722 std::string Code = R"( 4723 class MyClass { 4724 public: 4725 MyClass() : MyField(true) {} 4726 4727 bool MyField; 4728 }; 4729 4730 void target() { 4731 MyClass MyObj; 4732 bool Foo = MyObj.MyField; 4733 // [[p]] 4734 } 4735 )"; 4736 runDataflow( 4737 Code, 4738 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4739 ASTContext &ASTCtx) { 4740 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4741 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4742 4743 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4744 ASSERT_THAT(FooDecl, NotNull()); 4745 4746 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4747 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4748 }, 4749 {TransferOptions{ContextSensitiveOptions{}}}); 4750 } 4751 4752 TEST(TransferTest, ContextSensitiveConstructorDefault) { 4753 std::string Code = R"( 4754 class MyClass { 4755 public: 4756 MyClass() = default; 4757 4758 bool MyField = true; 4759 }; 4760 4761 void target() { 4762 MyClass MyObj; 4763 bool Foo = MyObj.MyField; 4764 // [[p]] 4765 } 4766 )"; 4767 runDataflow( 4768 Code, 4769 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, 4770 ASTContext &ASTCtx) { 4771 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); 4772 const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); 4773 4774 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); 4775 ASSERT_THAT(FooDecl, NotNull()); 4776 4777 auto &FooVal = *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None)); 4778 EXPECT_TRUE(Env.flowConditionImplies(FooVal)); 4779 }, 4780 {TransferOptions{ContextSensitiveOptions{}}}); 4781 } 4782 4783 } // namespace 4784