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 "NoopAnalysis.h" 10 #include "TestingSupport.h" 11 #include "clang/AST/ASTContext.h" 12 #include "clang/AST/Decl.h" 13 #include "clang/ASTMatchers/ASTMatchFinder.h" 14 #include "clang/ASTMatchers/ASTMatchers.h" 15 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" 16 #include "clang/Analysis/FlowSensitive/StorageLocation.h" 17 #include "clang/Analysis/FlowSensitive/Value.h" 18 #include "llvm/ADT/ArrayRef.h" 19 #include "llvm/ADT/StringRef.h" 20 #include "llvm/Support/Casting.h" 21 #include "gmock/gmock.h" 22 #include "gtest/gtest.h" 23 #include <cassert> 24 #include <string> 25 #include <utility> 26 27 namespace { 28 29 using namespace clang; 30 using namespace dataflow; 31 using ::testing::_; 32 using ::testing::ElementsAre; 33 using ::testing::IsNull; 34 using ::testing::NotNull; 35 using ::testing::Pair; 36 37 class TransferTest : public ::testing::Test { 38 protected: 39 template <typename Matcher> 40 void runDataflow(llvm::StringRef Code, Matcher Match) { 41 test::checkDataflow<NoopAnalysis>( 42 Code, "target", 43 [](ASTContext &C, Environment &) { return NoopAnalysis(C); }, 44 [&Match](llvm::ArrayRef< 45 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 46 Results, 47 ASTContext &ASTCtx) { Match(Results, ASTCtx); }, 48 {"-fsyntax-only", "-std=c++17"}); 49 } 50 }; 51 52 /// Returns the `ValueDecl` for the given identifier. 53 /// 54 /// Requirements: 55 /// 56 /// `Name` must be unique in `ASTCtx`. 57 static const ValueDecl *findValueDecl(ASTContext &ASTCtx, 58 llvm::StringRef Name) { 59 auto TargetNodes = ast_matchers::match( 60 ast_matchers::valueDecl(ast_matchers::hasName(Name)).bind("v"), ASTCtx); 61 assert(TargetNodes.size() == 1 && "Name must be unique"); 62 auto *const Result = ast_matchers::selectFirst<ValueDecl>("v", TargetNodes); 63 assert(Result != nullptr); 64 return Result; 65 } 66 67 TEST_F(TransferTest, IntVarDecl) { 68 std::string Code = R"( 69 void target() { 70 int foo; 71 // [[p]] 72 } 73 )"; 74 runDataflow( 75 Code, [](llvm::ArrayRef< 76 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 77 Results, 78 ASTContext &ASTCtx) { 79 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 80 const Environment &Env = Results[0].second.Env; 81 82 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "foo"); 83 ASSERT_THAT(FooDecl, NotNull()); 84 85 const StorageLocation *FooLoc = 86 Env.getStorageLocation(*FooDecl, SkipPast::None); 87 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 88 89 const Value *FooVal = Env.getValue(*FooLoc); 90 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 91 }); 92 } 93 94 TEST_F(TransferTest, StructVarDecl) { 95 std::string Code = R"( 96 struct Foo { 97 int Bar; 98 }; 99 100 void target() { 101 Foo foo; 102 // [[p]] 103 } 104 )"; 105 runDataflow( 106 Code, [](llvm::ArrayRef< 107 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 108 Results, 109 ASTContext &ASTCtx) { 110 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 111 const Environment &Env = Results[0].second.Env; 112 113 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "foo"); 114 ASSERT_THAT(FooDecl, NotNull()); 115 116 ASSERT_TRUE(FooDecl->getType()->isStructureType()); 117 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 118 119 FieldDecl *BarDecl = nullptr; 120 for (FieldDecl *Field : FooFields) { 121 if (Field->getNameAsString() == "Bar") { 122 BarDecl = Field; 123 } else { 124 FAIL() << "Unexpected field: " << Field->getNameAsString(); 125 } 126 } 127 ASSERT_THAT(BarDecl, NotNull()); 128 129 const auto *FooLoc = cast<AggregateStorageLocation>( 130 Env.getStorageLocation(*FooDecl, SkipPast::None)); 131 const auto *BarLoc = 132 cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl)); 133 134 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 135 const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl)); 136 ASSERT_EQ(Env.getValue(*BarLoc), BarVal); 137 }); 138 } 139 140 TEST_F(TransferTest, ClassVarDecl) { 141 std::string Code = R"( 142 class Foo { 143 int Bar; 144 }; 145 146 void target() { 147 Foo foo; 148 // [[p]] 149 } 150 )"; 151 runDataflow( 152 Code, [](llvm::ArrayRef< 153 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 154 Results, 155 ASTContext &ASTCtx) { 156 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 157 const Environment &Env = Results[0].second.Env; 158 159 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "foo"); 160 ASSERT_THAT(FooDecl, NotNull()); 161 162 ASSERT_TRUE(FooDecl->getType()->isClassType()); 163 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); 164 165 FieldDecl *BarDecl = nullptr; 166 for (FieldDecl *Field : FooFields) { 167 if (Field->getNameAsString() == "Bar") { 168 BarDecl = Field; 169 } else { 170 FAIL() << "Unexpected field: " << Field->getNameAsString(); 171 } 172 } 173 ASSERT_THAT(BarDecl, NotNull()); 174 175 const auto *FooLoc = cast<AggregateStorageLocation>( 176 Env.getStorageLocation(*FooDecl, SkipPast::None)); 177 const auto *BarLoc = 178 cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl)); 179 180 const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc)); 181 const auto *BarVal = cast<IntegerValue>(&FooVal->getChild(*BarDecl)); 182 ASSERT_EQ(Env.getValue(*BarLoc), BarVal); 183 }); 184 } 185 186 TEST_F(TransferTest, ReferenceVarDecl) { 187 std::string Code = R"( 188 struct Foo {}; 189 190 Foo& getFoo(); 191 192 void target() { 193 Foo& foo = getFoo(); 194 // [[p]] 195 } 196 )"; 197 runDataflow( 198 Code, [](llvm::ArrayRef< 199 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 200 Results, 201 ASTContext &ASTCtx) { 202 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 203 const Environment &Env = Results[0].second.Env; 204 205 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "foo"); 206 ASSERT_THAT(FooDecl, NotNull()); 207 208 const StorageLocation *FooLoc = 209 Env.getStorageLocation(*FooDecl, SkipPast::None); 210 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 211 212 const ReferenceValue *FooVal = 213 cast<ReferenceValue>(Env.getValue(*FooLoc)); 214 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc(); 215 ASSERT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc)); 216 217 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc); 218 ASSERT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal)); 219 }); 220 } 221 222 TEST_F(TransferTest, SelfReferentialReferenceVarDecl) { 223 std::string Code = R"( 224 struct Foo; 225 226 struct Baz {}; 227 228 struct Bar { 229 Foo& FooRef; 230 Foo* FooPtr; 231 Baz& BazRef; 232 Baz* BazPtr; 233 }; 234 235 struct Foo { 236 Bar& Bar; 237 }; 238 239 Foo& getFoo(); 240 241 void target() { 242 Foo& foo = getFoo(); 243 // [[p]] 244 } 245 )"; 246 runDataflow(Code, [](llvm::ArrayRef<std::pair< 247 std::string, DataflowAnalysisState<NoopLattice>>> 248 Results, 249 ASTContext &ASTCtx) { 250 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 251 const Environment &Env = Results[0].second.Env; 252 253 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "foo"); 254 ASSERT_THAT(FooDecl, NotNull()); 255 256 ASSERT_TRUE(FooDecl->getType()->isReferenceType()); 257 ASSERT_TRUE(FooDecl->getType().getNonReferenceType()->isStructureType()); 258 const auto FooFields = 259 FooDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields(); 260 261 FieldDecl *BarDecl = nullptr; 262 for (FieldDecl *Field : FooFields) { 263 if (Field->getNameAsString() == "Bar") { 264 BarDecl = Field; 265 } else { 266 FAIL() << "Unexpected field: " << Field->getNameAsString(); 267 } 268 } 269 ASSERT_THAT(BarDecl, NotNull()); 270 271 ASSERT_TRUE(BarDecl->getType()->isReferenceType()); 272 ASSERT_TRUE(BarDecl->getType().getNonReferenceType()->isStructureType()); 273 const auto BarFields = 274 BarDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields(); 275 276 FieldDecl *FooRefDecl = nullptr; 277 FieldDecl *FooPtrDecl = nullptr; 278 FieldDecl *BazRefDecl = nullptr; 279 FieldDecl *BazPtrDecl = nullptr; 280 for (FieldDecl *Field : BarFields) { 281 if (Field->getNameAsString() == "FooRef") { 282 FooRefDecl = Field; 283 } else if (Field->getNameAsString() == "FooPtr") { 284 FooPtrDecl = Field; 285 } else if (Field->getNameAsString() == "BazRef") { 286 BazRefDecl = Field; 287 } else if (Field->getNameAsString() == "BazPtr") { 288 BazPtrDecl = Field; 289 } else { 290 FAIL() << "Unexpected field: " << Field->getNameAsString(); 291 } 292 } 293 ASSERT_THAT(FooRefDecl, NotNull()); 294 ASSERT_THAT(FooPtrDecl, NotNull()); 295 ASSERT_THAT(BazRefDecl, NotNull()); 296 ASSERT_THAT(BazPtrDecl, NotNull()); 297 298 const auto *FooLoc = cast<ScalarStorageLocation>( 299 Env.getStorageLocation(*FooDecl, SkipPast::None)); 300 const auto *FooVal = cast<ReferenceValue>(Env.getValue(*FooLoc)); 301 const auto *FooPointeeVal = 302 cast<StructValue>(Env.getValue(FooVal->getPointeeLoc())); 303 304 const auto *BarVal = 305 cast<ReferenceValue>(&FooPointeeVal->getChild(*BarDecl)); 306 const auto *BarPointeeVal = 307 cast<StructValue>(Env.getValue(BarVal->getPointeeLoc())); 308 309 const auto *FooRefVal = 310 cast<ReferenceValue>(&BarPointeeVal->getChild(*FooRefDecl)); 311 const StorageLocation &FooRefPointeeLoc = FooRefVal->getPointeeLoc(); 312 ASSERT_THAT(Env.getValue(FooRefPointeeLoc), IsNull()); 313 314 const auto *FooPtrVal = 315 cast<PointerValue>(&BarPointeeVal->getChild(*FooPtrDecl)); 316 const StorageLocation &FooPtrPointeeLoc = FooPtrVal->getPointeeLoc(); 317 ASSERT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull()); 318 319 const auto *BazRefVal = 320 cast<ReferenceValue>(&BarPointeeVal->getChild(*BazRefDecl)); 321 const StorageLocation &BazRefPointeeLoc = BazRefVal->getPointeeLoc(); 322 ASSERT_THAT(Env.getValue(BazRefPointeeLoc), NotNull()); 323 324 const auto *BazPtrVal = 325 cast<PointerValue>(&BarPointeeVal->getChild(*BazPtrDecl)); 326 const StorageLocation &BazPtrPointeeLoc = BazPtrVal->getPointeeLoc(); 327 ASSERT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull()); 328 }); 329 } 330 331 TEST_F(TransferTest, PointerVarDecl) { 332 std::string Code = R"( 333 struct Foo {}; 334 335 Foo* getFoo(); 336 337 void target() { 338 Foo* foo = getFoo(); 339 // [[p]] 340 } 341 )"; 342 runDataflow( 343 Code, [](llvm::ArrayRef< 344 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 345 Results, 346 ASTContext &ASTCtx) { 347 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 348 const Environment &Env = Results[0].second.Env; 349 350 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "foo"); 351 ASSERT_THAT(FooDecl, NotNull()); 352 353 const StorageLocation *FooLoc = 354 Env.getStorageLocation(*FooDecl, SkipPast::None); 355 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc)); 356 357 const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc)); 358 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc(); 359 ASSERT_TRUE(isa<AggregateStorageLocation>(&FooPointeeLoc)); 360 361 const Value *FooPointeeVal = Env.getValue(FooPointeeLoc); 362 ASSERT_TRUE(isa_and_nonnull<StructValue>(FooPointeeVal)); 363 }); 364 } 365 366 TEST_F(TransferTest, SelfReferentialPointerVarDecl) { 367 std::string Code = R"( 368 struct Foo; 369 370 struct Baz {}; 371 372 struct Bar { 373 Foo& FooRef; 374 Foo* FooPtr; 375 Baz& BazRef; 376 Baz* BazPtr; 377 }; 378 379 struct Foo { 380 Bar* Bar; 381 }; 382 383 Foo* getFoo(); 384 385 void target() { 386 Foo* foo = getFoo(); 387 // [[p]] 388 } 389 )"; 390 runDataflow( 391 Code, [](llvm::ArrayRef< 392 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 393 Results, 394 ASTContext &ASTCtx) { 395 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 396 const Environment &Env = Results[0].second.Env; 397 398 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "foo"); 399 ASSERT_THAT(FooDecl, NotNull()); 400 401 ASSERT_TRUE(FooDecl->getType()->isPointerType()); 402 ASSERT_TRUE(FooDecl->getType() 403 ->getAs<PointerType>() 404 ->getPointeeType() 405 ->isStructureType()); 406 const auto FooFields = FooDecl->getType() 407 ->getAs<PointerType>() 408 ->getPointeeType() 409 ->getAsRecordDecl() 410 ->fields(); 411 412 FieldDecl *BarDecl = nullptr; 413 for (FieldDecl *Field : FooFields) { 414 if (Field->getNameAsString() == "Bar") { 415 BarDecl = Field; 416 } else { 417 FAIL() << "Unexpected field: " << Field->getNameAsString(); 418 } 419 } 420 ASSERT_THAT(BarDecl, NotNull()); 421 422 ASSERT_TRUE(BarDecl->getType()->isPointerType()); 423 ASSERT_TRUE(BarDecl->getType() 424 ->getAs<PointerType>() 425 ->getPointeeType() 426 ->isStructureType()); 427 const auto BarFields = BarDecl->getType() 428 ->getAs<PointerType>() 429 ->getPointeeType() 430 ->getAsRecordDecl() 431 ->fields(); 432 433 FieldDecl *FooRefDecl = nullptr; 434 FieldDecl *FooPtrDecl = nullptr; 435 FieldDecl *BazRefDecl = nullptr; 436 FieldDecl *BazPtrDecl = nullptr; 437 for (FieldDecl *Field : BarFields) { 438 if (Field->getNameAsString() == "FooRef") { 439 FooRefDecl = Field; 440 } else if (Field->getNameAsString() == "FooPtr") { 441 FooPtrDecl = Field; 442 } else if (Field->getNameAsString() == "BazRef") { 443 BazRefDecl = Field; 444 } else if (Field->getNameAsString() == "BazPtr") { 445 BazPtrDecl = Field; 446 } else { 447 FAIL() << "Unexpected field: " << Field->getNameAsString(); 448 } 449 } 450 ASSERT_THAT(FooRefDecl, NotNull()); 451 ASSERT_THAT(FooPtrDecl, NotNull()); 452 ASSERT_THAT(BazRefDecl, NotNull()); 453 ASSERT_THAT(BazPtrDecl, NotNull()); 454 455 const auto *FooLoc = cast<ScalarStorageLocation>( 456 Env.getStorageLocation(*FooDecl, SkipPast::None)); 457 const auto *FooVal = cast<PointerValue>(Env.getValue(*FooLoc)); 458 const auto *FooPointeeVal = 459 cast<StructValue>(Env.getValue(FooVal->getPointeeLoc())); 460 461 const auto *BarVal = 462 cast<PointerValue>(&FooPointeeVal->getChild(*BarDecl)); 463 const auto *BarPointeeVal = 464 cast<StructValue>(Env.getValue(BarVal->getPointeeLoc())); 465 466 const auto *FooRefVal = 467 cast<ReferenceValue>(&BarPointeeVal->getChild(*FooRefDecl)); 468 const StorageLocation &FooRefPointeeLoc = FooRefVal->getPointeeLoc(); 469 ASSERT_THAT(Env.getValue(FooRefPointeeLoc), IsNull()); 470 471 const auto *FooPtrVal = 472 cast<PointerValue>(&BarPointeeVal->getChild(*FooPtrDecl)); 473 const StorageLocation &FooPtrPointeeLoc = FooPtrVal->getPointeeLoc(); 474 ASSERT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull()); 475 476 const auto *BazRefVal = 477 cast<ReferenceValue>(&BarPointeeVal->getChild(*BazRefDecl)); 478 const StorageLocation &BazRefPointeeLoc = BazRefVal->getPointeeLoc(); 479 ASSERT_THAT(Env.getValue(BazRefPointeeLoc), NotNull()); 480 481 const auto *BazPtrVal = 482 cast<PointerValue>(&BarPointeeVal->getChild(*BazPtrDecl)); 483 const StorageLocation &BazPtrPointeeLoc = BazPtrVal->getPointeeLoc(); 484 ASSERT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull()); 485 }); 486 } 487 488 TEST_F(TransferTest, JoinVarDecl) { 489 std::string Code = R"( 490 void target(bool b) { 491 int foo; 492 // [[p1]] 493 if (b) { 494 int bar; 495 // [[p2]] 496 } else { 497 int baz; 498 // [[p3]] 499 } 500 (void)0; 501 // [[p4]] 502 } 503 )"; 504 runDataflow(Code, [](llvm::ArrayRef<std::pair< 505 std::string, DataflowAnalysisState<NoopLattice>>> 506 Results, 507 ASTContext &ASTCtx) { 508 ASSERT_THAT(Results, ElementsAre(Pair("p4", _), Pair("p3", _), 509 Pair("p2", _), Pair("p1", _))); 510 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "foo"); 511 ASSERT_THAT(FooDecl, NotNull()); 512 513 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "bar"); 514 ASSERT_THAT(BarDecl, NotNull()); 515 516 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "baz"); 517 ASSERT_THAT(BazDecl, NotNull()); 518 519 const Environment &Env1 = Results[3].second.Env; 520 const StorageLocation *FooLoc = 521 Env1.getStorageLocation(*FooDecl, SkipPast::None); 522 ASSERT_THAT(FooLoc, NotNull()); 523 ASSERT_THAT(Env1.getStorageLocation(*BarDecl, SkipPast::None), IsNull()); 524 ASSERT_THAT(Env1.getStorageLocation(*BazDecl, SkipPast::None), IsNull()); 525 526 const Environment &Env2 = Results[2].second.Env; 527 ASSERT_EQ(Env2.getStorageLocation(*FooDecl, SkipPast::None), FooLoc); 528 ASSERT_THAT(Env2.getStorageLocation(*BarDecl, SkipPast::None), NotNull()); 529 ASSERT_THAT(Env2.getStorageLocation(*BazDecl, SkipPast::None), IsNull()); 530 531 const Environment &Env3 = Results[1].second.Env; 532 ASSERT_EQ(Env3.getStorageLocation(*FooDecl, SkipPast::None), FooLoc); 533 ASSERT_THAT(Env3.getStorageLocation(*BarDecl, SkipPast::None), IsNull()); 534 ASSERT_THAT(Env3.getStorageLocation(*BazDecl, SkipPast::None), NotNull()); 535 536 const Environment &Env4 = Results[0].second.Env; 537 ASSERT_EQ(Env4.getStorageLocation(*FooDecl, SkipPast::None), FooLoc); 538 ASSERT_THAT(Env4.getStorageLocation(*BarDecl, SkipPast::None), IsNull()); 539 ASSERT_THAT(Env4.getStorageLocation(*BazDecl, SkipPast::None), IsNull()); 540 }); 541 } 542 543 TEST_F(TransferTest, BinaryOperatorAssign) { 544 std::string Code = R"( 545 void target() { 546 int foo; 547 int bar; 548 (bar) = (foo); 549 // [[p]] 550 } 551 )"; 552 runDataflow(Code, 553 [](llvm::ArrayRef< 554 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 555 Results, 556 ASTContext &ASTCtx) { 557 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 558 const Environment &Env = Results[0].second.Env; 559 560 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "foo"); 561 ASSERT_THAT(FooDecl, NotNull()); 562 563 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None); 564 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 565 566 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "bar"); 567 ASSERT_THAT(BarDecl, NotNull()); 568 569 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal); 570 }); 571 } 572 573 TEST_F(TransferTest, VarDeclInitAssign) { 574 std::string Code = R"( 575 void target() { 576 int foo; 577 int bar = foo; 578 // [[p]] 579 } 580 )"; 581 runDataflow(Code, 582 [](llvm::ArrayRef< 583 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 584 Results, 585 ASTContext &ASTCtx) { 586 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 587 const Environment &Env = Results[0].second.Env; 588 589 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "foo"); 590 ASSERT_THAT(FooDecl, NotNull()); 591 592 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None); 593 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 594 595 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "bar"); 596 ASSERT_THAT(BarDecl, NotNull()); 597 598 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal); 599 }); 600 } 601 602 TEST_F(TransferTest, VarDeclInitAssignChained) { 603 std::string Code = R"( 604 void target() { 605 int foo; 606 int bar; 607 int baz = (bar = foo); 608 // [[p]] 609 } 610 )"; 611 runDataflow(Code, 612 [](llvm::ArrayRef< 613 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 614 Results, 615 ASTContext &ASTCtx) { 616 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 617 const Environment &Env = Results[0].second.Env; 618 619 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "foo"); 620 ASSERT_THAT(FooDecl, NotNull()); 621 622 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None); 623 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 624 625 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "bar"); 626 ASSERT_THAT(BarDecl, NotNull()); 627 628 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "baz"); 629 ASSERT_THAT(BazDecl, NotNull()); 630 631 EXPECT_EQ(Env.getValue(*BarDecl, SkipPast::None), FooVal); 632 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), FooVal); 633 }); 634 } 635 636 TEST_F(TransferTest, VarDeclInitAssignPtrDeref) { 637 std::string Code = R"( 638 void target() { 639 int foo; 640 int *bar; 641 *(bar) = foo; 642 int baz = *(bar); 643 // [[p]] 644 } 645 )"; 646 runDataflow(Code, 647 [](llvm::ArrayRef< 648 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 649 Results, 650 ASTContext &ASTCtx) { 651 ASSERT_THAT(Results, ElementsAre(Pair("p", _))); 652 const Environment &Env = Results[0].second.Env; 653 654 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "foo"); 655 ASSERT_THAT(FooDecl, NotNull()); 656 657 const Value *FooVal = Env.getValue(*FooDecl, SkipPast::None); 658 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 659 660 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "bar"); 661 ASSERT_THAT(BarDecl, NotNull()); 662 663 const auto *BarVal = 664 cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None)); 665 EXPECT_EQ(Env.getValue(BarVal->getPointeeLoc()), FooVal); 666 667 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "baz"); 668 ASSERT_THAT(BazDecl, NotNull()); 669 670 EXPECT_EQ(Env.getValue(*BazDecl, SkipPast::None), FooVal); 671 }); 672 } 673 674 TEST_F(TransferTest, AssignToAndFromReference) { 675 std::string Code = R"( 676 void target() { 677 int foo; 678 int bar; 679 int& baz = foo; 680 // [[p1]] 681 baz = bar; 682 int qux = baz; 683 int& quux = baz; 684 // [[p2]] 685 } 686 )"; 687 runDataflow( 688 Code, [](llvm::ArrayRef< 689 std::pair<std::string, DataflowAnalysisState<NoopLattice>>> 690 Results, 691 ASTContext &ASTCtx) { 692 ASSERT_THAT(Results, ElementsAre(Pair("p1", _), Pair("p2", _))); 693 const Environment &Env1 = Results[0].second.Env; 694 const Environment &Env2 = Results[1].second.Env; 695 696 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "foo"); 697 ASSERT_THAT(FooDecl, NotNull()); 698 699 const Value *FooVal = Env1.getValue(*FooDecl, SkipPast::None); 700 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal)); 701 702 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "bar"); 703 ASSERT_THAT(BarDecl, NotNull()); 704 705 const Value *BarVal = Env1.getValue(*BarDecl, SkipPast::None); 706 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal)); 707 708 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "baz"); 709 ASSERT_THAT(BazDecl, NotNull()); 710 711 EXPECT_EQ(Env1.getValue(*BazDecl, SkipPast::Reference), FooVal); 712 713 EXPECT_EQ(Env2.getValue(*BazDecl, SkipPast::Reference), BarVal); 714 EXPECT_EQ(Env2.getValue(*FooDecl, SkipPast::None), BarVal); 715 716 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "qux"); 717 ASSERT_THAT(QuxDecl, NotNull()); 718 EXPECT_EQ(Env2.getValue(*QuxDecl, SkipPast::None), BarVal); 719 720 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "quux"); 721 ASSERT_THAT(QuuxDecl, NotNull()); 722 EXPECT_EQ(Env2.getValue(*QuuxDecl, SkipPast::Reference), BarVal); 723 }); 724 } 725 726 } // namespace 727