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