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