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