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