8190 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "TestingSupport.h"10#include "clang/AST/ASTContext.h"11#include "clang/AST/Decl.h"12#include "clang/AST/Expr.h"13#include "clang/AST/ExprCXX.h"14#include "clang/AST/OperationKinds.h"15#include "clang/ASTMatchers/ASTMatchFinder.h"16#include "clang/ASTMatchers/ASTMatchers.h"17#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"18#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"19#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"20#include "clang/Analysis/FlowSensitive/Formula.h"21#include "clang/Analysis/FlowSensitive/NoopAnalysis.h"22#include "clang/Analysis/FlowSensitive/NoopLattice.h"23#include "clang/Analysis/FlowSensitive/RecordOps.h"24#include "clang/Analysis/FlowSensitive/StorageLocation.h"25#include "clang/Analysis/FlowSensitive/Value.h"26#include "clang/Basic/LangStandard.h"27#include "clang/Testing/TestAST.h"28#include "llvm/ADT/SmallVector.h"29#include "llvm/ADT/StringMap.h"30#include "llvm/ADT/StringRef.h"31#include "llvm/Support/Casting.h"32#include "llvm/Testing/Support/Error.h"33#include "gmock/gmock.h"34#include "gtest/gtest.h"35#include <optional>36#include <string>37#include <string_view>38#include <utility>39#include <vector>40 41namespace clang {42namespace dataflow {43namespace {44AST_MATCHER(FunctionDecl, isTemplated) { return Node.isTemplated(); }45} // namespace46} // namespace dataflow47} // namespace clang48 49namespace {50 51using namespace clang;52using namespace dataflow;53using namespace test;54using ::testing::Eq;55using ::testing::IsNull;56using ::testing::Ne;57using ::testing::NotNull;58using ::testing::UnorderedElementsAre;59 60// Declares a minimal coroutine library.61constexpr llvm::StringRef CoroutineLibrary = R"cc(62struct promise;63struct task;64 65namespace std {66template <class, class...>67struct coroutine_traits {};68template <>69struct coroutine_traits<task> {70 using promise_type = promise;71};72 73template <class Promise = void>74struct coroutine_handle {75 static constexpr coroutine_handle from_address(void *addr) { return {}; }76};77} // namespace std78 79struct awaitable {80 bool await_ready() const noexcept;81 void await_suspend(std::coroutine_handle<promise>) const noexcept;82 void await_resume() const noexcept;83};84struct task {};85struct promise {86 task get_return_object();87 awaitable initial_suspend();88 awaitable final_suspend() noexcept;89 void unhandled_exception();90 void return_void();91};92)cc";93 94void runDataflow(95 llvm::StringRef Code,96 std::function<97 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,98 ASTContext &)>99 VerifyResults,100 DataflowAnalysisOptions Options,101 LangStandard::Kind Std = LangStandard::lang_cxx17,102 llvm::StringRef TargetFun = "target") {103 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code, VerifyResults, Options,104 Std, TargetFun),105 llvm::Succeeded());106}107 108void runDataflow(109 llvm::StringRef Code,110 std::function<111 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,112 ASTContext &)>113 VerifyResults,114 LangStandard::Kind Std = LangStandard::lang_cxx17,115 bool ApplyBuiltinTransfer = true, llvm::StringRef TargetFun = "target") {116 runDataflow(Code, std::move(VerifyResults),117 {ApplyBuiltinTransfer ? BuiltinOptions{}118 : std::optional<BuiltinOptions>()},119 Std, TargetFun);120}121 122void runDataflowOnLambda(123 llvm::StringRef Code,124 std::function<125 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,126 ASTContext &)>127 VerifyResults,128 DataflowAnalysisOptions Options,129 LangStandard::Kind Std = LangStandard::lang_cxx17) {130 ASSERT_THAT_ERROR(131 checkDataflowWithNoopAnalysis(132 Code,133 ast_matchers::hasDeclContext(134 ast_matchers::cxxRecordDecl(ast_matchers::isLambda())),135 VerifyResults, Options, Std),136 llvm::Succeeded());137}138 139void runDataflowOnLambda(140 llvm::StringRef Code,141 std::function<142 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,143 ASTContext &)>144 VerifyResults,145 LangStandard::Kind Std = LangStandard::lang_cxx17,146 bool ApplyBuiltinTransfer = true) {147 runDataflowOnLambda(Code, std::move(VerifyResults),148 {ApplyBuiltinTransfer ? BuiltinOptions{}149 : std::optional<BuiltinOptions>()},150 Std);151}152 153const Formula &getFormula(const ValueDecl &D, const Environment &Env) {154 return cast<BoolValue>(Env.getValue(D))->formula();155}156 157const BindingDecl *findBindingDecl(ASTContext &ASTCtx, std::string_view Name) {158 using ast_matchers::bindingDecl;159 using ast_matchers::hasName;160 auto TargetNodes =161 ast_matchers::match(bindingDecl(hasName(Name)).bind("v"), ASTCtx);162 assert(TargetNodes.size() == 1 && "Name must be unique");163 return ast_matchers::selectFirst<BindingDecl>("v", TargetNodes);164}165 166TEST(TransferTest, CNotSupported) {167 TestInputs Inputs("void target() {}");168 Inputs.Language = TestLanguage::Lang_C89;169 clang::TestAST AST(Inputs);170 const auto *Target =171 cast<FunctionDecl>(test::findValueDecl(AST.context(), "target"));172 ASSERT_THAT_ERROR(AdornedCFG::build(*Target).takeError(),173 llvm::FailedWithMessage("Can only analyze C++"));174}175 176TEST(TransferTest, ObjectiveCNotSupported) {177 TestInputs Inputs("void target() {}");178 Inputs.Language = TestLanguage::Lang_OBJC;179 clang::TestAST AST(Inputs);180 const auto *Target =181 cast<FunctionDecl>(test::findValueDecl(AST.context(), "target"));182 ASSERT_THAT_ERROR(AdornedCFG::build(*Target).takeError(),183 llvm::FailedWithMessage("Can only analyze C++"));184}185 186TEST(TransferTest, ObjectiveCXXNotSupported) {187 TestInputs Inputs("void target() {}");188 Inputs.Language = TestLanguage::Lang_OBJCXX;189 clang::TestAST AST(Inputs);190 const auto *Target =191 cast<FunctionDecl>(test::findValueDecl(AST.context(), "target"));192 ASSERT_THAT_ERROR(AdornedCFG::build(*Target).takeError(),193 llvm::FailedWithMessage("Can only analyze C++"));194}195 196TEST(TransferTest, IntVarDeclNotTrackedWhenTransferDisabled) {197 std::string Code = R"(198 void target() {199 int Foo;200 // [[p]]201 }202 )";203 runDataflow(204 Code,205 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,206 ASTContext &ASTCtx) {207 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));208 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");209 210 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");211 ASSERT_THAT(FooDecl, NotNull());212 213 EXPECT_EQ(Env.getStorageLocation(*FooDecl), nullptr);214 },215 LangStandard::lang_cxx17,216 /*ApplyBuiltinTransfer=*/false);217}218 219TEST(TransferTest, BoolVarDecl) {220 std::string Code = R"(221 void target() {222 bool Foo;223 // [[p]]224 }225 )";226 runDataflow(227 Code,228 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,229 ASTContext &ASTCtx) {230 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));231 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");232 233 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");234 ASSERT_THAT(FooDecl, NotNull());235 236 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);237 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));238 239 const Value *FooVal = Env.getValue(*FooLoc);240 EXPECT_TRUE(isa_and_nonnull<BoolValue>(FooVal));241 });242}243 244TEST(TransferTest, IntVarDecl) {245 std::string Code = R"(246 void target() {247 int Foo;248 // [[p]]249 }250 )";251 runDataflow(252 Code,253 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,254 ASTContext &ASTCtx) {255 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));256 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");257 258 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");259 ASSERT_THAT(FooDecl, NotNull());260 261 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);262 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));263 264 const Value *FooVal = Env.getValue(*FooLoc);265 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));266 });267}268 269TEST(TransferTest, StructIncomplete) {270 std::string Code = R"(271 struct A;272 273 void target() {274 A* Foo;275 // [[p]]276 }277 )";278 runDataflow(279 Code,280 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,281 ASTContext &ASTCtx) {282 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));283 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");284 285 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");286 ASSERT_THAT(FooDecl, NotNull());287 auto *FooValue = dyn_cast_or_null<PointerValue>(Env.getValue(*FooDecl));288 ASSERT_THAT(FooValue, NotNull());289 290 EXPECT_TRUE(isa<RecordStorageLocation>(FooValue->getPointeeLoc()));291 });292}293 294// As a memory optimization, we prevent modeling fields nested below a certain295// level (currently, depth 3). This test verifies this lack of modeling. We also296// include a regression test for the case that the unmodeled field is a297// reference to a struct; previously, we crashed when accessing such a field.298TEST(TransferTest, StructFieldUnmodeled) {299 std::string Code = R"(300 struct S { int X; };301 S GlobalS;302 struct A { S &Unmodeled = GlobalS; };303 struct B { A F3; };304 struct C { B F2; };305 struct D { C F1; };306 307 void target() {308 D Bar;309 A &Foo = Bar.F1.F2.F3;310 int Zab = Foo.Unmodeled.X;311 // [[p]]312 }313 )";314 runDataflow(315 Code,316 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,317 ASTContext &ASTCtx) {318 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));319 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");320 321 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");322 ASSERT_THAT(FooDecl, NotNull());323 QualType FooReferentType = FooDecl->getType()->getPointeeType();324 ASSERT_TRUE(FooReferentType->isStructureType());325 auto FooFields = FooReferentType->getAsRecordDecl()->fields();326 327 FieldDecl *UnmodeledDecl = nullptr;328 for (FieldDecl *Field : FooFields) {329 if (Field->getNameAsString() == "Unmodeled") {330 UnmodeledDecl = Field;331 } else {332 FAIL() << "Unexpected field: " << Field->getNameAsString();333 }334 }335 ASSERT_THAT(UnmodeledDecl, NotNull());336 337 const auto *FooLoc =338 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));339 const auto &UnmodeledLoc =340 *cast<RecordStorageLocation>(FooLoc->getChild(*UnmodeledDecl));341 StorageLocation &UnmodeledXLoc = getFieldLoc(UnmodeledLoc, "X", ASTCtx);342 EXPECT_EQ(Env.getValue(UnmodeledXLoc), nullptr);343 344 const ValueDecl *ZabDecl = findValueDecl(ASTCtx, "Zab");345 ASSERT_THAT(ZabDecl, NotNull());346 EXPECT_THAT(Env.getValue(*ZabDecl), NotNull());347 });348}349 350TEST(TransferTest, StructVarDecl) {351 std::string Code = R"(352 struct A {353 int Bar;354 };355 356 void target() {357 A Foo;358 (void)Foo.Bar;359 // [[p]]360 }361 )";362 runDataflow(363 Code,364 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,365 ASTContext &ASTCtx) {366 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));367 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");368 369 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");370 ASSERT_THAT(FooDecl, NotNull());371 372 ASSERT_TRUE(FooDecl->getType()->isStructureType());373 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();374 375 FieldDecl *BarDecl = nullptr;376 for (FieldDecl *Field : FooFields) {377 if (Field->getNameAsString() == "Bar") {378 BarDecl = Field;379 } else {380 FAIL() << "Unexpected field: " << Field->getNameAsString();381 }382 }383 ASSERT_THAT(BarDecl, NotNull());384 385 const auto *FooLoc =386 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));387 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));388 });389}390 391TEST(TransferTest, StructVarDeclWithInit) {392 std::string Code = R"(393 struct A {394 int Bar;395 };396 397 A Gen();398 399 void target() {400 A Foo = Gen();401 (void)Foo.Bar;402 // [[p]]403 }404 )";405 runDataflow(406 Code,407 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,408 ASTContext &ASTCtx) {409 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));410 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");411 412 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");413 ASSERT_THAT(FooDecl, NotNull());414 415 ASSERT_TRUE(FooDecl->getType()->isStructureType());416 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();417 418 FieldDecl *BarDecl = nullptr;419 for (FieldDecl *Field : FooFields) {420 if (Field->getNameAsString() == "Bar") {421 BarDecl = Field;422 } else {423 FAIL() << "Unexpected field: " << Field->getNameAsString();424 }425 }426 ASSERT_THAT(BarDecl, NotNull());427 428 const auto *FooLoc =429 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));430 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));431 });432}433 434TEST(TransferTest, StructArrayVarDecl) {435 std::string Code = R"(436 struct A {};437 438 void target() {439 A Array[2];440 // [[p]]441 }442 )";443 runDataflow(444 Code,445 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,446 ASTContext &ASTCtx) {447 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");448 449 const ValueDecl *ArrayDecl = findValueDecl(ASTCtx, "Array");450 451 // We currently don't create values for arrays.452 ASSERT_THAT(Env.getValue(*ArrayDecl), IsNull());453 });454}455 456TEST(TransferTest, ClassVarDecl) {457 std::string Code = R"(458 class A {459 public:460 int Bar;461 };462 463 void target() {464 A Foo;465 (void)Foo.Bar;466 // [[p]]467 }468 )";469 runDataflow(470 Code,471 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,472 ASTContext &ASTCtx) {473 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));474 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");475 476 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");477 ASSERT_THAT(FooDecl, NotNull());478 479 ASSERT_TRUE(FooDecl->getType()->isClassType());480 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();481 482 FieldDecl *BarDecl = nullptr;483 for (FieldDecl *Field : FooFields) {484 if (Field->getNameAsString() == "Bar") {485 BarDecl = Field;486 } else {487 FAIL() << "Unexpected field: " << Field->getNameAsString();488 }489 }490 ASSERT_THAT(BarDecl, NotNull());491 492 const auto *FooLoc =493 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));494 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));495 });496}497 498TEST(TransferTest, ReferenceVarDecl) {499 std::string Code = R"(500 struct A {};501 502 A &getA();503 504 void target() {505 A &Foo = getA();506 // [[p]]507 }508 )";509 runDataflow(510 Code,511 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,512 ASTContext &ASTCtx) {513 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));514 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");515 516 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");517 ASSERT_THAT(FooDecl, NotNull());518 519 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);520 ASSERT_TRUE(isa_and_nonnull<RecordStorageLocation>(FooLoc));521 });522}523 524TEST(TransferTest, SelfReferentialReferenceVarDecl) {525 std::string Code = R"(526 struct A;527 528 struct B {};529 530 struct C {531 A &FooRef;532 A *FooPtr;533 B &BazRef;534 B *BazPtr;535 };536 537 struct A {538 C &Bar;539 };540 541 A &getA();542 543 void target() {544 A &Foo = getA();545 (void)Foo.Bar.FooRef;546 (void)Foo.Bar.FooPtr;547 (void)Foo.Bar.BazRef;548 (void)Foo.Bar.BazPtr;549 // [[p]]550 }551 )";552 runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>>553 &Results,554 ASTContext &ASTCtx) {555 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));556 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");557 558 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");559 ASSERT_THAT(FooDecl, NotNull());560 561 ASSERT_TRUE(FooDecl->getType()->isReferenceType());562 ASSERT_TRUE(FooDecl->getType().getNonReferenceType()->isStructureType());563 const auto FooFields =564 FooDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields();565 566 FieldDecl *BarDecl = nullptr;567 for (FieldDecl *Field : FooFields) {568 if (Field->getNameAsString() == "Bar") {569 BarDecl = Field;570 } else {571 FAIL() << "Unexpected field: " << Field->getNameAsString();572 }573 }574 ASSERT_THAT(BarDecl, NotNull());575 576 ASSERT_TRUE(BarDecl->getType()->isReferenceType());577 ASSERT_TRUE(BarDecl->getType().getNonReferenceType()->isStructureType());578 const auto BarFields =579 BarDecl->getType().getNonReferenceType()->getAsRecordDecl()->fields();580 581 FieldDecl *FooRefDecl = nullptr;582 FieldDecl *FooPtrDecl = nullptr;583 FieldDecl *BazRefDecl = nullptr;584 FieldDecl *BazPtrDecl = nullptr;585 for (FieldDecl *Field : BarFields) {586 if (Field->getNameAsString() == "FooRef") {587 FooRefDecl = Field;588 } else if (Field->getNameAsString() == "FooPtr") {589 FooPtrDecl = Field;590 } else if (Field->getNameAsString() == "BazRef") {591 BazRefDecl = Field;592 } else if (Field->getNameAsString() == "BazPtr") {593 BazPtrDecl = Field;594 } else {595 FAIL() << "Unexpected field: " << Field->getNameAsString();596 }597 }598 ASSERT_THAT(FooRefDecl, NotNull());599 ASSERT_THAT(FooPtrDecl, NotNull());600 ASSERT_THAT(BazRefDecl, NotNull());601 ASSERT_THAT(BazPtrDecl, NotNull());602 603 const auto &FooLoc =604 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));605 606 const auto &BarLoc =607 *cast<RecordStorageLocation>(FooLoc.getChild(*BarDecl));608 609 const auto &FooReferentLoc =610 *cast<RecordStorageLocation>(BarLoc.getChild(*FooRefDecl));611 EXPECT_EQ(Env.getValue(*cast<RecordStorageLocation>(612 FooReferentLoc.getChild(*BarDecl))613 ->getChild(*FooPtrDecl)),614 nullptr);615 616 const auto &FooPtrVal =617 *cast<PointerValue>(getFieldValue(&BarLoc, *FooPtrDecl, Env));618 const auto &FooPtrPointeeLoc =619 cast<RecordStorageLocation>(FooPtrVal.getPointeeLoc());620 EXPECT_EQ(Env.getValue(*cast<RecordStorageLocation>(621 FooPtrPointeeLoc.getChild(*BarDecl))622 ->getChild(*FooPtrDecl)),623 nullptr);624 625 EXPECT_TRUE(isa<PointerValue>(getFieldValue(&BarLoc, *BazPtrDecl, Env)));626 });627}628 629TEST(TransferTest, PointerVarDecl) {630 std::string Code = R"(631 struct A {};632 633 A *getA();634 635 void target() {636 A *Foo = getA();637 // [[p]]638 }639 )";640 runDataflow(641 Code,642 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,643 ASTContext &ASTCtx) {644 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));645 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");646 647 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");648 ASSERT_THAT(FooDecl, NotNull());649 650 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);651 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));652 653 const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));654 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();655 EXPECT_TRUE(isa<RecordStorageLocation>(&FooPointeeLoc));656 });657}658 659TEST(TransferTest, SelfReferentialPointerVarDecl) {660 std::string Code = R"(661 struct A;662 663 struct B {};664 665 struct C {666 A &FooRef;667 A *FooPtr;668 B &BazRef;669 B *BazPtr;670 };671 672 struct A {673 C *Bar;674 };675 676 A *getA();677 678 void target() {679 A *Foo = getA();680 (void)Foo->Bar->FooRef;681 (void)Foo->Bar->FooPtr;682 (void)Foo->Bar->BazRef;683 (void)Foo->Bar->BazPtr;684 // [[p]]685 }686 )";687 runDataflow(688 Code,689 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,690 ASTContext &ASTCtx) {691 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));692 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");693 694 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");695 ASSERT_THAT(FooDecl, NotNull());696 697 ASSERT_TRUE(FooDecl->getType()->isPointerType());698 ASSERT_TRUE(FooDecl->getType()699 ->getAs<PointerType>()700 ->getPointeeType()701 ->isStructureType());702 const auto FooFields = FooDecl->getType()703 ->getAs<PointerType>()704 ->getPointeeType()705 ->getAsRecordDecl()706 ->fields();707 708 FieldDecl *BarDecl = nullptr;709 for (FieldDecl *Field : FooFields) {710 if (Field->getNameAsString() == "Bar") {711 BarDecl = Field;712 } else {713 FAIL() << "Unexpected field: " << Field->getNameAsString();714 }715 }716 ASSERT_THAT(BarDecl, NotNull());717 718 ASSERT_TRUE(BarDecl->getType()->isPointerType());719 ASSERT_TRUE(BarDecl->getType()720 ->getAs<PointerType>()721 ->getPointeeType()722 ->isStructureType());723 const auto BarFields = BarDecl->getType()724 ->getAs<PointerType>()725 ->getPointeeType()726 ->getAsRecordDecl()727 ->fields();728 729 FieldDecl *FooRefDecl = nullptr;730 FieldDecl *FooPtrDecl = nullptr;731 FieldDecl *BazRefDecl = nullptr;732 FieldDecl *BazPtrDecl = nullptr;733 for (FieldDecl *Field : BarFields) {734 if (Field->getNameAsString() == "FooRef") {735 FooRefDecl = Field;736 } else if (Field->getNameAsString() == "FooPtr") {737 FooPtrDecl = Field;738 } else if (Field->getNameAsString() == "BazRef") {739 BazRefDecl = Field;740 } else if (Field->getNameAsString() == "BazPtr") {741 BazPtrDecl = Field;742 } else {743 FAIL() << "Unexpected field: " << Field->getNameAsString();744 }745 }746 ASSERT_THAT(FooRefDecl, NotNull());747 ASSERT_THAT(FooPtrDecl, NotNull());748 ASSERT_THAT(BazRefDecl, NotNull());749 ASSERT_THAT(BazPtrDecl, NotNull());750 751 const auto &FooLoc =752 *cast<ScalarStorageLocation>(Env.getStorageLocation(*FooDecl));753 const auto &FooVal = *cast<PointerValue>(Env.getValue(FooLoc));754 const auto &FooPointeeLoc =755 cast<RecordStorageLocation>(FooVal.getPointeeLoc());756 757 const auto &BarVal =758 *cast<PointerValue>(getFieldValue(&FooPointeeLoc, *BarDecl, Env));759 const auto &BarPointeeLoc =760 cast<RecordStorageLocation>(BarVal.getPointeeLoc());761 762 const auto &FooPtrVal = *cast<PointerValue>(763 getFieldValue(&BarPointeeLoc, *FooPtrDecl, Env));764 const auto &FooPtrPointeeLoc =765 cast<RecordStorageLocation>(FooPtrVal.getPointeeLoc());766 EXPECT_EQ(Env.getValue(*FooPtrPointeeLoc.getChild(*BarDecl)), nullptr);767 768 EXPECT_TRUE(769 isa<PointerValue>(getFieldValue(&BarPointeeLoc, *BazPtrDecl, Env)));770 });771}772 773TEST(TransferTest, DirectlySelfReferentialReference) {774 std::string Code = R"(775 struct target {776 target() {777 (void)0;778 // [[p]]779 }780 target &self = *this;781 };782 )";783 runDataflow(784 Code,785 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,786 ASTContext &ASTCtx) {787 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");788 const ValueDecl *SelfDecl = findValueDecl(ASTCtx, "self");789 790 auto *ThisLoc = Env.getThisPointeeStorageLocation();791 ASSERT_EQ(ThisLoc->getChild(*SelfDecl), ThisLoc);792 });793}794 795TEST(TransferTest, MultipleVarsDecl) {796 std::string Code = R"(797 void target() {798 int Foo, Bar;799 (void)0;800 // [[p]]801 }802 )";803 runDataflow(804 Code,805 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,806 ASTContext &ASTCtx) {807 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));808 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");809 810 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");811 ASSERT_THAT(FooDecl, NotNull());812 813 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");814 ASSERT_THAT(BarDecl, NotNull());815 816 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);817 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));818 819 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);820 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));821 822 const Value *FooVal = Env.getValue(*FooLoc);823 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));824 825 const Value *BarVal = Env.getValue(*BarLoc);826 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));827 });828}829 830TEST(TransferTest, JoinVarDecl) {831 std::string Code = R"(832 void target(bool B) {833 int Foo;834 // [[p1]]835 if (B) {836 int Bar;837 // [[p2]]838 } else {839 int Baz;840 // [[p3]]841 }842 (void)0;843 // [[p4]]844 }845 )";846 runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>>847 &Results,848 ASTContext &ASTCtx) {849 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2", "p3", "p4"));850 851 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");852 ASSERT_THAT(FooDecl, NotNull());853 854 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");855 ASSERT_THAT(BarDecl, NotNull());856 857 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");858 ASSERT_THAT(BazDecl, NotNull());859 860 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");861 862 const StorageLocation *FooLoc = Env1.getStorageLocation(*FooDecl);863 EXPECT_THAT(FooLoc, NotNull());864 EXPECT_THAT(Env1.getStorageLocation(*BarDecl), IsNull());865 EXPECT_THAT(Env1.getStorageLocation(*BazDecl), IsNull());866 867 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");868 EXPECT_EQ(Env2.getStorageLocation(*FooDecl), FooLoc);869 EXPECT_THAT(Env2.getStorageLocation(*BarDecl), NotNull());870 EXPECT_THAT(Env2.getStorageLocation(*BazDecl), IsNull());871 872 const Environment &Env3 = getEnvironmentAtAnnotation(Results, "p3");873 EXPECT_EQ(Env3.getStorageLocation(*FooDecl), FooLoc);874 EXPECT_THAT(Env3.getStorageLocation(*BarDecl), IsNull());875 EXPECT_THAT(Env3.getStorageLocation(*BazDecl), NotNull());876 877 const Environment &Env4 = getEnvironmentAtAnnotation(Results, "p4");878 EXPECT_EQ(Env4.getStorageLocation(*FooDecl), FooLoc);879 EXPECT_THAT(Env4.getStorageLocation(*BarDecl), IsNull());880 EXPECT_THAT(Env4.getStorageLocation(*BazDecl), IsNull());881 });882}883 884TEST(TransferTest, BinaryOperatorAssign) {885 std::string Code = R"(886 void target() {887 int Foo;888 int Bar;889 (Bar) = (Foo);890 // [[p]]891 }892 )";893 runDataflow(894 Code,895 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,896 ASTContext &ASTCtx) {897 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));898 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");899 900 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");901 ASSERT_THAT(FooDecl, NotNull());902 903 const Value *FooVal = Env.getValue(*FooDecl);904 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));905 906 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");907 ASSERT_THAT(BarDecl, NotNull());908 909 EXPECT_EQ(Env.getValue(*BarDecl), FooVal);910 });911}912 913TEST(TransferTest, BinaryOperatorAssignIntegerLiteral) {914 std::string Code = R"(915 void target() {916 int Foo = 1;917 // [[before]]918 Foo = 2;919 // [[after]]920 }921 )";922 runDataflow(923 Code,924 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,925 ASTContext &ASTCtx) {926 const Environment &Before =927 getEnvironmentAtAnnotation(Results, "before");928 const Environment &After = getEnvironmentAtAnnotation(Results, "after");929 930 const auto &ValBefore =931 getValueForDecl<IntegerValue>(ASTCtx, Before, "Foo");932 const auto &ValAfter =933 getValueForDecl<IntegerValue>(ASTCtx, After, "Foo");934 EXPECT_NE(&ValBefore, &ValAfter);935 });936}937 938TEST(TransferTest, VarDeclInitAssign) {939 std::string Code = R"(940 void target() {941 int Foo;942 int Bar = Foo;943 // [[p]]944 }945 )";946 runDataflow(947 Code,948 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,949 ASTContext &ASTCtx) {950 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));951 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");952 953 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");954 ASSERT_THAT(FooDecl, NotNull());955 956 const Value *FooVal = Env.getValue(*FooDecl);957 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));958 959 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");960 ASSERT_THAT(BarDecl, NotNull());961 962 EXPECT_EQ(Env.getValue(*BarDecl), FooVal);963 });964}965 966TEST(TransferTest, VarDeclInitAssignChained) {967 std::string Code = R"(968 void target() {969 int Foo;970 int Bar;971 int Baz = (Bar = Foo);972 // [[p]]973 }974 )";975 runDataflow(976 Code,977 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,978 ASTContext &ASTCtx) {979 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));980 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");981 982 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");983 ASSERT_THAT(FooDecl, NotNull());984 985 const Value *FooVal = Env.getValue(*FooDecl);986 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));987 988 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");989 ASSERT_THAT(BarDecl, NotNull());990 991 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");992 ASSERT_THAT(BazDecl, NotNull());993 994 EXPECT_EQ(Env.getValue(*BarDecl), FooVal);995 EXPECT_EQ(Env.getValue(*BazDecl), FooVal);996 });997}998 999TEST(TransferTest, VarDeclInitAssignPtrDeref) {1000 std::string Code = R"(1001 void target() {1002 int Foo;1003 int *Bar;1004 *(Bar) = Foo;1005 int Baz = *(Bar);1006 // [[p]]1007 }1008 )";1009 runDataflow(1010 Code,1011 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1012 ASTContext &ASTCtx) {1013 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));1014 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");1015 1016 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");1017 ASSERT_THAT(FooDecl, NotNull());1018 1019 const Value *FooVal = Env.getValue(*FooDecl);1020 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));1021 1022 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");1023 ASSERT_THAT(BarDecl, NotNull());1024 1025 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl));1026 EXPECT_EQ(Env.getValue(BarVal->getPointeeLoc()), FooVal);1027 1028 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");1029 ASSERT_THAT(BazDecl, NotNull());1030 1031 EXPECT_EQ(Env.getValue(*BazDecl), FooVal);1032 });1033}1034 1035TEST(TransferTest, AssignToAndFromReference) {1036 std::string Code = R"(1037 void target() {1038 int Foo;1039 int Bar;1040 int &Baz = Foo;1041 // [[p1]]1042 Baz = Bar;1043 int Qux = Baz;1044 int &Quux = Baz;1045 // [[p2]]1046 }1047 )";1048 runDataflow(1049 Code,1050 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1051 ASTContext &ASTCtx) {1052 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));1053 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");1054 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");1055 1056 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");1057 ASSERT_THAT(FooDecl, NotNull());1058 1059 const Value *FooVal = Env1.getValue(*FooDecl);1060 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));1061 1062 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");1063 ASSERT_THAT(BarDecl, NotNull());1064 1065 const Value *BarVal = Env1.getValue(*BarDecl);1066 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));1067 1068 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");1069 ASSERT_THAT(BazDecl, NotNull());1070 1071 EXPECT_EQ(Env1.getValue(*BazDecl), FooVal);1072 1073 EXPECT_EQ(Env2.getValue(*BazDecl), BarVal);1074 EXPECT_EQ(Env2.getValue(*FooDecl), BarVal);1075 1076 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");1077 ASSERT_THAT(QuxDecl, NotNull());1078 EXPECT_EQ(Env2.getValue(*QuxDecl), BarVal);1079 1080 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");1081 ASSERT_THAT(QuuxDecl, NotNull());1082 EXPECT_EQ(Env2.getValue(*QuuxDecl), BarVal);1083 });1084}1085 1086TEST(TransferTest, MultipleParamDecls) {1087 std::string Code = R"(1088 void target(int Foo, int Bar) {1089 (void)0;1090 // [[p]]1091 }1092 )";1093 runDataflow(1094 Code,1095 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1096 ASTContext &ASTCtx) {1097 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));1098 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");1099 1100 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");1101 ASSERT_THAT(FooDecl, NotNull());1102 1103 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);1104 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));1105 1106 const Value *FooVal = Env.getValue(*FooLoc);1107 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));1108 1109 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");1110 ASSERT_THAT(BarDecl, NotNull());1111 1112 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);1113 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));1114 1115 const Value *BarVal = Env.getValue(*BarLoc);1116 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));1117 });1118}1119 1120TEST(TransferTest, StructParamDecl) {1121 std::string Code = R"(1122 struct A {1123 int Bar;1124 };1125 1126 void target(A Foo) {1127 (void)Foo.Bar;1128 // [[p]]1129 }1130 )";1131 runDataflow(1132 Code,1133 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1134 ASTContext &ASTCtx) {1135 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));1136 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");1137 1138 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");1139 ASSERT_THAT(FooDecl, NotNull());1140 1141 ASSERT_TRUE(FooDecl->getType()->isStructureType());1142 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();1143 1144 FieldDecl *BarDecl = nullptr;1145 for (FieldDecl *Field : FooFields) {1146 if (Field->getNameAsString() == "Bar") {1147 BarDecl = Field;1148 } else {1149 FAIL() << "Unexpected field: " << Field->getNameAsString();1150 }1151 }1152 ASSERT_THAT(BarDecl, NotNull());1153 1154 const auto *FooLoc =1155 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));1156 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));1157 });1158}1159 1160TEST(TransferTest, ReferenceParamDecl) {1161 std::string Code = R"(1162 struct A {};1163 1164 void target(A &Foo) {1165 (void)0;1166 // [[p]]1167 }1168 )";1169 runDataflow(1170 Code,1171 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1172 ASTContext &ASTCtx) {1173 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));1174 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");1175 1176 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");1177 ASSERT_THAT(FooDecl, NotNull());1178 1179 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);1180 ASSERT_TRUE(isa_and_nonnull<RecordStorageLocation>(FooLoc));1181 });1182}1183 1184TEST(TransferTest, PointerParamDecl) {1185 std::string Code = R"(1186 struct A {};1187 1188 void target(A *Foo) {1189 (void)0;1190 // [[p]]1191 }1192 )";1193 runDataflow(1194 Code,1195 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1196 ASTContext &ASTCtx) {1197 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));1198 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");1199 1200 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");1201 ASSERT_THAT(FooDecl, NotNull());1202 1203 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);1204 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));1205 1206 const PointerValue *FooVal = cast<PointerValue>(Env.getValue(*FooLoc));1207 const StorageLocation &FooPointeeLoc = FooVal->getPointeeLoc();1208 EXPECT_TRUE(isa<RecordStorageLocation>(&FooPointeeLoc));1209 });1210}1211 1212TEST(TransferTest, StructMember) {1213 std::string Code = R"(1214 struct A {1215 int Bar;1216 };1217 1218 void target(A Foo) {1219 int Baz = Foo.Bar;1220 // [[p]]1221 }1222 )";1223 runDataflow(1224 Code,1225 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1226 ASTContext &ASTCtx) {1227 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));1228 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");1229 1230 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");1231 ASSERT_THAT(FooDecl, NotNull());1232 1233 ASSERT_TRUE(FooDecl->getType()->isStructureType());1234 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();1235 1236 FieldDecl *BarDecl = nullptr;1237 for (FieldDecl *Field : FooFields) {1238 if (Field->getNameAsString() == "Bar") {1239 BarDecl = Field;1240 } else {1241 FAIL() << "Unexpected field: " << Field->getNameAsString();1242 }1243 }1244 ASSERT_THAT(BarDecl, NotNull());1245 1246 const auto *FooLoc =1247 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));1248 const auto *BarVal =1249 cast<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env));1250 1251 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");1252 ASSERT_THAT(BazDecl, NotNull());1253 1254 EXPECT_EQ(Env.getValue(*BazDecl), BarVal);1255 });1256}1257 1258TEST(TransferTest, StructMemberEnum) {1259 std::string Code = R"(1260 struct A {1261 int Bar;1262 enum E { ONE, TWO };1263 };1264 1265 void target(A Foo) {1266 A::E Baz = Foo.ONE;1267 // [[p]]1268 }1269 )";1270 // Minimal expectations -- we're just testing that it doesn't crash, since1271 // enums aren't interpreted.1272 runDataflow(1273 Code,1274 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1275 ASTContext &ASTCtx) {1276 EXPECT_THAT(Results.keys(), UnorderedElementsAre("p"));1277 });1278}1279 1280TEST(TransferTest, DerivedBaseMemberClass) {1281 std::string Code = R"(1282 class A {1283 int ADefault;1284 protected:1285 int AProtected;1286 private:1287 int APrivate;1288 public:1289 int APublic;1290 1291 private:1292 friend void target();1293 };1294 1295 class B : public A {1296 int BDefault;1297 protected:1298 int BProtected;1299 private:1300 int BPrivate;1301 1302 private:1303 friend void target();1304 };1305 1306 void target() {1307 B Foo;1308 (void)Foo.ADefault;1309 (void)Foo.AProtected;1310 (void)Foo.APrivate;1311 (void)Foo.APublic;1312 (void)Foo.BDefault;1313 (void)Foo.BProtected;1314 (void)Foo.BPrivate;1315 // [[p]]1316 }1317 )";1318 runDataflow(1319 Code,1320 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1321 ASTContext &ASTCtx) {1322 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));1323 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");1324 1325 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");1326 ASSERT_THAT(FooDecl, NotNull());1327 ASSERT_TRUE(FooDecl->getType()->isRecordType());1328 1329 // Derived-class fields.1330 const FieldDecl *BDefaultDecl = nullptr;1331 const FieldDecl *BProtectedDecl = nullptr;1332 const FieldDecl *BPrivateDecl = nullptr;1333 for (const FieldDecl *Field :1334 FooDecl->getType()->getAsRecordDecl()->fields()) {1335 if (Field->getNameAsString() == "BDefault") {1336 BDefaultDecl = Field;1337 } else if (Field->getNameAsString() == "BProtected") {1338 BProtectedDecl = Field;1339 } else if (Field->getNameAsString() == "BPrivate") {1340 BPrivateDecl = Field;1341 } else {1342 FAIL() << "Unexpected field: " << Field->getNameAsString();1343 }1344 }1345 ASSERT_THAT(BDefaultDecl, NotNull());1346 ASSERT_THAT(BProtectedDecl, NotNull());1347 ASSERT_THAT(BPrivateDecl, NotNull());1348 1349 // Base-class fields.1350 const FieldDecl *ADefaultDecl = nullptr;1351 const FieldDecl *APrivateDecl = nullptr;1352 const FieldDecl *AProtectedDecl = nullptr;1353 const FieldDecl *APublicDecl = nullptr;1354 for (const clang::CXXBaseSpecifier &Base :1355 FooDecl->getType()->getAsCXXRecordDecl()->bases()) {1356 QualType BaseType = Base.getType();1357 ASSERT_TRUE(BaseType->isRecordType());1358 for (const FieldDecl *Field : BaseType->getAsRecordDecl()->fields()) {1359 if (Field->getNameAsString() == "ADefault") {1360 ADefaultDecl = Field;1361 } else if (Field->getNameAsString() == "AProtected") {1362 AProtectedDecl = Field;1363 } else if (Field->getNameAsString() == "APrivate") {1364 APrivateDecl = Field;1365 } else if (Field->getNameAsString() == "APublic") {1366 APublicDecl = Field;1367 } else {1368 FAIL() << "Unexpected field: " << Field->getNameAsString();1369 }1370 }1371 }1372 ASSERT_THAT(ADefaultDecl, NotNull());1373 ASSERT_THAT(AProtectedDecl, NotNull());1374 ASSERT_THAT(APrivateDecl, NotNull());1375 ASSERT_THAT(APublicDecl, NotNull());1376 1377 ASSERT_TRUE(1378 isa<RecordStorageLocation>(Env.getStorageLocation(*FooDecl)));1379 });1380}1381 1382static void derivedBaseMemberExpectations(1383 const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1384 ASTContext &ASTCtx) {1385 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));1386 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");1387 1388 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");1389 ASSERT_THAT(FooDecl, NotNull());1390 1391 ASSERT_TRUE(FooDecl->getType()->isRecordType());1392 const FieldDecl *BarDecl = nullptr;1393 for (const clang::CXXBaseSpecifier &Base :1394 FooDecl->getType()->getAsCXXRecordDecl()->bases()) {1395 QualType BaseType = Base.getType();1396 ASSERT_TRUE(BaseType->isStructureType());1397 1398 for (const FieldDecl *Field : BaseType->getAsRecordDecl()->fields()) {1399 if (Field->getNameAsString() == "Bar") {1400 BarDecl = Field;1401 } else {1402 FAIL() << "Unexpected field: " << Field->getNameAsString();1403 }1404 }1405 }1406 ASSERT_THAT(BarDecl, NotNull());1407 1408 const auto &FooLoc =1409 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));1410 EXPECT_NE(Env.getValue(*FooLoc.getChild(*BarDecl)), nullptr);1411}1412 1413TEST(TransferTest, DerivedBaseMemberStructDefault) {1414 std::string Code = R"(1415 struct A {1416 int Bar;1417 };1418 struct B : public A {1419 };1420 1421 void target() {1422 B Foo;1423 (void)Foo.Bar;1424 // [[p]]1425 }1426 )";1427 runDataflow(Code, derivedBaseMemberExpectations);1428}1429 1430TEST(TransferTest, DerivedBaseMemberPrivateFriend) {1431 // Include an access to `Foo.Bar` to verify the analysis doesn't crash on that1432 // access.1433 std::string Code = R"(1434 struct A {1435 private:1436 friend void target();1437 int Bar;1438 };1439 struct B : public A {1440 };1441 1442 void target() {1443 B Foo;1444 (void)Foo.Bar;1445 // [[p]]1446 }1447 )";1448 runDataflow(Code, derivedBaseMemberExpectations);1449}1450 1451TEST(TransferTest, ClassMember) {1452 std::string Code = R"(1453 class A {1454 public:1455 int Bar;1456 };1457 1458 void target(A Foo) {1459 int Baz = Foo.Bar;1460 // [[p]]1461 }1462 )";1463 runDataflow(1464 Code,1465 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1466 ASTContext &ASTCtx) {1467 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));1468 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");1469 1470 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");1471 ASSERT_THAT(FooDecl, NotNull());1472 1473 ASSERT_TRUE(FooDecl->getType()->isClassType());1474 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();1475 1476 FieldDecl *BarDecl = nullptr;1477 for (FieldDecl *Field : FooFields) {1478 if (Field->getNameAsString() == "Bar") {1479 BarDecl = Field;1480 } else {1481 FAIL() << "Unexpected field: " << Field->getNameAsString();1482 }1483 }1484 ASSERT_THAT(BarDecl, NotNull());1485 1486 const auto *FooLoc =1487 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));1488 const auto *BarVal =1489 cast<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env));1490 1491 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");1492 ASSERT_THAT(BazDecl, NotNull());1493 1494 EXPECT_EQ(Env.getValue(*BazDecl), BarVal);1495 });1496}1497 1498TEST(TransferTest, BaseClassInitializer) {1499 using ast_matchers::cxxConstructorDecl;1500 using ast_matchers::hasName;1501 using ast_matchers::ofClass;1502 1503 std::string Code = R"(1504 class A {1505 public:1506 A(int I) : Bar(I) {}1507 int Bar;1508 };1509 1510 class B : public A {1511 public:1512 B(int I) : A(I) {1513 (void)0;1514 // [[p]]1515 }1516 };1517 )";1518 ASSERT_THAT_ERROR(1519 checkDataflow<NoopAnalysis>(1520 AnalysisInputs<NoopAnalysis>(1521 Code, cxxConstructorDecl(ofClass(hasName("B"))),1522 [](ASTContext &C, Environment &) { return NoopAnalysis(C); })1523 .withASTBuildArgs(1524 {"-fsyntax-only", "-fno-delayed-template-parsing",1525 "-std=" + std::string(LangStandard::getLangStandardForKind(1526 LangStandard::lang_cxx17)1527 .getName())}),1528 /*VerifyResults=*/1529 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1530 const AnalysisOutputs &) {1531 // Regression test to verify that base-class initializers do not1532 // trigger an assertion. If we add support for such initializers in1533 // the future, we can expand this test to check more specific1534 // properties.1535 EXPECT_THAT(Results.keys(), UnorderedElementsAre("p"));1536 }),1537 llvm::Succeeded());1538}1539 1540TEST(TransferTest, BaseClassInitializerFromSiblingDerivedInstance) {1541 using ast_matchers::cxxConstructorDecl;1542 using ast_matchers::hasName;1543 using ast_matchers::ofClass;1544 1545 std::string Code = R"(1546 struct Base {1547 bool BaseField;1548 char UnmodeledField;1549 };1550 1551 struct DerivedOne : public Base {1552 int DerivedOneField;1553 };1554 1555 struct DerivedTwo : public Base {1556 int DerivedTwoField;1557 1558 DerivedTwo(const DerivedOne& D1)1559 : Base(D1), DerivedTwoField(D1.DerivedOneField) {1560 (void)BaseField;1561 }1562 };1563 )";1564 runDataflow(1565 Code,1566 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1567 ASTContext &ASTCtx) {1568 // Regression test only; we used to crash when transferring the base1569 // class initializer from the DerivedToBase-cast `D1`.1570 },1571 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "DerivedTwo");1572}1573 1574TEST(TransferTest, CopyAssignmentToDerivedToBase) {1575 std::string Code = R"cc(1576 struct Base {};1577 1578struct DerivedOne : public Base {1579 int DerivedOneField;1580};1581 1582struct DerivedTwo : public Base {1583 int DerivedTwoField;1584 1585 explicit DerivedTwo(const DerivedOne& D1) {1586 *static_cast<Base*>(this) = D1;1587 }1588};1589)cc";1590 1591 runDataflow(1592 Code,1593 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1594 ASTContext &ASTCtx) {1595 // Regression test only; we used to crash when transferring the copy1596 // assignment operator in the constructor for `DerivedTwo`.1597 },1598 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "DerivedTwo");1599}1600 1601TEST(TransferTest, FieldsDontHaveValuesInConstructor) {1602 // In a constructor, unlike in regular member functions, we don't want fields1603 // to be pre-initialized with values, because doing so is the job of the1604 // constructor.1605 std::string Code = R"(1606 struct target {1607 target() {1608 0;1609 // [[p]]1610 // Mention the field so it is modeled;1611 Val;1612 }1613 1614 int Val;1615 };1616 )";1617 runDataflow(1618 Code,1619 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1620 ASTContext &ASTCtx) {1621 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");1622 EXPECT_EQ(getFieldValue(Env.getThisPointeeStorageLocation(), "Val",1623 ASTCtx, Env),1624 nullptr);1625 });1626}1627 1628TEST(TransferTest, FieldsDontHaveValuesInConstructorWithBaseClass) {1629 // See above, but for a class with a base class.1630 std::string Code = R"(1631 struct Base {1632 int BaseVal;1633 };1634 1635 struct target : public Base {1636 target() {1637 0;1638 // [[p]]1639 // Mention the fields so they are modeled.1640 BaseVal;1641 Val;1642 }1643 1644 int Val;1645 };1646 )";1647 runDataflow(1648 Code,1649 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1650 ASTContext &ASTCtx) {1651 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");1652 // The field of the base class should already have been initialized with1653 // a value by the base constructor.1654 EXPECT_NE(getFieldValue(Env.getThisPointeeStorageLocation(), "BaseVal",1655 ASTCtx, Env),1656 nullptr);1657 EXPECT_EQ(getFieldValue(Env.getThisPointeeStorageLocation(), "Val",1658 ASTCtx, Env),1659 nullptr);1660 });1661}1662 1663TEST(TransferTest, StructModeledFieldsWithAccessor) {1664 std::string Code = R"(1665 class S {1666 int *Ptr;1667 int *PtrNonConst;1668 int Int;1669 int IntWithInc;1670 int IntNotAccessed;1671 int IntRef;1672 public:1673 int *getPtr() const { return Ptr; }1674 int *getPtrNonConst() { return PtrNonConst; }1675 int getInt(int i) const { return Int; }1676 int getWithInc(int i) { IntWithInc += i; return IntWithInc; }1677 int getIntNotAccessed() const { return IntNotAccessed; }1678 int getIntNoDefinition() const;1679 int &getIntRef() { return IntRef; }1680 void returnVoid() const { return; }1681 };1682 1683 void target() {1684 S s;1685 int *p1 = s.getPtr();1686 int *p2 = s.getPtrNonConst();1687 int i1 = s.getInt(1);1688 int i2 = s.getWithInc(1);1689 int i3 = s.getIntNoDefinition();1690 int &iref = s.getIntRef();1691 1692 // Regression test: Don't crash on an indirect call (which doesn't have1693 // an associated `CXXMethodDecl`).1694 auto ptr_to_member_fn = &S::getPtr;1695 p1 = (s.*ptr_to_member_fn)();1696 1697 // Regression test: Don't crash on a return statement without a value.1698 s.returnVoid();1699 // [[p]]1700 }1701 )";1702 runDataflow(1703 Code,1704 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1705 ASTContext &ASTCtx) {1706 const Environment &Env =1707 getEnvironmentAtAnnotation(Results, "p");1708 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s");1709 std::vector<const ValueDecl*> Fields;1710 for (auto [Field, _] : SLoc.children())1711 Fields.push_back(Field);1712 // Only the fields that have simple accessor methods (that have a1713 // single statement body that returns the member variable) should be1714 // modeled.1715 ASSERT_THAT(Fields, UnorderedElementsAre(1716 findValueDecl(ASTCtx, "Ptr"), findValueDecl(ASTCtx, "PtrNonConst"),1717 findValueDecl(ASTCtx, "Int"), findValueDecl(ASTCtx, "IntRef")));1718 });1719}1720 1721TEST(TransferTest, StructModeledFieldsInTypeid) {1722 // Test that we model fields mentioned inside a `typeid()` expression only if1723 // that expression is potentially evaluated -- i.e. if the expression inside1724 // `typeid()` is a glvalue of polymorphic type (see1725 // `CXXTypeidExpr::isPotentiallyEvaluated()` and [expr.typeid]p3).1726 std::string Code = R"(1727 // Definitions needed for `typeid`.1728 namespace std {1729 class type_info {};1730 class bad_typeid {};1731 } // namespace std1732 1733 struct NonPolymorphic {};1734 1735 struct Polymorphic {1736 virtual ~Polymorphic() = default;1737 };1738 1739 struct S {1740 NonPolymorphic *NonPoly;1741 Polymorphic *Poly;1742 };1743 1744 void target(S &s) {1745 typeid(*s.NonPoly);1746 typeid(*s.Poly);1747 // [[p]]1748 }1749 )";1750 runDataflow(1751 Code,1752 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1753 ASTContext &ASTCtx) {1754 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");1755 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s");1756 std::vector<const ValueDecl *> Fields;1757 for (auto [Field, _] : SLoc.children())1758 Fields.push_back(Field);1759 EXPECT_THAT(Fields,1760 UnorderedElementsAre(findValueDecl(ASTCtx, "Poly")));1761 });1762}1763 1764TEST(TransferTest, StructModeledFieldsWithComplicatedInheritance) {1765 std::string Code = R"(1766 struct Base1 {1767 int base1_1;1768 int base1_2;1769 };1770 struct Intermediate : Base1 {1771 int intermediate_1;1772 int intermediate_2;1773 };1774 struct Base2 {1775 int base2_1;1776 int base2_2;1777 };1778 struct MostDerived : public Intermediate, Base2 {1779 int most_derived_1;1780 int most_derived_2;1781 };1782 1783 void target() {1784 MostDerived MD;1785 MD.base1_2 = 1;1786 MD.intermediate_2 = 1;1787 MD.base2_2 = 1;1788 MD.most_derived_2 = 1;1789 // [[p]]1790 }1791 )";1792 runDataflow(1793 Code,1794 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1795 ASTContext &ASTCtx) {1796 const Environment &Env =1797 getEnvironmentAtAnnotation(Results, "p");1798 1799 // Only the accessed fields should exist in the model.1800 auto &MDLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "MD");1801 std::vector<const ValueDecl*> Fields;1802 for (auto [Field, _] : MDLoc.children())1803 Fields.push_back(Field);1804 ASSERT_THAT(Fields, UnorderedElementsAre(1805 findValueDecl(ASTCtx, "base1_2"),1806 findValueDecl(ASTCtx, "intermediate_2"),1807 findValueDecl(ASTCtx, "base2_2"),1808 findValueDecl(ASTCtx, "most_derived_2")));1809 });1810}1811 1812TEST(TransferTest, StructInitializerListWithComplicatedInheritance) {1813 std::string Code = R"(1814 struct Base1 {1815 int base1;1816 };1817 struct Intermediate : Base1 {1818 int intermediate;1819 };1820 struct Base2 {1821 int base2;1822 };1823 struct MostDerived : public Intermediate, Base2 {1824 int most_derived;1825 };1826 1827 void target() {1828 MostDerived MD = {};1829 // [[p]]1830 }1831 )";1832 runDataflow(1833 Code,1834 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1835 ASTContext &ASTCtx) {1836 const Environment &Env =1837 getEnvironmentAtAnnotation(Results, "p");1838 1839 // When a struct is initialized with a initializer list, all the1840 // fields are considered "accessed", and therefore do exist.1841 auto &MD = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "MD");1842 ASSERT_THAT(cast<IntegerValue>(1843 getFieldValue(&MD, *findValueDecl(ASTCtx, "base1"), Env)),1844 NotNull());1845 ASSERT_THAT(cast<IntegerValue>(1846 getFieldValue(&MD, *findValueDecl(ASTCtx, "intermediate"), Env)),1847 NotNull());1848 ASSERT_THAT(cast<IntegerValue>(1849 getFieldValue(&MD, *findValueDecl(ASTCtx, "base2"), Env)),1850 NotNull());1851 ASSERT_THAT(cast<IntegerValue>(1852 getFieldValue(&MD, *findValueDecl(ASTCtx, "most_derived"), Env)),1853 NotNull());1854 });1855}1856 1857TEST(TransferTest, ReferenceMember) {1858 std::string Code = R"(1859 struct A {1860 int &Bar;1861 };1862 1863 void target(A Foo) {1864 int Baz = Foo.Bar;1865 // [[p]]1866 }1867 )";1868 runDataflow(1869 Code,1870 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1871 ASTContext &ASTCtx) {1872 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));1873 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");1874 1875 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");1876 ASSERT_THAT(FooDecl, NotNull());1877 1878 ASSERT_TRUE(FooDecl->getType()->isStructureType());1879 auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();1880 1881 FieldDecl *BarDecl = nullptr;1882 for (FieldDecl *Field : FooFields) {1883 if (Field->getNameAsString() == "Bar") {1884 BarDecl = Field;1885 } else {1886 FAIL() << "Unexpected field: " << Field->getNameAsString();1887 }1888 }1889 ASSERT_THAT(BarDecl, NotNull());1890 1891 const auto *FooLoc =1892 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));1893 const auto *BarReferentVal =1894 cast<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env));1895 1896 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");1897 ASSERT_THAT(BazDecl, NotNull());1898 1899 EXPECT_EQ(Env.getValue(*BazDecl), BarReferentVal);1900 });1901}1902 1903TEST(TransferTest, StructThisMember) {1904 std::string Code = R"(1905 struct A {1906 int Bar;1907 1908 struct B {1909 int Baz;1910 };1911 1912 B Qux;1913 1914 void target() {1915 int Foo = Bar;1916 int Quux = Qux.Baz;1917 // [[p]]1918 }1919 };1920 )";1921 runDataflow(1922 Code,1923 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1924 ASTContext &ASTCtx) {1925 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));1926 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");1927 1928 const auto *ThisLoc = Env.getThisPointeeStorageLocation();1929 ASSERT_THAT(ThisLoc, NotNull());1930 1931 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");1932 ASSERT_THAT(BarDecl, NotNull());1933 1934 const auto *BarLoc =1935 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl));1936 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));1937 1938 const Value *BarVal = Env.getValue(*BarLoc);1939 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));1940 1941 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");1942 ASSERT_THAT(FooDecl, NotNull());1943 EXPECT_EQ(Env.getValue(*FooDecl), BarVal);1944 1945 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");1946 ASSERT_THAT(QuxDecl, NotNull());1947 1948 ASSERT_TRUE(QuxDecl->getType()->isStructureType());1949 auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields();1950 1951 FieldDecl *BazDecl = nullptr;1952 for (FieldDecl *Field : QuxFields) {1953 if (Field->getNameAsString() == "Baz") {1954 BazDecl = Field;1955 } else {1956 FAIL() << "Unexpected field: " << Field->getNameAsString();1957 }1958 }1959 ASSERT_THAT(BazDecl, NotNull());1960 1961 const auto *QuxLoc =1962 cast<RecordStorageLocation>(ThisLoc->getChild(*QuxDecl));1963 1964 const auto *BazVal =1965 cast<IntegerValue>(getFieldValue(QuxLoc, *BazDecl, Env));1966 1967 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");1968 ASSERT_THAT(QuuxDecl, NotNull());1969 EXPECT_EQ(Env.getValue(*QuuxDecl), BazVal);1970 });1971}1972 1973TEST(TransferTest, ClassThisMember) {1974 std::string Code = R"(1975 class A {1976 int Bar;1977 1978 class B {1979 public:1980 int Baz;1981 };1982 1983 B Qux;1984 1985 void target() {1986 int Foo = Bar;1987 int Quux = Qux.Baz;1988 // [[p]]1989 }1990 };1991 )";1992 runDataflow(1993 Code,1994 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,1995 ASTContext &ASTCtx) {1996 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));1997 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");1998 1999 const auto *ThisLoc = Env.getThisPointeeStorageLocation();2000 2001 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");2002 ASSERT_THAT(BarDecl, NotNull());2003 2004 const auto *BarLoc =2005 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl));2006 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));2007 2008 const Value *BarVal = Env.getValue(*BarLoc);2009 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));2010 2011 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");2012 ASSERT_THAT(FooDecl, NotNull());2013 EXPECT_EQ(Env.getValue(*FooDecl), BarVal);2014 2015 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");2016 ASSERT_THAT(QuxDecl, NotNull());2017 2018 ASSERT_TRUE(QuxDecl->getType()->isClassType());2019 auto QuxFields = QuxDecl->getType()->getAsRecordDecl()->fields();2020 2021 FieldDecl *BazDecl = nullptr;2022 for (FieldDecl *Field : QuxFields) {2023 if (Field->getNameAsString() == "Baz") {2024 BazDecl = Field;2025 } else {2026 FAIL() << "Unexpected field: " << Field->getNameAsString();2027 }2028 }2029 ASSERT_THAT(BazDecl, NotNull());2030 2031 const auto *QuxLoc =2032 cast<RecordStorageLocation>(ThisLoc->getChild(*QuxDecl));2033 2034 const auto *BazVal =2035 cast<IntegerValue>(getFieldValue(QuxLoc, *BazDecl, Env));2036 2037 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");2038 ASSERT_THAT(QuuxDecl, NotNull());2039 EXPECT_EQ(Env.getValue(*QuuxDecl), BazVal);2040 });2041}2042 2043TEST(TransferTest, UnionThisMember) {2044 std::string Code = R"(2045 union A {2046 int Foo;2047 int Bar;2048 2049 void target() {2050 A a;2051 // Mention the fields to ensure they're included in the analysis.2052 (void)a.Foo;2053 (void)a.Bar;2054 // [[p]]2055 }2056 };2057 )";2058 runDataflow(2059 Code,2060 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2061 ASTContext &ASTCtx) {2062 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));2063 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");2064 2065 const auto *ThisLoc = Env.getThisPointeeStorageLocation();2066 ASSERT_THAT(ThisLoc, NotNull());2067 2068 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");2069 ASSERT_THAT(FooDecl, NotNull());2070 2071 const auto *FooLoc =2072 cast<ScalarStorageLocation>(ThisLoc->getChild(*FooDecl));2073 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));2074 2075 const Value *FooVal = Env.getValue(*FooLoc);2076 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));2077 2078 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");2079 ASSERT_THAT(BarDecl, NotNull());2080 2081 const auto *BarLoc =2082 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl));2083 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));2084 2085 const Value *BarVal = Env.getValue(*BarLoc);2086 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));2087 });2088}2089 2090TEST(TransferTest, StructThisInLambda) {2091 std::string ThisCaptureCode = R"(2092 struct A {2093 void frob() {2094 [this]() {2095 int Foo = Bar;2096 // [[p1]]2097 }();2098 }2099 2100 int Bar;2101 };2102 )";2103 runDataflow(2104 ThisCaptureCode,2105 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2106 ASTContext &ASTCtx) {2107 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1"));2108 const Environment &Env = getEnvironmentAtAnnotation(Results, "p1");2109 2110 const auto *ThisLoc = Env.getThisPointeeStorageLocation();2111 ASSERT_THAT(ThisLoc, NotNull());2112 2113 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");2114 ASSERT_THAT(BarDecl, NotNull());2115 2116 const auto *BarLoc =2117 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl));2118 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));2119 2120 const Value *BarVal = Env.getValue(*BarLoc);2121 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));2122 2123 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");2124 ASSERT_THAT(FooDecl, NotNull());2125 EXPECT_EQ(Env.getValue(*FooDecl), BarVal);2126 },2127 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()");2128 2129 std::string RefCaptureDefaultCode = R"(2130 struct A {2131 void frob() {2132 [&]() {2133 int Foo = Bar;2134 // [[p2]]2135 }();2136 }2137 2138 int Bar;2139 };2140 )";2141 runDataflow(2142 RefCaptureDefaultCode,2143 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2144 ASTContext &ASTCtx) {2145 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p2"));2146 const Environment &Env = getEnvironmentAtAnnotation(Results, "p2");2147 2148 const auto *ThisLoc = Env.getThisPointeeStorageLocation();2149 ASSERT_THAT(ThisLoc, NotNull());2150 2151 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");2152 ASSERT_THAT(BarDecl, NotNull());2153 2154 const auto *BarLoc =2155 cast<ScalarStorageLocation>(ThisLoc->getChild(*BarDecl));2156 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));2157 2158 const Value *BarVal = Env.getValue(*BarLoc);2159 ASSERT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));2160 2161 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");2162 ASSERT_THAT(FooDecl, NotNull());2163 EXPECT_EQ(Env.getValue(*FooDecl), BarVal);2164 },2165 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()");2166 2167 std::string FreeFunctionLambdaCode = R"(2168 void foo() {2169 int Bar;2170 [&]() {2171 int Foo = Bar;2172 // [[p3]]2173 }();2174 }2175 )";2176 runDataflow(2177 FreeFunctionLambdaCode,2178 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2179 ASTContext &ASTCtx) {2180 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p3"));2181 const Environment &Env = getEnvironmentAtAnnotation(Results, "p3");2182 2183 EXPECT_THAT(Env.getThisPointeeStorageLocation(), IsNull());2184 },2185 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator()");2186}2187 2188TEST(TransferTest, ConstructorInitializer) {2189 std::string Code = R"(2190 struct target {2191 int Bar;2192 2193 target(int Foo) : Bar(Foo) {2194 int Qux = Bar;2195 // [[p]]2196 }2197 };2198 )";2199 runDataflow(2200 Code,2201 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2202 ASTContext &ASTCtx) {2203 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));2204 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");2205 2206 const auto *ThisLoc = Env.getThisPointeeStorageLocation();2207 ASSERT_THAT(ThisLoc, NotNull());2208 2209 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");2210 ASSERT_THAT(FooDecl, NotNull());2211 2212 const auto *FooVal = cast<IntegerValue>(Env.getValue(*FooDecl));2213 2214 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");2215 ASSERT_THAT(QuxDecl, NotNull());2216 EXPECT_EQ(Env.getValue(*QuxDecl), FooVal);2217 });2218}2219 2220TEST(TransferTest, DefaultInitializer) {2221 std::string Code = R"(2222 struct target {2223 int Bar;2224 int Baz = Bar;2225 2226 target(int Foo) : Bar(Foo) {2227 int Qux = Baz;2228 // [[p]]2229 }2230 };2231 )";2232 runDataflow(2233 Code,2234 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2235 ASTContext &ASTCtx) {2236 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));2237 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");2238 2239 const auto *ThisLoc = Env.getThisPointeeStorageLocation();2240 ASSERT_THAT(ThisLoc, NotNull());2241 2242 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");2243 ASSERT_THAT(FooDecl, NotNull());2244 2245 const auto *FooVal = cast<IntegerValue>(Env.getValue(*FooDecl));2246 2247 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");2248 ASSERT_THAT(QuxDecl, NotNull());2249 EXPECT_EQ(Env.getValue(*QuxDecl), FooVal);2250 });2251}2252 2253TEST(TransferTest, DefaultInitializerReference) {2254 std::string Code = R"(2255 struct target {2256 int &Bar;2257 int &Baz = Bar;2258 2259 target(int &Foo) : Bar(Foo) {2260 int &Qux = Baz;2261 // [[p]]2262 }2263 };2264 )";2265 runDataflow(2266 Code,2267 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2268 ASTContext &ASTCtx) {2269 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));2270 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");2271 2272 const auto *ThisLoc = Env.getThisPointeeStorageLocation();2273 ASSERT_THAT(ThisLoc, NotNull());2274 2275 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");2276 ASSERT_THAT(FooDecl, NotNull());2277 2278 const auto *FooLoc = Env.getStorageLocation(*FooDecl);2279 2280 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");2281 ASSERT_THAT(QuxDecl, NotNull());2282 2283 const auto *QuxLoc = Env.getStorageLocation(*QuxDecl);2284 EXPECT_EQ(QuxLoc, FooLoc);2285 });2286}2287 2288TEST(TransferTest, TemporaryObject) {2289 std::string Code = R"(2290 struct A {2291 int Bar;2292 };2293 2294 void target() {2295 A Foo = A();2296 (void)Foo.Bar;2297 // [[p]]2298 }2299 )";2300 runDataflow(2301 Code,2302 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2303 ASTContext &ASTCtx) {2304 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));2305 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");2306 2307 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");2308 ASSERT_THAT(FooDecl, NotNull());2309 2310 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");2311 ASSERT_THAT(BarDecl, NotNull());2312 2313 const auto *FooLoc =2314 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));2315 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));2316 });2317}2318 2319TEST(TransferTest, ElidableConstructor) {2320 // This test is effectively the same as TransferTest.TemporaryObject, but2321 // the code is compiled as C++14.2322 std::string Code = R"(2323 struct A {2324 int Bar;2325 };2326 2327 void target() {2328 A Foo = A();2329 (void)Foo.Bar;2330 // [[p]]2331 }2332 )";2333 runDataflow(2334 Code,2335 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2336 ASTContext &ASTCtx) {2337 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));2338 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");2339 2340 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");2341 ASSERT_THAT(FooDecl, NotNull());2342 2343 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");2344 ASSERT_THAT(BarDecl, NotNull());2345 2346 const auto *FooLoc =2347 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));2348 EXPECT_TRUE(isa<IntegerValue>(getFieldValue(FooLoc, *BarDecl, Env)));2349 },2350 LangStandard::lang_cxx14);2351}2352 2353TEST(TransferTest, AssignmentOperator) {2354 std::string Code = R"(2355 struct A {2356 int Baz;2357 };2358 2359 void target() {2360 A Foo = { 1 };2361 A Bar = { 2 };2362 // [[p1]]2363 A &Rval = (Foo = Bar);2364 // [[p2]]2365 Foo.Baz = 3;2366 // [[p3]]2367 }2368 )";2369 runDataflow(2370 Code,2371 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2372 ASTContext &ASTCtx) {2373 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");2374 ASSERT_THAT(FooDecl, NotNull());2375 2376 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");2377 ASSERT_THAT(BarDecl, NotNull());2378 2379 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");2380 ASSERT_THAT(BazDecl, NotNull());2381 2382 // Before copy assignment.2383 {2384 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");2385 2386 const auto *FooLoc1 =2387 cast<RecordStorageLocation>(Env1.getStorageLocation(*FooDecl));2388 const auto *BarLoc1 =2389 cast<RecordStorageLocation>(Env1.getStorageLocation(*BarDecl));2390 EXPECT_FALSE(recordsEqual(*FooLoc1, *BarLoc1, Env1));2391 2392 const auto *FooBazVal1 =2393 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env1));2394 const auto *BarBazVal1 =2395 cast<IntegerValue>(getFieldValue(BarLoc1, *BazDecl, Env1));2396 EXPECT_NE(FooBazVal1, BarBazVal1);2397 }2398 2399 // After copy assignment.2400 {2401 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");2402 2403 const auto *FooLoc2 =2404 cast<RecordStorageLocation>(Env2.getStorageLocation(*FooDecl));2405 const auto *BarLoc2 =2406 cast<RecordStorageLocation>(Env2.getStorageLocation(*BarDecl));2407 2408 EXPECT_TRUE(recordsEqual(*FooLoc2, *BarLoc2, Env2));2409 EXPECT_EQ(&getLocForDecl(ASTCtx, Env2, "Rval"), FooLoc2);2410 2411 const auto *FooBazVal2 =2412 cast<IntegerValue>(getFieldValue(FooLoc2, *BazDecl, Env2));2413 const auto *BarBazVal2 =2414 cast<IntegerValue>(getFieldValue(BarLoc2, *BazDecl, Env2));2415 EXPECT_EQ(FooBazVal2, BarBazVal2);2416 }2417 2418 // After value update.2419 {2420 const Environment &Env3 = getEnvironmentAtAnnotation(Results, "p3");2421 2422 const auto *FooLoc3 =2423 cast<RecordStorageLocation>(Env3.getStorageLocation(*FooDecl));2424 const auto *BarLoc3 =2425 cast<RecordStorageLocation>(Env3.getStorageLocation(*BarDecl));2426 EXPECT_FALSE(recordsEqual(*FooLoc3, *BarLoc3, Env3));2427 2428 const auto *FooBazVal3 =2429 cast<IntegerValue>(getFieldValue(FooLoc3, *BazDecl, Env3));2430 const auto *BarBazVal3 =2431 cast<IntegerValue>(getFieldValue(BarLoc3, *BazDecl, Env3));2432 EXPECT_NE(FooBazVal3, BarBazVal3);2433 }2434 });2435}2436 2437// It's legal for the assignment operator to take its source parameter by value.2438// Check that we handle this correctly. (This is a repro -- we used to2439// assert-fail on this.)2440TEST(TransferTest, AssignmentOperator_ArgByValue) {2441 std::string Code = R"(2442 struct A {2443 int Baz;2444 A &operator=(A);2445 };2446 2447 void target() {2448 A Foo = { 1 };2449 A Bar = { 2 };2450 Foo = Bar;2451 // [[p]]2452 }2453 )";2454 runDataflow(2455 Code,2456 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2457 ASTContext &ASTCtx) {2458 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");2459 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");2460 2461 const auto &FooLoc =2462 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo");2463 const auto &BarLoc =2464 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar");2465 2466 const auto *FooBazVal =2467 cast<IntegerValue>(getFieldValue(&FooLoc, *BazDecl, Env));2468 const auto *BarBazVal =2469 cast<IntegerValue>(getFieldValue(&BarLoc, *BazDecl, Env));2470 EXPECT_EQ(FooBazVal, BarBazVal);2471 });2472}2473 2474TEST(TransferTest, AssignmentOperatorFromBase) {2475 std::string Code = R"(2476 struct Base {2477 int base;2478 };2479 struct Derived : public Base {2480 using Base::operator=;2481 int derived;2482 };2483 void target(Base B, Derived D) {2484 D.base = 1;2485 D.derived = 1;2486 // [[before]]2487 D = B;2488 // [[after]]2489 }2490 )";2491 runDataflow(2492 Code,2493 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2494 ASTContext &ASTCtx) {2495 const Environment &EnvBefore =2496 getEnvironmentAtAnnotation(Results, "before");2497 const Environment &EnvAfter =2498 getEnvironmentAtAnnotation(Results, "after");2499 2500 auto &BLoc =2501 getLocForDecl<RecordStorageLocation>(ASTCtx, EnvBefore, "B");2502 auto &DLoc =2503 getLocForDecl<RecordStorageLocation>(ASTCtx, EnvBefore, "D");2504 2505 EXPECT_NE(getFieldValue(&BLoc, "base", ASTCtx, EnvBefore),2506 getFieldValue(&DLoc, "base", ASTCtx, EnvBefore));2507 EXPECT_EQ(getFieldValue(&BLoc, "base", ASTCtx, EnvAfter),2508 getFieldValue(&DLoc, "base", ASTCtx, EnvAfter));2509 2510 EXPECT_EQ(getFieldValue(&DLoc, "derived", ASTCtx, EnvBefore),2511 getFieldValue(&DLoc, "derived", ASTCtx, EnvAfter));2512 });2513}2514 2515TEST(TransferTest, AssignmentOperatorFromCallResult) {2516 std::string Code = R"(2517 struct A {};2518 A ReturnA();2519 2520 void target() {2521 A MyA;2522 MyA = ReturnA();2523 }2524 )";2525 runDataflow(2526 Code,2527 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2528 ASTContext &ASTCtx) {2529 // As of this writing, we don't produce a `Value` for the call2530 // `ReturnA()`. The only condition we're testing for is that the2531 // analysis should not crash in this case.2532 });2533}2534 2535TEST(TransferTest, AssignmentOperatorWithInitAndInheritance) {2536 // This is a crash repro.2537 std::string Code = R"(2538 struct B { int Foo; };2539 struct S : public B {};2540 void target() {2541 S S1 = { 1 };2542 S S2;2543 S S3;2544 S1 = S2; // Only Dst has InitListExpr.2545 S3 = S1; // Only Src has InitListExpr.2546 // [[p]]2547 }2548 )";2549 runDataflow(2550 Code,2551 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2552 ASTContext &ASTCtx) {});2553}2554 2555TEST(TransferTest, AssignmentOperatorReturnsVoid) {2556 // This is a crash repro.2557 std::string Code = R"(2558 struct S {2559 void operator=(S&& other);2560 };2561 void target() {2562 S s;2563 s = S();2564 // [[p]]2565 }2566 )";2567 runDataflow(2568 Code,2569 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2570 ASTContext &ASTCtx) {});2571}2572 2573TEST(TransferTest, AssignmentOperatorReturnsByValue) {2574 // This is a crash repro.2575 std::string Code = R"(2576 struct S {2577 S operator=(const S&);2578 int i;2579 };2580 void target() {2581 S S1 = { 1 };2582 S S2 = { 2 };2583 S S3 = { 3 };2584 // [[before]]2585 // Test that the returned value is modeled by assigning to another value.2586 S1 = (S2 = S3);2587 (void)0;2588 // [[after]]2589 }2590 )";2591 runDataflow(2592 Code,2593 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2594 ASTContext &ASTCtx) {2595 const ValueDecl *S1Decl = findValueDecl(ASTCtx, "S1");2596 const ValueDecl *S2Decl = findValueDecl(ASTCtx, "S2");2597 const ValueDecl *S3Decl = findValueDecl(ASTCtx, "S3");2598 2599 const Environment &EnvBefore =2600 getEnvironmentAtAnnotation(Results, "before");2601 2602 EXPECT_FALSE(recordsEqual(2603 *EnvBefore.get<RecordStorageLocation>(*S1Decl),2604 *EnvBefore.get<RecordStorageLocation>(*S2Decl), EnvBefore));2605 EXPECT_FALSE(recordsEqual(2606 *EnvBefore.get<RecordStorageLocation>(*S2Decl),2607 *EnvBefore.get<RecordStorageLocation>(*S3Decl), EnvBefore));2608 2609 const Environment &EnvAfter =2610 getEnvironmentAtAnnotation(Results, "after");2611 2612 EXPECT_TRUE(recordsEqual(*EnvAfter.get<RecordStorageLocation>(*S1Decl),2613 *EnvAfter.get<RecordStorageLocation>(*S2Decl),2614 EnvAfter));2615 EXPECT_TRUE(recordsEqual(*EnvAfter.get<RecordStorageLocation>(*S2Decl),2616 *EnvAfter.get<RecordStorageLocation>(*S3Decl),2617 EnvAfter));2618 });2619}2620 2621TEST(TransferTest, AssignmentOperatorReturnsDifferentTypeByRef) {2622 // This is a crash repro.2623 std::string Code = R"(2624 struct DifferentType {};2625 struct S {2626 DifferentType& operator=(const S&);2627 };2628 void target() {2629 S s;2630 s = S();2631 // [[p]]2632 }2633 )";2634 runDataflow(2635 Code,2636 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2637 ASTContext &ASTCtx) {});2638}2639 2640TEST(TransferTest, AssignmentOperatorReturnsDifferentTypeByValue) {2641 // This is a crash repro.2642 std::string Code = R"(2643 struct DifferentType {};2644 struct S {2645 DifferentType operator=(const S&);2646 };2647 void target() {2648 S s;2649 s = S();2650 // [[p]]2651 }2652 )";2653 runDataflow(2654 Code,2655 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2656 ASTContext &ASTCtx) {});2657}2658 2659TEST(TransferTest, InitListExprAsXValue) {2660 // This is a crash repro.2661 std::string Code = R"(2662 void target() {2663 bool&& Foo{false};2664 // [[p]]2665 }2666 )";2667 runDataflow(2668 Code,2669 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2670 ASTContext &ASTCtx) {2671 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");2672 const auto &FooVal = getValueForDecl<BoolValue>(ASTCtx, Env, "Foo");2673 ASSERT_TRUE(FooVal.formula().isLiteral(false));2674 });2675}2676 2677TEST(TransferTest, ArrayInitListExprOneRecordElement) {2678 // This is a crash repro.2679 std::string Code = R"cc(2680 struct S {};2681 2682 void target() { S foo[] = {S()}; }2683 )cc";2684 runDataflow(2685 Code,2686 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2687 ASTContext &ASTCtx) {2688 // Just verify that it doesn't crash.2689 });2690}2691 2692TEST(TransferTest, InitListExprAsUnion) {2693 // This is a crash repro.2694 std::string Code = R"cc(2695 class target {2696 union {2697 int *a;2698 bool *b;2699 } F;2700 2701 public:2702 constexpr target() : F{nullptr} {2703 int *null = nullptr;2704 F.b; // Make sure we reference 'b' so it is modeled.2705 // [[p]]2706 }2707 };2708 )cc";2709 runDataflow(2710 Code,2711 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2712 ASTContext &ASTCtx) {2713 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");2714 2715 auto &FLoc = getFieldLoc<RecordStorageLocation>(2716 *Env.getThisPointeeStorageLocation(), "F", ASTCtx);2717 auto *AVal = cast<PointerValue>(getFieldValue(&FLoc, "a", ASTCtx, Env));2718 EXPECT_EQ(AVal, &getValueForDecl<PointerValue>(ASTCtx, Env, "null"));2719 EXPECT_EQ(getFieldValue(&FLoc, "b", ASTCtx, Env), nullptr);2720 });2721}2722 2723TEST(TransferTest, EmptyInitListExprForUnion) {2724 // This is a crash repro.2725 std::string Code = R"cc(2726 class target {2727 union {2728 int *a;2729 bool *b;2730 } F;2731 2732 public:2733 // Empty initializer list means that `F` is aggregate-initialized.2734 // For a union, this has the effect that the first member of the union2735 // is copy-initialized from an empty initializer list; in this specific2736 // case, this has the effect of initializing `a` with null.2737 constexpr target() : F{} {2738 int *null = nullptr;2739 F.b; // Make sure we reference 'b' so it is modeled.2740 // [[p]]2741 }2742 };2743 )cc";2744 runDataflow(2745 Code,2746 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2747 ASTContext &ASTCtx) {2748 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");2749 2750 auto &FLoc = getFieldLoc<RecordStorageLocation>(2751 *Env.getThisPointeeStorageLocation(), "F", ASTCtx);2752 auto *AVal = cast<PointerValue>(getFieldValue(&FLoc, "a", ASTCtx, Env));2753 EXPECT_EQ(AVal, &getValueForDecl<PointerValue>(ASTCtx, Env, "null"));2754 EXPECT_EQ(getFieldValue(&FLoc, "b", ASTCtx, Env), nullptr);2755 });2756}2757 2758TEST(TransferTest, EmptyInitListExprForStruct) {2759 std::string Code = R"cc(2760 class target {2761 struct {2762 int *a;2763 bool *b;2764 } F;2765 2766 public:2767 constexpr target() : F{} {2768 int *NullIntPtr = nullptr;2769 bool *NullBoolPtr = nullptr;2770 // [[p]]2771 }2772 };2773 )cc";2774 runDataflow(2775 Code,2776 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2777 ASTContext &ASTCtx) {2778 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");2779 2780 auto &FLoc = getFieldLoc<RecordStorageLocation>(2781 *Env.getThisPointeeStorageLocation(), "F", ASTCtx);2782 auto *AVal = cast<PointerValue>(getFieldValue(&FLoc, "a", ASTCtx, Env));2783 EXPECT_EQ(AVal,2784 &getValueForDecl<PointerValue>(ASTCtx, Env, "NullIntPtr"));2785 auto *BVal = cast<PointerValue>(getFieldValue(&FLoc, "b", ASTCtx, Env));2786 EXPECT_EQ(BVal,2787 &getValueForDecl<PointerValue>(ASTCtx, Env, "NullBoolPtr"));2788 });2789}2790 2791TEST(TransferTest, CopyConstructor) {2792 std::string Code = R"(2793 struct A {2794 int Baz;2795 };2796 2797 void target() {2798 A Foo = { 1 };2799 A Bar = Foo;2800 // [[after_copy]]2801 Foo.Baz = 2;2802 // [[after_update]]2803 }2804 )";2805 runDataflow(2806 Code,2807 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2808 ASTContext &ASTCtx) {2809 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");2810 ASSERT_THAT(FooDecl, NotNull());2811 2812 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");2813 ASSERT_THAT(BarDecl, NotNull());2814 2815 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");2816 ASSERT_THAT(BazDecl, NotNull());2817 2818 // after_copy2819 {2820 const Environment &Env =2821 getEnvironmentAtAnnotation(Results, "after_copy");2822 2823 const auto *FooLoc =2824 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));2825 const auto *BarLoc =2826 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl));2827 2828 // The records compare equal.2829 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env));2830 2831 // In particular, the value of `Baz` in both records is the same.2832 const auto *FooBazVal =2833 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env));2834 const auto *BarBazVal =2835 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env));2836 EXPECT_EQ(FooBazVal, BarBazVal);2837 }2838 2839 // after_update2840 {2841 const Environment &Env =2842 getEnvironmentAtAnnotation(Results, "after_update");2843 2844 const auto *FooLoc =2845 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));2846 const auto *BarLoc =2847 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl));2848 2849 EXPECT_FALSE(recordsEqual(*FooLoc, *BarLoc, Env));2850 2851 const auto *FooBazVal =2852 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env));2853 const auto *BarBazVal =2854 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env));2855 EXPECT_NE(FooBazVal, BarBazVal);2856 }2857 });2858}2859 2860TEST(TransferTest, CopyConstructorWithDefaultArgument) {2861 std::string Code = R"(2862 struct A {2863 int Baz;2864 A() = default;2865 A(const A& a, bool def = true) { Baz = a.Baz; }2866 };2867 2868 void target() {2869 A Foo;2870 (void)Foo.Baz;2871 A Bar = Foo;2872 // [[p]]2873 }2874 )";2875 runDataflow(2876 Code,2877 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2878 ASTContext &ASTCtx) {2879 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));2880 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");2881 2882 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");2883 ASSERT_THAT(FooDecl, NotNull());2884 2885 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");2886 ASSERT_THAT(BarDecl, NotNull());2887 2888 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");2889 ASSERT_THAT(BazDecl, NotNull());2890 2891 const auto *FooLoc =2892 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));2893 const auto *BarLoc =2894 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl));2895 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env));2896 2897 const auto *FooBazVal =2898 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env));2899 const auto *BarBazVal =2900 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env));2901 EXPECT_EQ(FooBazVal, BarBazVal);2902 });2903}2904 2905TEST(TransferTest, CopyConstructorWithParens) {2906 std::string Code = R"(2907 struct A {2908 int Baz;2909 };2910 2911 void target() {2912 A Foo;2913 (void)Foo.Baz;2914 A Bar((A(Foo)));2915 // [[p]]2916 }2917 )";2918 runDataflow(2919 Code,2920 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2921 ASTContext &ASTCtx) {2922 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));2923 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");2924 2925 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");2926 ASSERT_THAT(FooDecl, NotNull());2927 2928 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");2929 ASSERT_THAT(BarDecl, NotNull());2930 2931 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");2932 ASSERT_THAT(BazDecl, NotNull());2933 2934 const auto *FooLoc =2935 cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));2936 const auto *BarLoc =2937 cast<RecordStorageLocation>(Env.getStorageLocation(*BarDecl));2938 EXPECT_TRUE(recordsEqual(*FooLoc, *BarLoc, Env));2939 2940 const auto *FooBazVal =2941 cast<IntegerValue>(getFieldValue(FooLoc, *BazDecl, Env));2942 const auto *BarBazVal =2943 cast<IntegerValue>(getFieldValue(BarLoc, *BazDecl, Env));2944 EXPECT_EQ(FooBazVal, BarBazVal);2945 });2946}2947 2948TEST(TransferTest, CopyConstructorWithInitializerListAsSyntacticSugar) {2949 std::string Code = R"(2950 struct A {2951 int Baz;2952 };2953 void target() {2954 A Foo = {3};2955 (void)Foo.Baz;2956 A Bar = {A(Foo)};2957 // [[p]]2958 }2959 )";2960 runDataflow(2961 Code,2962 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2963 ASTContext &ASTCtx) {2964 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");2965 2966 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");2967 2968 const auto &FooLoc =2969 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo");2970 const auto &BarLoc =2971 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar");2972 2973 const auto *FooBazVal =2974 cast<IntegerValue>(getFieldValue(&FooLoc, *BazDecl, Env));2975 const auto *BarBazVal =2976 cast<IntegerValue>(getFieldValue(&BarLoc, *BazDecl, Env));2977 EXPECT_EQ(FooBazVal, BarBazVal);2978 });2979}2980 2981TEST(TransferTest, CopyConstructorArgIsRefReturnedByFunction) {2982 // This is a crash repro.2983 std::string Code = R"(2984 struct S {};2985 const S &returnsSRef();2986 void target() {2987 S s(returnsSRef());2988 }2989 )";2990 runDataflow(2991 Code,2992 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,2993 ASTContext &ASTCtx) {});2994}2995 2996TEST(TransferTest, MoveConstructor) {2997 std::string Code = R"(2998 namespace std {2999 3000 template <typename T> struct remove_reference { using type = T; };3001 template <typename T> struct remove_reference<T&> { using type = T; };3002 template <typename T> struct remove_reference<T&&> { using type = T; };3003 3004 template <typename T>3005 using remove_reference_t = typename remove_reference<T>::type;3006 3007 template <typename T>3008 std::remove_reference_t<T>&& move(T&& x);3009 3010 } // namespace std3011 3012 struct A {3013 int Baz;3014 };3015 3016 void target() {3017 A Foo;3018 A Bar;3019 (void)Foo.Baz;3020 // [[p1]]3021 Foo = std::move(Bar);3022 // [[p2]]3023 }3024 )";3025 runDataflow(3026 Code,3027 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3028 ASTContext &ASTCtx) {3029 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));3030 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");3031 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");3032 3033 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");3034 ASSERT_THAT(FooDecl, NotNull());3035 3036 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");3037 ASSERT_THAT(BarDecl, NotNull());3038 3039 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");3040 ASSERT_THAT(BazDecl, NotNull());3041 3042 const auto *FooLoc1 =3043 cast<RecordStorageLocation>(Env1.getStorageLocation(*FooDecl));3044 const auto *BarLoc1 =3045 cast<RecordStorageLocation>(Env1.getStorageLocation(*BarDecl));3046 3047 EXPECT_FALSE(recordsEqual(*FooLoc1, *BarLoc1, Env1));3048 3049 const auto *FooBazVal1 =3050 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env1));3051 const auto *BarBazVal1 =3052 cast<IntegerValue>(getFieldValue(BarLoc1, *BazDecl, Env1));3053 EXPECT_NE(FooBazVal1, BarBazVal1);3054 3055 const auto *FooLoc2 =3056 cast<RecordStorageLocation>(Env2.getStorageLocation(*FooDecl));3057 EXPECT_TRUE(recordsEqual(*FooLoc2, Env2, *BarLoc1, Env1));3058 3059 const auto *FooBazVal2 =3060 cast<IntegerValue>(getFieldValue(FooLoc1, *BazDecl, Env2));3061 EXPECT_EQ(FooBazVal2, BarBazVal1);3062 });3063}3064 3065TEST(TransferTest, BindTemporary) {3066 std::string Code = R"(3067 struct A {3068 virtual ~A() = default;3069 3070 int Baz;3071 };3072 3073 void target(A Foo) {3074 int Bar = A(Foo).Baz;3075 // [[p]]3076 }3077 )";3078 runDataflow(3079 Code,3080 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3081 ASTContext &ASTCtx) {3082 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));3083 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3084 3085 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");3086 ASSERT_THAT(FooDecl, NotNull());3087 3088 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");3089 ASSERT_THAT(BarDecl, NotNull());3090 3091 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");3092 ASSERT_THAT(BazDecl, NotNull());3093 3094 const auto &FooLoc =3095 *cast<RecordStorageLocation>(Env.getStorageLocation(*FooDecl));3096 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));3097 EXPECT_EQ(BarVal, getFieldValue(&FooLoc, *BazDecl, Env));3098 });3099}3100 3101TEST(TransferTest, ResultObjectLocation) {3102 std::string Code = R"(3103 struct A {3104 virtual ~A() = default;3105 };3106 3107 void target() {3108 0, A();3109 (void)0; // [[p]]3110 }3111 )";3112 using ast_matchers::binaryOperator;3113 using ast_matchers::cxxBindTemporaryExpr;3114 using ast_matchers::cxxTemporaryObjectExpr;3115 using ast_matchers::exprWithCleanups;3116 using ast_matchers::has;3117 using ast_matchers::hasOperatorName;3118 using ast_matchers::hasRHS;3119 using ast_matchers::match;3120 using ast_matchers::selectFirst;3121 using ast_matchers::traverse;3122 runDataflow(3123 Code,3124 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3125 ASTContext &ASTCtx) {3126 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3127 3128 // The expression `0, A()` in the code above produces the following3129 // structure, consisting of four prvalues of record type.3130 // `Env.getResultObjectLocation()` should return the same location for3131 // all of these.3132 auto MatchResult = match(3133 traverse(TK_AsIs,3134 exprWithCleanups(3135 has(binaryOperator(3136 hasOperatorName(","),3137 hasRHS(cxxBindTemporaryExpr(3138 has(cxxTemporaryObjectExpr().bind(3139 "toe")))3140 .bind("bte")))3141 .bind("comma")))3142 .bind("ewc")),3143 ASTCtx);3144 auto *TOE = selectFirst<CXXTemporaryObjectExpr>("toe", MatchResult);3145 ASSERT_NE(TOE, nullptr);3146 auto *Comma = selectFirst<BinaryOperator>("comma", MatchResult);3147 ASSERT_NE(Comma, nullptr);3148 auto *EWC = selectFirst<ExprWithCleanups>("ewc", MatchResult);3149 ASSERT_NE(EWC, nullptr);3150 auto *BTE = selectFirst<CXXBindTemporaryExpr>("bte", MatchResult);3151 ASSERT_NE(BTE, nullptr);3152 3153 RecordStorageLocation &Loc = Env.getResultObjectLocation(*TOE);3154 EXPECT_EQ(&Loc, &Env.getResultObjectLocation(*Comma));3155 EXPECT_EQ(&Loc, &Env.getResultObjectLocation(*EWC));3156 EXPECT_EQ(&Loc, &Env.getResultObjectLocation(*BTE));3157 });3158}3159 3160TEST(TransferTest, ResultObjectLocationForDefaultArgExpr) {3161 std::string Code = R"(3162 struct Inner {};3163 struct Outer {3164 Inner I = {};3165 };3166 3167 void funcWithDefaultArg(Outer O = {});3168 void target() {3169 funcWithDefaultArg();3170 // [[p]]3171 }3172 )";3173 3174 using ast_matchers::cxxDefaultArgExpr;3175 using ast_matchers::match;3176 using ast_matchers::selectFirst;3177 runDataflow(3178 Code,3179 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3180 ASTContext &ASTCtx) {3181 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3182 3183 auto *DefaultArg = selectFirst<CXXDefaultArgExpr>(3184 "default_arg",3185 match(cxxDefaultArgExpr().bind("default_arg"), ASTCtx));3186 ASSERT_NE(DefaultArg, nullptr);3187 3188 // The values for default arguments aren't modeled; we merely verify3189 // that we can get a result object location for a default arg.3190 Env.getResultObjectLocation(*DefaultArg);3191 });3192}3193 3194TEST(TransferTest, ResultObjectLocationForDefaultInitExpr) {3195 std::string Code = R"(3196 struct S {};3197 struct target {3198 target () {3199 (void)0;3200 // [[p]]3201 }3202 S s = {};3203 };3204 )";3205 3206 using ast_matchers::cxxCtorInitializer;3207 using ast_matchers::match;3208 using ast_matchers::selectFirst;3209 runDataflow(3210 Code,3211 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3212 ASTContext &ASTCtx) {3213 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3214 3215 const ValueDecl *SField = findValueDecl(ASTCtx, "s");3216 3217 auto *CtorInit = selectFirst<CXXCtorInitializer>(3218 "ctor_initializer",3219 match(cxxCtorInitializer().bind("ctor_initializer"), ASTCtx));3220 ASSERT_NE(CtorInit, nullptr);3221 3222 auto *DefaultInit = cast<CXXDefaultInitExpr>(CtorInit->getInit());3223 3224 RecordStorageLocation &Loc = Env.getResultObjectLocation(*DefaultInit);3225 3226 EXPECT_EQ(&Loc, Env.getThisPointeeStorageLocation()->getChild(*SField));3227 });3228}3229 3230// This test ensures that CXXOperatorCallExpr returning prvalues are correctly3231// handled by the transfer functions, especially that `getResultObjectLocation`3232// correctly returns a storage location for those.3233TEST(TransferTest, ResultObjectLocationForCXXOperatorCallExpr) {3234 std::string Code = R"(3235 struct A {3236 A operator+(int);3237 };3238 3239 void target() {3240 A a;3241 a + 3;3242 (void)0; // [[p]]3243 }3244 )";3245 using ast_matchers::cxxOperatorCallExpr;3246 using ast_matchers::match;3247 using ast_matchers::selectFirst;3248 using ast_matchers::traverse;3249 runDataflow(3250 Code,3251 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3252 ASTContext &ASTCtx) {3253 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3254 3255 auto *CallExpr = selectFirst<CXXOperatorCallExpr>(3256 "call_expr",3257 match(cxxOperatorCallExpr().bind("call_expr"), ASTCtx));3258 3259 EXPECT_NE(&Env.getResultObjectLocation(*CallExpr), nullptr);3260 });3261}3262 3263TEST(TransferTest, ResultObjectLocationForInitListExpr) {3264 std::string Code = R"cc(3265 struct Inner {};3266 3267 struct Outer { Inner I; };3268 3269 void target() {3270 Outer O = { Inner() };3271 // [[p]]3272 }3273 )cc";3274 using ast_matchers::asString;3275 using ast_matchers::cxxConstructExpr;3276 using ast_matchers::hasType;3277 using ast_matchers::match;3278 using ast_matchers::selectFirst;3279 using ast_matchers::traverse;3280 runDataflow(3281 Code,3282 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3283 ASTContext &ASTCtx) {3284 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3285 3286 auto *Construct = selectFirst<CXXConstructExpr>(3287 "construct",3288 match(3289 cxxConstructExpr(hasType(asString("Inner"))).bind("construct"),3290 ASTCtx));3291 3292 EXPECT_EQ(3293 &Env.getResultObjectLocation(*Construct),3294 &getFieldLoc(getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "O"),3295 "I", ASTCtx));3296 });3297}3298 3299TEST(TransferTest, ResultObjectLocationForParenInitListExpr) {3300 std::string Code = R"cc(3301 struct Inner {};3302 3303 struct Outer { Inner I; };3304 3305 void target() {3306 Outer O((Inner()));3307 // [[p]]3308 }3309 )cc";3310 using ast_matchers::asString;3311 using ast_matchers::cxxConstructExpr;3312 using ast_matchers::hasType;3313 using ast_matchers::match;3314 using ast_matchers::selectFirst;3315 using ast_matchers::traverse;3316 runDataflow(3317 Code,3318 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3319 ASTContext &ASTCtx) {3320 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3321 3322 auto *Construct = selectFirst<CXXConstructExpr>(3323 "construct",3324 match(3325 cxxConstructExpr(hasType(asString("Inner"))).bind("construct"),3326 ASTCtx));3327 3328 EXPECT_EQ(3329 &Env.getResultObjectLocation(*Construct),3330 &getFieldLoc(getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "O"),3331 "I", ASTCtx));3332 },3333 LangStandard::lang_cxx20);3334}3335 3336// Check that the `std::strong_ordering` object returned by builtin `<=>` has a3337// correctly modeled result object location.3338TEST(TransferTest, ResultObjectLocationForBuiltinSpaceshipOperator) {3339 std::string Code = R"(3340 namespace std {3341 // This is the minimal definition required to get3342 // `Sema::CheckComparisonCategoryType()` to accept this fake.3343 struct strong_ordering {3344 enum class ordering { less, equal, greater };3345 ordering o;3346 static const strong_ordering less;3347 static const strong_ordering equivalent;3348 static const strong_ordering equal;3349 static const strong_ordering greater;3350 };3351 3352 inline constexpr strong_ordering strong_ordering::less =3353 { strong_ordering::ordering::less };3354 inline constexpr strong_ordering strong_ordering::equal =3355 { strong_ordering::ordering::equal };3356 inline constexpr strong_ordering strong_ordering::equivalent =3357 { strong_ordering::ordering::equal };3358 inline constexpr strong_ordering strong_ordering::greater =3359 { strong_ordering::ordering::greater };3360 }3361 void target(int i, int j) {3362 auto ordering = i <=> j;3363 // [[p]]3364 }3365 )";3366 using ast_matchers::binaryOperator;3367 using ast_matchers::hasOperatorName;3368 using ast_matchers::match;3369 using ast_matchers::selectFirst;3370 using ast_matchers::traverse;3371 runDataflow(3372 Code,3373 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3374 ASTContext &ASTCtx) {3375 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3376 3377 auto *Spaceship = selectFirst<BinaryOperator>(3378 "op",3379 match(binaryOperator(hasOperatorName("<=>")).bind("op"), ASTCtx));3380 3381 EXPECT_EQ(3382 &Env.getResultObjectLocation(*Spaceship),3383 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "ordering"));3384 },3385 LangStandard::lang_cxx20);3386}3387 3388TEST(TransferTest, ResultObjectLocationForStdInitializerListExpr) {3389 std::string Code = R"(3390 namespace std {3391 template <typename T>3392 struct initializer_list { const T *a, *b; };3393 } // namespace std3394 3395 void target() {3396 std::initializer_list<int> list = {1};3397 // [[p]]3398 }3399 )";3400 3401 using ast_matchers::cxxStdInitializerListExpr;3402 using ast_matchers::match;3403 using ast_matchers::selectFirst;3404 runDataflow(3405 Code,3406 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3407 ASTContext &ASTCtx) {3408 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3409 3410 auto *StdInitList = selectFirst<CXXStdInitializerListExpr>(3411 "std_init_list",3412 match(cxxStdInitializerListExpr().bind("std_init_list"), ASTCtx));3413 ASSERT_NE(StdInitList, nullptr);3414 3415 EXPECT_EQ(&Env.getResultObjectLocation(*StdInitList),3416 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "list"));3417 });3418}3419 3420TEST(TransferTest, ResultObjectLocationForStmtExpr) {3421 std::string Code = R"(3422 struct S {};3423 void target() {3424 S s = ({ S(); });3425 // [[p]]3426 }3427 )";3428 using ast_matchers::cxxConstructExpr;3429 using ast_matchers::match;3430 using ast_matchers::selectFirst;3431 using ast_matchers::traverse;3432 runDataflow(3433 Code,3434 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3435 ASTContext &ASTCtx) {3436 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3437 3438 auto *Construct = selectFirst<CXXConstructExpr>(3439 "construct", match(cxxConstructExpr().bind("construct"), ASTCtx));3440 3441 EXPECT_EQ(&Env.getResultObjectLocation(*Construct),3442 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"));3443 });3444}3445 3446TEST(TransferTest, ResultObjectLocationForBuiltinBitCastExpr) {3447 std::string Code = R"(3448 struct S { int i; };3449 void target(int i) {3450 S s = __builtin_bit_cast(S, i);3451 // [[p]]3452 }3453 )";3454 using ast_matchers::explicitCastExpr;3455 using ast_matchers::match;3456 using ast_matchers::selectFirst;3457 using ast_matchers::traverse;3458 runDataflow(3459 Code,3460 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3461 ASTContext &ASTCtx) {3462 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3463 3464 auto *BuiltinBitCast = selectFirst<BuiltinBitCastExpr>(3465 "cast", match(explicitCastExpr().bind("cast"), ASTCtx));3466 3467 EXPECT_EQ(&Env.getResultObjectLocation(*BuiltinBitCast),3468 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"));3469 });3470}3471 3472TEST(TransferTest, ResultObjectLocationForAtomicExpr) {3473 std::string Code = R"(3474 struct S {};3475 void target(_Atomic(S) *ptr) {3476 S s = __c11_atomic_load(ptr, __ATOMIC_SEQ_CST);3477 // [[p]]3478 }3479 )";3480 using ast_matchers::atomicExpr;3481 using ast_matchers::match;3482 using ast_matchers::selectFirst;3483 using ast_matchers::traverse;3484 runDataflow(3485 Code,3486 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3487 ASTContext &ASTCtx) {3488 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3489 3490 auto *Atomic = selectFirst<AtomicExpr>(3491 "atomic", match(atomicExpr().bind("atomic"), ASTCtx));3492 3493 EXPECT_EQ(&Env.getResultObjectLocation(*Atomic),3494 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s"));3495 });3496}3497 3498TEST(TransferTest, ResultObjectLocationPropagatesThroughConditionalOperator) {3499 std::string Code = R"(3500 struct A {3501 A(int);3502 };3503 3504 void target(bool b) {3505 A a = b ? A(0) : A(1);3506 (void)0; // [[p]]3507 }3508 )";3509 using ast_matchers::cxxConstructExpr;3510 using ast_matchers::equals;3511 using ast_matchers::hasArgument;3512 using ast_matchers::integerLiteral;3513 using ast_matchers::match;3514 using ast_matchers::selectFirst;3515 using ast_matchers::traverse;3516 runDataflow(3517 Code,3518 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3519 ASTContext &ASTCtx) {3520 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3521 3522 auto *ConstructExpr0 = selectFirst<CXXConstructExpr>(3523 "construct",3524 match(cxxConstructExpr(hasArgument(0, integerLiteral(equals(0))))3525 .bind("construct"),3526 ASTCtx));3527 auto *ConstructExpr1 = selectFirst<CXXConstructExpr>(3528 "construct",3529 match(cxxConstructExpr(hasArgument(0, integerLiteral(equals(1))))3530 .bind("construct"),3531 ASTCtx));3532 3533 auto &ALoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "a");3534 EXPECT_EQ(&Env.getResultObjectLocation(*ConstructExpr0), &ALoc);3535 EXPECT_EQ(&Env.getResultObjectLocation(*ConstructExpr1), &ALoc);3536 });3537}3538 3539TEST(TransferTest, ResultObjectLocationDontVisitNestedRecordDecl) {3540 // This is a crash repro.3541 // We used to crash because when propagating result objects, we would visit3542 // nested record and function declarations, but we don't model fields used3543 // only in these.3544 std::string Code = R"(3545 struct S1 {};3546 struct S2 { S1 s1; };3547 void target() {3548 struct Nested {3549 void f() {3550 S2 s2 = { S1() };3551 }3552 };3553 }3554 )";3555 runDataflow(3556 Code,3557 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3558 ASTContext &ASTCtx) {});3559}3560 3561TEST(TransferTest, ResultObjectLocationDontVisitUnevaluatedContexts) {3562 // This is a crash repro.3563 // We used to crash because when propagating result objects, we would visit3564 // unevaluated contexts, but we don't model fields used only in these.3565 3566 auto testFunction = [](llvm::StringRef Code, llvm::StringRef TargetFun) {3567 runDataflow(3568 Code,3569 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3570 ASTContext &ASTCtx) {},3571 LangStandard::lang_gnucxx17,3572 /* ApplyBuiltinTransfer= */ true, TargetFun);3573 };3574 3575 std::string Code = R"cc(3576 // Definitions needed for `typeid`.3577 namespace std {3578 class type_info {};3579 class bad_typeid {};3580 } // namespace std3581 3582 struct S1 {};3583 struct S2 { S1 s1; };3584 3585 // We test each type of unevaluated context from a different target3586 // function. Some types of unevaluated contexts may actually cause the3587 // field `s1` to be modeled, and we don't want this to "pollute" the tests3588 // for the other unevaluated contexts.3589 void decltypeTarget() {3590 decltype(S2{}) Dummy;3591 }3592 void typeofTarget() {3593 typeof(S2{}) Dummy;3594 }3595 void typeidTarget() {3596#if __has_feature(cxx_rtti)3597 typeid(S2{});3598#endif3599 }3600 void sizeofTarget() {3601 sizeof(S2{});3602 }3603 void noexceptTarget() {3604 noexcept(S2{});3605 }3606 )cc";3607 3608 testFunction(Code, "decltypeTarget");3609 testFunction(Code, "typeofTarget");3610 testFunction(Code, "typeidTarget");3611 testFunction(Code, "sizeofTarget");3612 testFunction(Code, "noexceptTarget");3613}3614 3615TEST(TransferTest, StaticCastNoOp) {3616 std::string Code = R"(3617 void target(int Foo) {3618 int Bar = static_cast<int>(Foo);3619 // [[p]]3620 }3621 )";3622 runDataflow(3623 Code,3624 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3625 ASTContext &ASTCtx) {3626 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));3627 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3628 3629 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");3630 ASSERT_THAT(FooDecl, NotNull());3631 3632 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");3633 ASSERT_THAT(BarDecl, NotNull());3634 3635 const auto *Cast = ast_matchers::selectFirst<CXXStaticCastExpr>(3636 "cast",3637 ast_matchers::match(ast_matchers::cxxStaticCastExpr().bind("cast"),3638 ASTCtx));3639 ASSERT_THAT(Cast, NotNull());3640 ASSERT_EQ(Cast->getCastKind(), CK_NoOp);3641 3642 const auto *FooVal = Env.getValue(*FooDecl);3643 const auto *BarVal = Env.getValue(*BarDecl);3644 EXPECT_TRUE(isa<IntegerValue>(FooVal));3645 EXPECT_TRUE(isa<IntegerValue>(BarVal));3646 EXPECT_EQ(FooVal, BarVal);3647 });3648}3649 3650TEST(TransferTest, StaticCastBaseToDerived) {3651 std::string Code = R"cc(3652 struct Base {3653 char C;3654 };3655 struct Intermediate : public Base {3656 bool B;3657 };3658 struct Derived : public Intermediate {3659 int I;3660 };3661 Base& getBaseRef();3662 void target(Base* BPtr) {3663 Derived* DPtr = static_cast<Derived*>(BPtr);3664 DPtr->C;3665 DPtr->B;3666 DPtr->I;3667 Derived& DRef = static_cast<Derived&>(*BPtr);3668 DRef.C;3669 DRef.B;3670 DRef.I;3671 Derived& DRefFromFunc = static_cast<Derived&>(getBaseRef());3672 DRefFromFunc.C;3673 DRefFromFunc.B;3674 DRefFromFunc.I;3675 // [[p]]3676 }3677 )cc";3678 runDataflow(3679 Code,3680 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3681 ASTContext &ASTCtx) {3682 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));3683 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3684 3685 const ValueDecl *BPtrDecl = findValueDecl(ASTCtx, "BPtr");3686 ASSERT_THAT(BPtrDecl, NotNull());3687 3688 const ValueDecl *DPtrDecl = findValueDecl(ASTCtx, "DPtr");3689 ASSERT_THAT(DPtrDecl, NotNull());3690 3691 const ValueDecl *DRefDecl = findValueDecl(ASTCtx, "DRef");3692 ASSERT_THAT(DRefDecl, NotNull());3693 3694 const ValueDecl *DRefFromFuncDecl =3695 findValueDecl(ASTCtx, "DRefFromFunc");3696 ASSERT_THAT(DRefFromFuncDecl, NotNull());3697 3698 const auto *Cast = ast_matchers::selectFirst<CXXStaticCastExpr>(3699 "cast",3700 ast_matchers::match(ast_matchers::cxxStaticCastExpr().bind("cast"),3701 ASTCtx));3702 ASSERT_THAT(Cast, NotNull());3703 ASSERT_EQ(Cast->getCastKind(), CK_BaseToDerived);3704 3705 EXPECT_EQ(Env.getValue(*BPtrDecl), Env.getValue(*DPtrDecl));3706 EXPECT_EQ(&Env.get<PointerValue>(*BPtrDecl)->getPointeeLoc(),3707 Env.getStorageLocation(*DRefDecl));3708 // For DRefFromFunc, not crashing when analyzing the field accesses is3709 // enough.3710 });3711}3712 3713TEST(TransferTest, MultipleConstructionsFromStaticCastsBaseToDerived) {3714 std::string Code = R"cc(3715 struct Base {};3716 3717struct DerivedOne : public Base {3718 // Need a field in one of the derived siblings that the other doesn't have.3719 int I;3720};3721 3722struct DerivedTwo : public Base {};3723 3724int getInt();3725 3726void target(Base* B) {3727 // Need something to cause modeling of I.3728 DerivedOne D1;3729 (void)D1.I;3730 3731 // Switch cases are a reasonable pattern where the same variable might be3732 // safely cast to two different derived types within the same function3733 // without resetting the value of the variable. getInt is a stand-in for what3734 // is usually a function indicating the dynamic derived type.3735 switch (getInt()) {3736 case 1:3737 // Need a CXXConstructExpr or copy/move CXXOperatorCallExpr from each of3738 // the casts to derived types, cast from the same base variable, to3739 // trigger the copyRecord behavior.3740 (void)new DerivedOne(*static_cast<DerivedOne*>(B));3741 break;3742 case 2:3743 (void)new DerivedTwo(*static_cast<DerivedTwo*>(B));3744 break;3745 };3746}3747)cc";3748 runDataflow(3749 Code,3750 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3751 ASTContext &ASTCtx) {3752 // This is a crash repro. We used to crash when transferring the3753 // construction of DerivedTwo because B's StorageLocation had a child3754 // for the field I, but DerivedTwo doesn't. Now, we should only copy the3755 // fields from B that are present in DerivedTwo.3756 });3757}3758 3759TEST(TransferTest, CopyConstructionOfBaseAfterStaticCastsBaseToDerived) {3760 std::string Code = R"cc(3761 struct Base {};3762 3763struct Derived : public Base {3764// Need a field in Derived that is not in Base.3765 char C;3766};3767 3768void target(Base* B, Base* OtherB) {3769 Derived* D = static_cast<Derived*>(B);3770 *B = *OtherB;3771 // Need something to cause modeling of C.3772 (void)D->C;3773}3774 3775)cc";3776 runDataflow(3777 Code,3778 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3779 ASTContext &ASTCtx) {3780 // This is a crash repro. We used to crash when transferring the3781 // copy construction of B from OtherB because B's StorageLocation had a3782 // child for the field C, but Base doesn't (so OtherB doesn't, since3783 // it's never been cast to any other type), and we tried to copy from3784 // the source (OtherB) all the fields present in the destination (B).3785 // Now, we should only try to copy the fields from OtherB that are3786 // present in Base.3787 });3788}3789 3790TEST(TransferTest, ExplicitDerivedToBaseCast) {3791 std::string Code = R"cc(3792 struct Base {};3793 struct Derived : public Base {};3794 void target(Derived D) {3795 (Base*)&D;3796 // [[p]]3797 }3798)cc";3799 runDataflow(3800 Code,3801 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3802 ASTContext &ASTCtx) {3803 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));3804 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3805 3806 auto *Cast = ast_matchers::selectFirst<ImplicitCastExpr>(3807 "cast", ast_matchers::match(3808 ast_matchers::implicitCastExpr().bind("cast"), ASTCtx));3809 ASSERT_THAT(Cast, NotNull());3810 ASSERT_EQ(Cast->getCastKind(), CK_DerivedToBase);3811 3812 auto *AddressOf = ast_matchers::selectFirst<UnaryOperator>(3813 "addressof",3814 ast_matchers::match(ast_matchers::unaryOperator().bind("addressof"),3815 ASTCtx));3816 ASSERT_THAT(AddressOf, NotNull());3817 ASSERT_EQ(AddressOf->getOpcode(), UO_AddrOf);3818 3819 EXPECT_EQ(Env.getValue(*Cast), Env.getValue(*AddressOf));3820 });3821}3822 3823TEST(TransferTest, ConstructorConversion) {3824 std::string Code = R"cc(3825 struct Base {};3826 struct Derived : public Base {};3827 void target(Derived D) {3828 Base B = (Base)D;3829 // [[p]]3830 }3831)cc";3832 runDataflow(3833 Code,3834 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3835 ASTContext &ASTCtx) {3836 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));3837 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3838 3839 auto *Cast = ast_matchers::selectFirst<CStyleCastExpr>(3840 "cast", ast_matchers::match(3841 ast_matchers::cStyleCastExpr().bind("cast"), ASTCtx));3842 ASSERT_THAT(Cast, NotNull());3843 ASSERT_EQ(Cast->getCastKind(), CK_ConstructorConversion);3844 3845 auto &DLoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "D");3846 auto &BLoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "B");3847 EXPECT_NE(&BLoc, &DLoc);3848 });3849}3850 3851TEST(TransferTest, UserDefinedConversion) {3852 std::string Code = R"cc(3853 struct To {};3854 struct From {3855 operator To();3856 };3857 void target(From F) {3858 To T = (To)F;3859 // [[p]]3860 }3861)cc";3862 runDataflow(3863 Code,3864 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3865 ASTContext &ASTCtx) {3866 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));3867 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3868 3869 auto *Cast = ast_matchers::selectFirst<ImplicitCastExpr>(3870 "cast", ast_matchers::match(3871 ast_matchers::implicitCastExpr().bind("cast"), ASTCtx));3872 ASSERT_THAT(Cast, NotNull());3873 ASSERT_EQ(Cast->getCastKind(), CK_UserDefinedConversion);3874 3875 auto &FLoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "F");3876 auto &TLoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "T");3877 EXPECT_NE(&TLoc, &FLoc);3878 });3879}3880 3881TEST(TransferTest, ImplicitUncheckedDerivedToBaseCast) {3882 std::string Code = R"cc(3883 struct Base {3884 void method();3885 };3886 struct Derived : public Base {};3887 void target(Derived D) {3888 D.method();3889 // [[p]]3890 }3891)cc";3892 runDataflow(3893 Code,3894 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3895 ASTContext &ASTCtx) {3896 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));3897 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3898 3899 auto *Cast = ast_matchers::selectFirst<ImplicitCastExpr>(3900 "cast", ast_matchers::match(3901 ast_matchers::implicitCastExpr().bind("cast"), ASTCtx));3902 ASSERT_THAT(Cast, NotNull());3903 ASSERT_EQ(Cast->getCastKind(), CK_UncheckedDerivedToBase);3904 3905 auto &DLoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "D");3906 EXPECT_EQ(Env.getStorageLocation(*Cast), &DLoc);3907 });3908}3909 3910TEST(TransferTest, ImplicitDerivedToBaseCast) {3911 std::string Code = R"cc(3912 struct Base {};3913 struct Derived : public Base {};3914 void target() {3915 Base* B = new Derived();3916 // [[p]]3917 }3918)cc";3919 runDataflow(3920 Code,3921 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3922 ASTContext &ASTCtx) {3923 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));3924 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3925 3926 auto *Cast = ast_matchers::selectFirst<ImplicitCastExpr>(3927 "cast", ast_matchers::match(3928 ast_matchers::implicitCastExpr().bind("cast"), ASTCtx));3929 ASSERT_THAT(Cast, NotNull());3930 ASSERT_EQ(Cast->getCastKind(), CK_DerivedToBase);3931 3932 auto *New = ast_matchers::selectFirst<CXXNewExpr>(3933 "new", ast_matchers::match(ast_matchers::cxxNewExpr().bind("new"),3934 ASTCtx));3935 ASSERT_THAT(New, NotNull());3936 3937 EXPECT_EQ(Env.getValue(*Cast), Env.getValue(*New));3938 });3939}3940 3941TEST(TransferTest, ReinterpretCast) {3942 std::string Code = R"cc(3943 struct S {3944 int I;3945 };3946 3947 void target(unsigned char* Bytes) {3948 S& SRef = reinterpret_cast<S&>(Bytes);3949 SRef.I;3950 S* SPtr = reinterpret_cast<S*>(Bytes);3951 SPtr->I;3952 // [[p]]3953 }3954 )cc";3955 runDataflow(Code, [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>>3956 &Results,3957 ASTContext &ASTCtx) {3958 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));3959 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");3960 const ValueDecl *I = findValueDecl(ASTCtx, "I");3961 ASSERT_THAT(I, NotNull());3962 3963 // No particular knowledge of I's value is modeled, but for both casts,3964 // the fields of S are modeled.3965 3966 {3967 auto &Loc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "SRef");3968 std::vector<const ValueDecl *> Children;3969 for (const auto &Entry : Loc.children()) {3970 Children.push_back(Entry.getFirst());3971 }3972 3973 EXPECT_THAT(Children, UnorderedElementsAre(I));3974 }3975 3976 {3977 auto &Loc = cast<RecordStorageLocation>(3978 getValueForDecl<PointerValue>(ASTCtx, Env, "SPtr").getPointeeLoc());3979 std::vector<const ValueDecl *> Children;3980 for (const auto &Entry : Loc.children()) {3981 Children.push_back(Entry.getFirst());3982 }3983 3984 EXPECT_THAT(Children, UnorderedElementsAre(I));3985 }3986 });3987}3988 3989TEST(TransferTest, IntegralCast) {3990 std::string Code = R"(3991 void target(int Foo) {3992 long Bar = Foo;3993 // [[p]]3994 }3995 )";3996 runDataflow(3997 Code,3998 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,3999 ASTContext &ASTCtx) {4000 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4001 4002 const auto &FooVal = getValueForDecl<IntegerValue>(ASTCtx, Env, "Foo");4003 const auto &BarVal = getValueForDecl<IntegerValue>(ASTCtx, Env, "Bar");4004 EXPECT_EQ(&FooVal, &BarVal);4005 });4006}4007 4008TEST(TransferTest, IntegraltoBooleanCast) {4009 std::string Code = R"(4010 void target(int Foo) {4011 bool Bar = Foo;4012 // [[p]]4013 }4014 )";4015 runDataflow(4016 Code,4017 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4018 ASTContext &ASTCtx) {4019 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4020 4021 const auto &FooVal = getValueForDecl(ASTCtx, Env, "Foo");4022 const auto &BarVal = getValueForDecl(ASTCtx, Env, "Bar");4023 EXPECT_TRUE(isa<IntegerValue>(FooVal));4024 EXPECT_TRUE(isa<BoolValue>(BarVal));4025 });4026}4027 4028TEST(TransferTest, IntegralToBooleanCastFromBool) {4029 std::string Code = R"(4030 void target(bool Foo) {4031 int Zab = Foo;4032 bool Bar = Zab;4033 // [[p]]4034 }4035 )";4036 runDataflow(4037 Code,4038 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4039 ASTContext &ASTCtx) {4040 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4041 4042 const auto &FooVal = getValueForDecl<BoolValue>(ASTCtx, Env, "Foo");4043 const auto &BarVal = getValueForDecl<BoolValue>(ASTCtx, Env, "Bar");4044 EXPECT_EQ(&FooVal, &BarVal);4045 });4046}4047 4048TEST(TransferTest, WidenBoolValueInIntegerVariable) {4049 // This is a crash repro.4050 // This test sets up a case where we perform widening on an integer variable4051 // that contains a `BoolValue` for the previous iteration and an4052 // `IntegerValue` for the current iteration. We used to crash on this because4053 // `widenDistinctValues()` assumed that if the previous iteration had a4054 // `BoolValue`, the current iteration would too.4055 // FIXME: The real fix here is to make sure we never store `BoolValue`s in4056 // integer variables; see also the comment in `widenDistinctValues()`.4057 std::string Code = R"cc(4058 struct S {4059 int i;4060 S *next;4061 };4062 void target(S *s) {4063 for (; s; s = s->next)4064 s->i = false;4065 }4066 )cc";4067 runDataflow(Code,4068 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,4069 ASTContext &) {});4070}4071 4072TEST(TransferTest, NullToPointerCast) {4073 std::string Code = R"(4074 using my_nullptr_t = decltype(nullptr);4075 struct Baz {};4076 void target() {4077 int *FooX = nullptr;4078 int *FooY = nullptr;4079 bool **Bar = nullptr;4080 Baz *Baz = nullptr;4081 my_nullptr_t Null = 0;4082 // [[p]]4083 }4084 )";4085 runDataflow(4086 Code,4087 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4088 ASTContext &ASTCtx) {4089 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));4090 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4091 4092 const ValueDecl *FooXDecl = findValueDecl(ASTCtx, "FooX");4093 ASSERT_THAT(FooXDecl, NotNull());4094 4095 const ValueDecl *FooYDecl = findValueDecl(ASTCtx, "FooY");4096 ASSERT_THAT(FooYDecl, NotNull());4097 4098 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");4099 ASSERT_THAT(BarDecl, NotNull());4100 4101 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");4102 ASSERT_THAT(BazDecl, NotNull());4103 4104 const ValueDecl *NullDecl = findValueDecl(ASTCtx, "Null");4105 ASSERT_THAT(NullDecl, NotNull());4106 4107 const auto *FooXVal = cast<PointerValue>(Env.getValue(*FooXDecl));4108 const auto *FooYVal = cast<PointerValue>(Env.getValue(*FooYDecl));4109 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl));4110 const auto *BazVal = cast<PointerValue>(Env.getValue(*BazDecl));4111 const auto *NullVal = cast<PointerValue>(Env.getValue(*NullDecl));4112 4113 EXPECT_EQ(FooXVal, FooYVal);4114 EXPECT_NE(FooXVal, BarVal);4115 EXPECT_NE(FooXVal, BazVal);4116 EXPECT_NE(BarVal, BazVal);4117 4118 const StorageLocation &FooPointeeLoc = FooXVal->getPointeeLoc();4119 EXPECT_TRUE(isa<ScalarStorageLocation>(FooPointeeLoc));4120 EXPECT_THAT(Env.getValue(FooPointeeLoc), IsNull());4121 4122 const StorageLocation &BarPointeeLoc = BarVal->getPointeeLoc();4123 EXPECT_TRUE(isa<ScalarStorageLocation>(BarPointeeLoc));4124 EXPECT_THAT(Env.getValue(BarPointeeLoc), IsNull());4125 4126 const StorageLocation &BazPointeeLoc = BazVal->getPointeeLoc();4127 EXPECT_TRUE(isa<RecordStorageLocation>(BazPointeeLoc));4128 EXPECT_EQ(BazVal, &Env.fork().getOrCreateNullPointerValue(4129 BazPointeeLoc.getType()));4130 4131 const StorageLocation &NullPointeeLoc = NullVal->getPointeeLoc();4132 EXPECT_TRUE(isa<ScalarStorageLocation>(NullPointeeLoc));4133 EXPECT_THAT(Env.getValue(NullPointeeLoc), IsNull());4134 });4135}4136 4137TEST(TransferTest, PointerToMemberVariable) {4138 std::string Code = R"(4139 struct S {4140 int i;4141 };4142 void target() {4143 int S::*MemberPointer = &S::i;4144 // [[p]]4145 }4146 )";4147 runDataflow(4148 Code,4149 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4150 ASTContext &ASTCtx) {4151 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4152 4153 const ValueDecl *MemberPointerDecl =4154 findValueDecl(ASTCtx, "MemberPointer");4155 ASSERT_THAT(MemberPointerDecl, NotNull());4156 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull());4157 });4158}4159 4160TEST(TransferTest, PointerToMemberFunction) {4161 std::string Code = R"(4162 struct S {4163 void Method();4164 };4165 void target() {4166 void (S::*MemberPointer)() = &S::Method;4167 // [[p]]4168 }4169 )";4170 runDataflow(4171 Code,4172 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4173 ASTContext &ASTCtx) {4174 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4175 4176 const ValueDecl *MemberPointerDecl =4177 findValueDecl(ASTCtx, "MemberPointer");4178 ASSERT_THAT(MemberPointerDecl, NotNull());4179 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull());4180 });4181}4182 4183TEST(TransferTest, NullToMemberPointerCast) {4184 std::string Code = R"(4185 struct Foo {};4186 void target() {4187 int Foo::*MemberPointer = nullptr;4188 // [[p]]4189 }4190 )";4191 runDataflow(4192 Code,4193 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4194 ASTContext &ASTCtx) {4195 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));4196 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4197 4198 const ValueDecl *MemberPointerDecl =4199 findValueDecl(ASTCtx, "MemberPointer");4200 ASSERT_THAT(MemberPointerDecl, NotNull());4201 ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull());4202 });4203}4204 4205TEST(TransferTest, AddrOfValue) {4206 std::string Code = R"(4207 void target() {4208 int Foo;4209 int *Bar = &Foo;4210 // [[p]]4211 }4212 )";4213 runDataflow(4214 Code,4215 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4216 ASTContext &ASTCtx) {4217 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));4218 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4219 4220 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");4221 ASSERT_THAT(FooDecl, NotNull());4222 4223 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");4224 ASSERT_THAT(BarDecl, NotNull());4225 4226 const auto *FooLoc =4227 cast<ScalarStorageLocation>(Env.getStorageLocation(*FooDecl));4228 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl));4229 EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc);4230 });4231}4232 4233TEST(TransferTest, AddrOfReference) {4234 std::string Code = R"(4235 void target(int *Foo) {4236 int *Bar = &(*Foo);4237 // [[p]]4238 }4239 )";4240 runDataflow(4241 Code,4242 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4243 ASTContext &ASTCtx) {4244 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));4245 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4246 4247 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");4248 ASSERT_THAT(FooDecl, NotNull());4249 4250 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");4251 ASSERT_THAT(BarDecl, NotNull());4252 4253 const auto *FooVal = cast<PointerValue>(Env.getValue(*FooDecl));4254 const auto *BarVal = cast<PointerValue>(Env.getValue(*BarDecl));4255 EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc());4256 });4257}4258 4259TEST(TransferTest, Preincrement) {4260 std::string Code = R"(4261 void target(int I) {4262 (void)0; // [[before]]4263 int &IRef = ++I;4264 // [[after]]4265 }4266 )";4267 runDataflow(4268 Code,4269 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4270 ASTContext &ASTCtx) {4271 const Environment &EnvBefore =4272 getEnvironmentAtAnnotation(Results, "before");4273 const Environment &EnvAfter =4274 getEnvironmentAtAnnotation(Results, "after");4275 4276 EXPECT_EQ(&getLocForDecl(ASTCtx, EnvAfter, "IRef"),4277 &getLocForDecl(ASTCtx, EnvBefore, "I"));4278 4279 const ValueDecl *IDecl = findValueDecl(ASTCtx, "I");4280 EXPECT_NE(EnvBefore.getValue(*IDecl), nullptr);4281 EXPECT_EQ(EnvAfter.getValue(*IDecl), nullptr);4282 });4283}4284 4285TEST(TransferTest, Postincrement) {4286 std::string Code = R"(4287 void target(int I) {4288 (void)0; // [[before]]4289 int OldVal = I++;4290 // [[after]]4291 }4292 )";4293 runDataflow(4294 Code,4295 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4296 ASTContext &ASTCtx) {4297 const Environment &EnvBefore =4298 getEnvironmentAtAnnotation(Results, "before");4299 const Environment &EnvAfter =4300 getEnvironmentAtAnnotation(Results, "after");4301 4302 EXPECT_EQ(&getValueForDecl(ASTCtx, EnvBefore, "I"),4303 &getValueForDecl(ASTCtx, EnvAfter, "OldVal"));4304 4305 const ValueDecl *IDecl = findValueDecl(ASTCtx, "I");4306 EXPECT_EQ(EnvAfter.getValue(*IDecl), nullptr);4307 });4308}4309 4310// We test just one of the compound assignment operators because we know the4311// code for propagating the storage location is shared among all of them.4312TEST(TransferTest, AddAssign) {4313 std::string Code = R"(4314 void target(int I) {4315 int &IRef = (I += 1);4316 // [[p]]4317 }4318 )";4319 runDataflow(4320 Code,4321 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4322 ASTContext &ASTCtx) {4323 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4324 4325 EXPECT_EQ(&getLocForDecl(ASTCtx, Env, "IRef"),4326 &getLocForDecl(ASTCtx, Env, "I"));4327 });4328}4329 4330TEST(TransferTest, CannotAnalyzeFunctionTemplate) {4331 std::string Code = R"(4332 template <typename T>4333 void target() {}4334 )";4335 ASSERT_THAT_ERROR(4336 checkDataflowWithNoopAnalysis(Code),4337 llvm::FailedWithMessage("Cannot analyze templated declarations"));4338}4339 4340TEST(TransferTest, CannotAnalyzeMethodOfClassTemplate) {4341 std::string Code = R"(4342 template <typename T>4343 struct A {4344 void target() {}4345 };4346 )";4347 ASSERT_THAT_ERROR(4348 checkDataflowWithNoopAnalysis(Code),4349 llvm::FailedWithMessage("Cannot analyze templated declarations"));4350}4351 4352TEST(TransferTest, VarDeclInitAssignConditionalOperator) {4353 std::string Code = R"(4354 struct A {4355 int i;4356 };4357 4358 void target(A Foo, A Bar, bool Cond) {4359 A Baz = Cond ? A(Foo) : A(Bar);4360 // Make sure A::i is modeled.4361 Baz.i;4362 /*[[p]]*/4363 }4364 )";4365 runDataflow(4366 Code,4367 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4368 ASTContext &ASTCtx) {4369 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4370 4371 auto *FooIVal = cast<IntegerValue>(getFieldValue(4372 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo"), "i",4373 ASTCtx, Env));4374 auto *BarIVal = cast<IntegerValue>(getFieldValue(4375 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar"), "i",4376 ASTCtx, Env));4377 auto *BazIVal = cast<IntegerValue>(getFieldValue(4378 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Baz"), "i",4379 ASTCtx, Env));4380 4381 EXPECT_NE(BazIVal, FooIVal);4382 EXPECT_NE(BazIVal, BarIVal);4383 });4384}4385 4386TEST(TransferTest, VarDeclInitReferenceAssignConditionalOperator) {4387 std::string Code = R"(4388 struct A {4389 int i;4390 };4391 4392 void target(A Foo, A Bar, bool Cond) {4393 A &Baz = Cond ? Foo : Bar;4394 // Make sure A::i is modeled.4395 Baz.i;4396 /*[[p]]*/4397 }4398 )";4399 runDataflow(4400 Code,4401 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4402 ASTContext &ASTCtx) {4403 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4404 4405 auto *FooIVal = cast<IntegerValue>(getFieldValue(4406 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Foo"), "i",4407 ASTCtx, Env));4408 auto *BarIVal = cast<IntegerValue>(getFieldValue(4409 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Bar"), "i",4410 ASTCtx, Env));4411 auto *BazIVal = cast<IntegerValue>(getFieldValue(4412 &getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "Baz"), "i",4413 ASTCtx, Env));4414 4415 EXPECT_NE(BazIVal, FooIVal);4416 EXPECT_NE(BazIVal, BarIVal);4417 });4418}4419 4420TEST(TransferTest, VarDeclInDoWhile) {4421 std::string Code = R"(4422 void target(int *Foo) {4423 do {4424 int Bar = *Foo;4425 // [[in_loop]]4426 } while (false);4427 (void)0;4428 // [[after_loop]]4429 }4430 )";4431 runDataflow(4432 Code,4433 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4434 ASTContext &ASTCtx) {4435 const Environment &EnvInLoop =4436 getEnvironmentAtAnnotation(Results, "in_loop");4437 const Environment &EnvAfterLoop =4438 getEnvironmentAtAnnotation(Results, "after_loop");4439 4440 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");4441 ASSERT_THAT(FooDecl, NotNull());4442 4443 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");4444 ASSERT_THAT(BarDecl, NotNull());4445 4446 const auto *FooVal =4447 cast<PointerValue>(EnvAfterLoop.getValue(*FooDecl));4448 const auto *FooPointeeVal =4449 cast<IntegerValue>(EnvAfterLoop.getValue(FooVal->getPointeeLoc()));4450 4451 const auto *BarVal = cast<IntegerValue>(EnvInLoop.getValue(*BarDecl));4452 EXPECT_EQ(BarVal, FooPointeeVal);4453 4454 ASSERT_THAT(EnvAfterLoop.getValue(*BarDecl), IsNull());4455 });4456}4457 4458TEST(TransferTest, UnreachableAfterWhileTrue) {4459 std::string Code = R"(4460 void target() {4461 while (true) {}4462 (void)0;4463 /*[[p]]*/4464 }4465 )";4466 runDataflow(4467 Code,4468 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4469 ASTContext &ASTCtx) {4470 // The node after the while-true is pruned because it is trivially4471 // known to be unreachable.4472 ASSERT_TRUE(Results.empty());4473 });4474}4475 4476TEST(TransferTest, AggregateInitialization) {4477 std::string BracesCode = R"(4478 struct A {4479 int Foo;4480 };4481 4482 struct B {4483 int Bar;4484 A Baz;4485 int Qux;4486 };4487 4488 void target(int BarArg, int FooArg, int QuxArg) {4489 B Quux{BarArg, {FooArg}, QuxArg};4490 B OtherB;4491 /*[[p]]*/4492 }4493 )";4494 std::string BraceElisionCode = R"(4495 struct A {4496 int Foo;4497 };4498 4499 struct B {4500 int Bar;4501 A Baz;4502 int Qux;4503 };4504 4505 void target(int BarArg, int FooArg, int QuxArg) {4506 B Quux = {BarArg, FooArg, QuxArg};4507 B OtherB;4508 /*[[p]]*/4509 }4510 )";4511 for (const std::string &Code : {BracesCode, BraceElisionCode}) {4512 runDataflow(4513 Code,4514 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4515 ASTContext &ASTCtx) {4516 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));4517 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4518 4519 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");4520 ASSERT_THAT(FooDecl, NotNull());4521 4522 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");4523 ASSERT_THAT(BarDecl, NotNull());4524 4525 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");4526 ASSERT_THAT(BazDecl, NotNull());4527 4528 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");4529 ASSERT_THAT(QuxDecl, NotNull());4530 4531 const ValueDecl *FooArgDecl = findValueDecl(ASTCtx, "FooArg");4532 ASSERT_THAT(FooArgDecl, NotNull());4533 4534 const ValueDecl *BarArgDecl = findValueDecl(ASTCtx, "BarArg");4535 ASSERT_THAT(BarArgDecl, NotNull());4536 4537 const ValueDecl *QuxArgDecl = findValueDecl(ASTCtx, "QuxArg");4538 ASSERT_THAT(QuxArgDecl, NotNull());4539 4540 const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");4541 ASSERT_THAT(QuuxDecl, NotNull());4542 4543 const auto *FooArgVal = cast<IntegerValue>(Env.getValue(*FooArgDecl));4544 const auto *BarArgVal = cast<IntegerValue>(Env.getValue(*BarArgDecl));4545 const auto *QuxArgVal = cast<IntegerValue>(Env.getValue(*QuxArgDecl));4546 4547 const auto &QuuxLoc =4548 *cast<RecordStorageLocation>(Env.getStorageLocation(*QuuxDecl));4549 const auto &BazLoc =4550 *cast<RecordStorageLocation>(QuuxLoc.getChild(*BazDecl));4551 4552 EXPECT_EQ(getFieldValue(&QuuxLoc, *BarDecl, Env), BarArgVal);4553 EXPECT_EQ(getFieldValue(&BazLoc, *FooDecl, Env), FooArgVal);4554 EXPECT_EQ(getFieldValue(&QuuxLoc, *QuxDecl, Env), QuxArgVal);4555 4556 // Check that fields initialized in an initializer list are always4557 // modeled in other instances of the same type.4558 const auto &OtherBLoc =4559 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "OtherB");4560 EXPECT_THAT(OtherBLoc.getChild(*BarDecl), NotNull());4561 EXPECT_THAT(OtherBLoc.getChild(*BazDecl), NotNull());4562 EXPECT_THAT(OtherBLoc.getChild(*QuxDecl), NotNull());4563 });4564 }4565}4566 4567TEST(TransferTest, AggregateInitializationReferenceField) {4568 std::string Code = R"(4569 struct S {4570 int &RefField;4571 };4572 4573 void target(int i) {4574 S s = { i };4575 /*[[p]]*/4576 }4577 )";4578 runDataflow(4579 Code,4580 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4581 ASTContext &ASTCtx) {4582 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4583 4584 const ValueDecl *RefFieldDecl = findValueDecl(ASTCtx, "RefField");4585 4586 auto &ILoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "i");4587 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s");4588 4589 EXPECT_EQ(SLoc.getChild(*RefFieldDecl), &ILoc);4590 });4591}4592 4593TEST(TransferTest, AggregateInitialization_NotExplicitlyInitializedField) {4594 std::string Code = R"(4595 struct S {4596 int i1;4597 int i2;4598 };4599 4600 void target(int i) {4601 S s = { i };4602 /*[[p]]*/4603 }4604 )";4605 runDataflow(4606 Code,4607 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4608 ASTContext &ASTCtx) {4609 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4610 4611 const ValueDecl *I1FieldDecl = findValueDecl(ASTCtx, "i1");4612 const ValueDecl *I2FieldDecl = findValueDecl(ASTCtx, "i2");4613 4614 auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s");4615 4616 auto &IValue = getValueForDecl<IntegerValue>(ASTCtx, Env, "i");4617 auto &I1Value =4618 *cast<IntegerValue>(getFieldValue(&SLoc, *I1FieldDecl, Env));4619 EXPECT_EQ(&I1Value, &IValue);4620 auto &I2Value =4621 *cast<IntegerValue>(getFieldValue(&SLoc, *I2FieldDecl, Env));4622 EXPECT_NE(&I2Value, &IValue);4623 });4624}4625 4626TEST(TransferTest, AggregateInitializationFunctionPointer) {4627 // This is a repro for an assertion failure.4628 // nullptr takes on the type of a const function pointer, but its type was4629 // asserted to be equal to the *unqualified* type of Field, which no longer4630 // included the const.4631 std::string Code = R"(4632 struct S {4633 void (*const Field)();4634 };4635 4636 void target() {4637 S s{nullptr};4638 }4639 )";4640 runDataflow(4641 Code,4642 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4643 ASTContext &ASTCtx) {});4644}4645 4646TEST(TransferTest, AssignToUnionMember) {4647 std::string Code = R"(4648 union A {4649 int Foo;4650 };4651 4652 void target(int Bar) {4653 A Baz;4654 Baz.Foo = Bar;4655 // [[p]]4656 }4657 )";4658 runDataflow(4659 Code,4660 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4661 ASTContext &ASTCtx) {4662 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));4663 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4664 4665 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");4666 ASSERT_THAT(BazDecl, NotNull());4667 ASSERT_TRUE(BazDecl->getType()->isUnionType());4668 4669 auto BazFields = BazDecl->getType()->getAsRecordDecl()->fields();4670 FieldDecl *FooDecl = nullptr;4671 for (FieldDecl *Field : BazFields) {4672 if (Field->getNameAsString() == "Foo") {4673 FooDecl = Field;4674 } else {4675 FAIL() << "Unexpected field: " << Field->getNameAsString();4676 }4677 }4678 ASSERT_THAT(FooDecl, NotNull());4679 4680 const auto *BazLoc = dyn_cast_or_null<RecordStorageLocation>(4681 Env.getStorageLocation(*BazDecl));4682 ASSERT_THAT(BazLoc, NotNull());4683 4684 const auto *FooVal =4685 cast<IntegerValue>(getFieldValue(BazLoc, *FooDecl, Env));4686 4687 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");4688 ASSERT_THAT(BarDecl, NotNull());4689 const auto *BarLoc = Env.getStorageLocation(*BarDecl);4690 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));4691 4692 EXPECT_EQ(Env.getValue(*BarLoc), FooVal);4693 });4694}4695 4696TEST(TransferTest, AssignFromBoolLiteral) {4697 std::string Code = R"(4698 void target() {4699 bool Foo = true;4700 bool Bar = false;4701 // [[p]]4702 }4703 )";4704 runDataflow(4705 Code,4706 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4707 ASTContext &ASTCtx) {4708 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));4709 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4710 4711 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");4712 ASSERT_THAT(FooDecl, NotNull());4713 4714 const auto *FooVal =4715 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));4716 ASSERT_THAT(FooVal, NotNull());4717 4718 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");4719 ASSERT_THAT(BarDecl, NotNull());4720 4721 const auto *BarVal =4722 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl));4723 ASSERT_THAT(BarVal, NotNull());4724 4725 EXPECT_EQ(FooVal, &Env.getBoolLiteralValue(true));4726 EXPECT_EQ(BarVal, &Env.getBoolLiteralValue(false));4727 });4728}4729 4730TEST(TransferTest, AssignFromCompositeBoolExpression) {4731 {4732 std::string Code = R"(4733 void target(bool Foo, bool Bar, bool Qux) {4734 bool Baz = (Foo) && (Bar || Qux);4735 // [[p]]4736 }4737 )";4738 runDataflow(4739 Code,4740 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4741 ASTContext &ASTCtx) {4742 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));4743 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4744 4745 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");4746 ASSERT_THAT(FooDecl, NotNull());4747 4748 const auto *FooVal =4749 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));4750 ASSERT_THAT(FooVal, NotNull());4751 4752 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");4753 ASSERT_THAT(BarDecl, NotNull());4754 4755 const auto *BarVal =4756 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl));4757 ASSERT_THAT(BarVal, NotNull());4758 4759 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");4760 ASSERT_THAT(QuxDecl, NotNull());4761 4762 const auto *QuxVal =4763 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl));4764 ASSERT_THAT(QuxVal, NotNull());4765 4766 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");4767 ASSERT_THAT(BazDecl, NotNull());4768 4769 const auto *BazVal =4770 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl));4771 ASSERT_THAT(BazVal, NotNull());4772 auto &A = Env.arena();4773 EXPECT_EQ(&BazVal->formula(),4774 &A.makeAnd(FooVal->formula(),4775 A.makeOr(BarVal->formula(), QuxVal->formula())));4776 });4777 }4778 4779 {4780 std::string Code = R"(4781 void target(bool Foo, bool Bar, bool Qux) {4782 bool Baz = (Foo && Qux) || (Bar);4783 // [[p]]4784 }4785 )";4786 runDataflow(4787 Code,4788 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4789 ASTContext &ASTCtx) {4790 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));4791 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4792 4793 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");4794 ASSERT_THAT(FooDecl, NotNull());4795 4796 const auto *FooVal =4797 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));4798 ASSERT_THAT(FooVal, NotNull());4799 4800 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");4801 ASSERT_THAT(BarDecl, NotNull());4802 4803 const auto *BarVal =4804 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl));4805 ASSERT_THAT(BarVal, NotNull());4806 4807 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");4808 ASSERT_THAT(QuxDecl, NotNull());4809 4810 const auto *QuxVal =4811 dyn_cast_or_null<BoolValue>(Env.getValue(*QuxDecl));4812 ASSERT_THAT(QuxVal, NotNull());4813 4814 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");4815 ASSERT_THAT(BazDecl, NotNull());4816 4817 const auto *BazVal =4818 dyn_cast_or_null<BoolValue>(Env.getValue(*BazDecl));4819 ASSERT_THAT(BazVal, NotNull());4820 auto &A = Env.arena();4821 EXPECT_EQ(&BazVal->formula(),4822 &A.makeOr(A.makeAnd(FooVal->formula(), QuxVal->formula()),4823 BarVal->formula()));4824 });4825 }4826 4827 {4828 std::string Code = R"(4829 void target(bool A, bool B, bool C, bool D) {4830 bool Foo = ((A && B) && C) && D;4831 // [[p]]4832 }4833 )";4834 runDataflow(4835 Code,4836 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4837 ASTContext &ASTCtx) {4838 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));4839 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4840 4841 const ValueDecl *ADecl = findValueDecl(ASTCtx, "A");4842 ASSERT_THAT(ADecl, NotNull());4843 4844 const auto *AVal = dyn_cast_or_null<BoolValue>(Env.getValue(*ADecl));4845 ASSERT_THAT(AVal, NotNull());4846 4847 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B");4848 ASSERT_THAT(BDecl, NotNull());4849 4850 const auto *BVal = dyn_cast_or_null<BoolValue>(Env.getValue(*BDecl));4851 ASSERT_THAT(BVal, NotNull());4852 4853 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C");4854 ASSERT_THAT(CDecl, NotNull());4855 4856 const auto *CVal = dyn_cast_or_null<BoolValue>(Env.getValue(*CDecl));4857 ASSERT_THAT(CVal, NotNull());4858 4859 const ValueDecl *DDecl = findValueDecl(ASTCtx, "D");4860 ASSERT_THAT(DDecl, NotNull());4861 4862 const auto *DVal = dyn_cast_or_null<BoolValue>(Env.getValue(*DDecl));4863 ASSERT_THAT(DVal, NotNull());4864 4865 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");4866 ASSERT_THAT(FooDecl, NotNull());4867 4868 const auto *FooVal =4869 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));4870 ASSERT_THAT(FooVal, NotNull());4871 auto &A = Env.arena();4872 EXPECT_EQ(4873 &FooVal->formula(),4874 &A.makeAnd(A.makeAnd(A.makeAnd(AVal->formula(), BVal->formula()),4875 CVal->formula()),4876 DVal->formula()));4877 });4878 }4879}4880 4881TEST(TransferTest, AssignFromBoolNegation) {4882 std::string Code = R"(4883 void target() {4884 bool Foo = true;4885 bool Bar = !(Foo);4886 // [[p]]4887 }4888 )";4889 runDataflow(4890 Code,4891 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4892 ASTContext &ASTCtx) {4893 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));4894 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4895 4896 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");4897 ASSERT_THAT(FooDecl, NotNull());4898 4899 const auto *FooVal =4900 dyn_cast_or_null<BoolValue>(Env.getValue(*FooDecl));4901 ASSERT_THAT(FooVal, NotNull());4902 4903 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");4904 ASSERT_THAT(BarDecl, NotNull());4905 4906 const auto *BarVal =4907 dyn_cast_or_null<BoolValue>(Env.getValue(*BarDecl));4908 ASSERT_THAT(BarVal, NotNull());4909 auto &A = Env.arena();4910 EXPECT_EQ(&BarVal->formula(), &A.makeNot(FooVal->formula()));4911 });4912}4913 4914TEST(TransferTest, BuiltinExpect) {4915 std::string Code = R"(4916 void target(long Foo) {4917 long Bar = __builtin_expect(Foo, true);4918 /*[[p]]*/4919 }4920 )";4921 runDataflow(4922 Code,4923 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4924 ASTContext &ASTCtx) {4925 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));4926 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4927 4928 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");4929 ASSERT_THAT(FooDecl, NotNull());4930 4931 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");4932 ASSERT_THAT(BarDecl, NotNull());4933 4934 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));4935 });4936}4937 4938// `__builtin_expect` takes and returns a `long` argument, so other types4939// involve casts. This verifies that we identify the input and output in that4940// case.4941TEST(TransferTest, BuiltinExpectBoolArg) {4942 std::string Code = R"(4943 void target(bool Foo) {4944 bool Bar = __builtin_expect(Foo, true);4945 /*[[p]]*/4946 }4947 )";4948 runDataflow(4949 Code,4950 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4951 ASTContext &ASTCtx) {4952 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));4953 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4954 4955 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");4956 ASSERT_THAT(FooDecl, NotNull());4957 4958 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");4959 ASSERT_THAT(BarDecl, NotNull());4960 4961 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));4962 });4963}4964 4965TEST(TransferTest, BuiltinUnreachable) {4966 std::string Code = R"(4967 void target(bool Foo) {4968 bool Bar = false;4969 if (Foo)4970 Bar = Foo;4971 else4972 __builtin_unreachable();4973 (void)0;4974 /*[[p]]*/4975 }4976 )";4977 runDataflow(4978 Code,4979 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,4980 ASTContext &ASTCtx) {4981 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));4982 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");4983 4984 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");4985 ASSERT_THAT(FooDecl, NotNull());4986 4987 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");4988 ASSERT_THAT(BarDecl, NotNull());4989 4990 // `__builtin_unreachable` promises that the code is4991 // unreachable, so the compiler treats the "then" branch as the4992 // only possible predecessor of this statement.4993 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));4994 });4995}4996 4997TEST(TransferTest, BuiltinTrap) {4998 std::string Code = R"(4999 void target(bool Foo) {5000 bool Bar = false;5001 if (Foo)5002 Bar = Foo;5003 else5004 __builtin_trap();5005 (void)0;5006 /*[[p]]*/5007 }5008 )";5009 runDataflow(5010 Code,5011 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5012 ASTContext &ASTCtx) {5013 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));5014 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5015 5016 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");5017 ASSERT_THAT(FooDecl, NotNull());5018 5019 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");5020 ASSERT_THAT(BarDecl, NotNull());5021 5022 // `__builtin_trap` ensures program termination, so only the5023 // "then" branch is a predecessor of this statement.5024 EXPECT_EQ(Env.getValue(*FooDecl), Env.getValue(*BarDecl));5025 });5026}5027 5028TEST(TransferTest, BuiltinDebugTrap) {5029 std::string Code = R"(5030 void target(bool Foo) {5031 bool Bar = false;5032 if (Foo)5033 Bar = Foo;5034 else5035 __builtin_debugtrap();5036 (void)0;5037 /*[[p]]*/5038 }5039 )";5040 runDataflow(5041 Code,5042 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5043 ASTContext &ASTCtx) {5044 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));5045 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5046 5047 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");5048 ASSERT_THAT(FooDecl, NotNull());5049 5050 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");5051 ASSERT_THAT(BarDecl, NotNull());5052 5053 // `__builtin_debugtrap` doesn't ensure program termination.5054 EXPECT_NE(Env.getValue(*FooDecl), Env.getValue(*BarDecl));5055 });5056}5057 5058TEST(TransferTest, StaticIntSingleVarDecl) {5059 std::string Code = R"(5060 void target() {5061 static int Foo;5062 // [[p]]5063 }5064 )";5065 runDataflow(5066 Code,5067 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5068 ASTContext &ASTCtx) {5069 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));5070 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5071 5072 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");5073 ASSERT_THAT(FooDecl, NotNull());5074 5075 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);5076 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));5077 5078 const Value *FooVal = Env.getValue(*FooLoc);5079 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));5080 });5081}5082 5083TEST(TransferTest, StaticIntGroupVarDecl) {5084 std::string Code = R"(5085 void target() {5086 static int Foo, Bar;5087 (void)0;5088 // [[p]]5089 }5090 )";5091 runDataflow(5092 Code,5093 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5094 ASTContext &ASTCtx) {5095 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));5096 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5097 5098 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");5099 ASSERT_THAT(FooDecl, NotNull());5100 5101 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");5102 ASSERT_THAT(BarDecl, NotNull());5103 5104 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);5105 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));5106 5107 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);5108 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));5109 5110 const Value *FooVal = Env.getValue(*FooLoc);5111 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));5112 5113 const Value *BarVal = Env.getValue(*BarLoc);5114 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));5115 5116 EXPECT_NE(FooVal, BarVal);5117 });5118}5119 5120TEST(TransferTest, GlobalIntVarDecl) {5121 std::string Code = R"(5122 static int Foo;5123 5124 void target() {5125 int Bar = Foo;5126 int Baz = Foo;5127 // [[p]]5128 }5129 )";5130 runDataflow(5131 Code,5132 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5133 ASTContext &ASTCtx) {5134 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));5135 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5136 5137 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");5138 ASSERT_THAT(BarDecl, NotNull());5139 5140 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");5141 ASSERT_THAT(BazDecl, NotNull());5142 5143 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));5144 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl));5145 EXPECT_EQ(BarVal, BazVal);5146 });5147}5148 5149TEST(TransferTest, StaticMemberIntVarDecl) {5150 std::string Code = R"(5151 struct A {5152 static int Foo;5153 };5154 5155 void target(A a) {5156 int Bar = a.Foo;5157 int Baz = a.Foo;5158 // [[p]]5159 }5160 )";5161 runDataflow(5162 Code,5163 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5164 ASTContext &ASTCtx) {5165 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));5166 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5167 5168 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");5169 ASSERT_THAT(BarDecl, NotNull());5170 5171 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");5172 ASSERT_THAT(BazDecl, NotNull());5173 5174 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));5175 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl));5176 EXPECT_EQ(BarVal, BazVal);5177 });5178}5179 5180TEST(TransferTest, StaticMemberRefVarDecl) {5181 std::string Code = R"(5182 struct A {5183 static int &Foo;5184 };5185 5186 void target(A a) {5187 int Bar = a.Foo;5188 int Baz = a.Foo;5189 // [[p]]5190 }5191 )";5192 runDataflow(5193 Code,5194 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5195 ASTContext &ASTCtx) {5196 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));5197 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5198 5199 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");5200 ASSERT_THAT(BarDecl, NotNull());5201 5202 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");5203 ASSERT_THAT(BazDecl, NotNull());5204 5205 const Value *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));5206 const Value *BazVal = cast<IntegerValue>(Env.getValue(*BazDecl));5207 EXPECT_EQ(BarVal, BazVal);5208 });5209}5210 5211TEST(TransferTest, AssignMemberBeforeCopy) {5212 std::string Code = R"(5213 struct A {5214 int Foo;5215 };5216 5217 void target() {5218 A A1;5219 A A2;5220 int Bar;5221 A1.Foo = Bar;5222 A2 = A1;5223 // [[p]]5224 }5225 )";5226 runDataflow(5227 Code,5228 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5229 ASTContext &ASTCtx) {5230 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));5231 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5232 5233 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");5234 ASSERT_THAT(FooDecl, NotNull());5235 5236 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");5237 ASSERT_THAT(BarDecl, NotNull());5238 5239 const ValueDecl *A1Decl = findValueDecl(ASTCtx, "A1");5240 ASSERT_THAT(A1Decl, NotNull());5241 5242 const ValueDecl *A2Decl = findValueDecl(ASTCtx, "A2");5243 ASSERT_THAT(A2Decl, NotNull());5244 5245 const auto *BarVal = cast<IntegerValue>(Env.getValue(*BarDecl));5246 5247 const auto &A2Loc =5248 *cast<RecordStorageLocation>(Env.getStorageLocation(*A2Decl));5249 EXPECT_EQ(getFieldValue(&A2Loc, *FooDecl, Env), BarVal);5250 });5251}5252 5253TEST(TransferTest, BooleanEquality) {5254 std::string Code = R"(5255 void target(bool Bar) {5256 bool Foo = true;5257 if (Bar == Foo) {5258 (void)0;5259 /*[[p-then]]*/5260 } else {5261 (void)0;5262 /*[[p-else]]*/5263 }5264 }5265 )";5266 runDataflow(5267 Code,5268 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5269 ASTContext &ASTCtx) {5270 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else"));5271 const Environment &EnvThen =5272 getEnvironmentAtAnnotation(Results, "p-then");5273 const Environment &EnvElse =5274 getEnvironmentAtAnnotation(Results, "p-else");5275 5276 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");5277 ASSERT_THAT(BarDecl, NotNull());5278 5279 auto &BarValThen = getFormula(*BarDecl, EnvThen);5280 EXPECT_TRUE(EnvThen.proves(BarValThen));5281 5282 auto &BarValElse = getFormula(*BarDecl, EnvElse);5283 EXPECT_TRUE(EnvElse.proves(EnvElse.arena().makeNot(BarValElse)));5284 });5285}5286 5287TEST(TransferTest, BooleanInequality) {5288 std::string Code = R"(5289 void target(bool Bar) {5290 bool Foo = true;5291 if (Bar != Foo) {5292 (void)0;5293 /*[[p-then]]*/5294 } else {5295 (void)0;5296 /*[[p-else]]*/5297 }5298 }5299 )";5300 runDataflow(5301 Code,5302 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5303 ASTContext &ASTCtx) {5304 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-then", "p-else"));5305 const Environment &EnvThen =5306 getEnvironmentAtAnnotation(Results, "p-then");5307 const Environment &EnvElse =5308 getEnvironmentAtAnnotation(Results, "p-else");5309 5310 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");5311 ASSERT_THAT(BarDecl, NotNull());5312 5313 auto &BarValThen = getFormula(*BarDecl, EnvThen);5314 EXPECT_TRUE(EnvThen.proves(EnvThen.arena().makeNot(BarValThen)));5315 5316 auto &BarValElse = getFormula(*BarDecl, EnvElse);5317 EXPECT_TRUE(EnvElse.proves(BarValElse));5318 });5319}5320 5321TEST(TransferTest, PointerEquality) {5322 std::string Code = R"cc(5323 void target() {5324 int i = 0;5325 int i_other = 0;5326 int *p1 = &i;5327 int *p2 = &i;5328 int *p_other = &i_other;5329 int *null = nullptr;5330 5331 bool p1_eq_p1 = (p1 == p1);5332 bool p1_eq_p2 = (p1 == p2);5333 bool p1_eq_p_other = (p1 == p_other);5334 5335 bool p1_eq_null = (p1 == null);5336 bool p1_eq_nullptr = (p1 == nullptr);5337 bool null_eq_nullptr = (null == nullptr);5338 bool nullptr_eq_nullptr = (nullptr == nullptr);5339 5340 // We won't duplicate all of the tests above with `!=`, as we know that5341 // the implementation simply negates the result of the `==` comparison.5342 // Instead, just spot-check one case.5343 bool p1_ne_p1 = (p1 != p1);5344 5345 (void)0; // [[p]]5346 }5347 )cc";5348 runDataflow(5349 Code,5350 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5351 ASTContext &ASTCtx) {5352 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5353 5354 // Check the we have indeed set things up so that `p1` and `p2` have5355 // different pointer values.5356 EXPECT_NE(&getValueForDecl<PointerValue>(ASTCtx, Env, "p1"),5357 &getValueForDecl<PointerValue>(ASTCtx, Env, "p2"));5358 5359 EXPECT_EQ(&getValueForDecl<BoolValue>(ASTCtx, Env, "p1_eq_p1"),5360 &Env.getBoolLiteralValue(true));5361 EXPECT_EQ(&getValueForDecl<BoolValue>(ASTCtx, Env, "p1_eq_p2"),5362 &Env.getBoolLiteralValue(true));5363 EXPECT_TRUE(isa<AtomicBoolValue>(5364 getValueForDecl<BoolValue>(ASTCtx, Env, "p1_eq_p_other")));5365 5366 EXPECT_TRUE(isa<AtomicBoolValue>(5367 getValueForDecl<BoolValue>(ASTCtx, Env, "p1_eq_null")));5368 EXPECT_TRUE(isa<AtomicBoolValue>(5369 getValueForDecl<BoolValue>(ASTCtx, Env, "p1_eq_nullptr")));5370 EXPECT_EQ(&getValueForDecl<BoolValue>(ASTCtx, Env, "null_eq_nullptr"),5371 &Env.getBoolLiteralValue(true));5372 EXPECT_EQ(5373 &getValueForDecl<BoolValue>(ASTCtx, Env, "nullptr_eq_nullptr"),5374 &Env.getBoolLiteralValue(true));5375 5376 EXPECT_EQ(&getValueForDecl<BoolValue>(ASTCtx, Env, "p1_ne_p1"),5377 &Env.getBoolLiteralValue(false));5378 });5379}5380 5381TEST(TransferTest, PointerEqualityUnionMembers) {5382 std::string Code = R"cc(5383 union U {5384 int i1;5385 int i2;5386 };5387 void target() {5388 U u;5389 bool i1_eq_i2 = (&u.i1 == &u.i2);5390 5391 (void)0; // [[p]]5392 }5393 )cc";5394 runDataflow(5395 Code,5396 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5397 ASTContext &ASTCtx) {5398 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5399 5400 // FIXME: By the standard, `u.i1` and `u.i2` should have the same5401 // address, but we don't yet model this property of union members5402 // correctly. The result is therefore weaker than it could be (just an5403 // atom rather than a true literal), though not wrong.5404 EXPECT_TRUE(isa<AtomicBoolValue>(5405 getValueForDecl<BoolValue>(ASTCtx, Env, "i1_eq_i2")));5406 });5407}5408 5409TEST(TransferTest, IntegerLiteralEquality) {5410 std::string Code = R"(5411 void target() {5412 bool equal = (42 == 42);5413 // [[p]]5414 }5415 )";5416 runDataflow(5417 Code,5418 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5419 ASTContext &ASTCtx) {5420 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5421 5422 auto &Equal =5423 getValueForDecl<BoolValue>(ASTCtx, Env, "equal").formula();5424 EXPECT_TRUE(Env.proves(Equal));5425 });5426}5427 5428TEST(TransferTest, UnsupportedValueEquality) {5429 std::string Code = R"(5430 // An explicitly unsupported type by the framework.5431 enum class EC {5432 A,5433 B5434 };5435 5436 void target() {5437 EC ec = EC::A;5438 5439 bool unsupported_eq_same = (EC::A == EC::A);5440 bool unsupported_eq_other = (EC::A == EC::B);5441 bool unsupported_eq_var = (ec == EC::B);5442 5443 (void)0; // [[p]]5444 }5445 )";5446 runDataflow(5447 Code,5448 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5449 ASTContext &ASTCtx) {5450 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5451 5452 // We do not model the values of unsupported types, so this5453 // seemingly-trivial case will not be true either.5454 EXPECT_TRUE(isa<AtomicBoolValue>(5455 getValueForDecl<BoolValue>(ASTCtx, Env, "unsupported_eq_same")));5456 EXPECT_TRUE(isa<AtomicBoolValue>(5457 getValueForDecl<BoolValue>(ASTCtx, Env, "unsupported_eq_other")));5458 EXPECT_TRUE(isa<AtomicBoolValue>(5459 getValueForDecl<BoolValue>(ASTCtx, Env, "unsupported_eq_var")));5460 });5461}5462 5463TEST(TransferTest, CorrelatedBranches) {5464 std::string Code = R"(5465 void target(bool B, bool C) {5466 if (B) {5467 return;5468 }5469 (void)0;5470 /*[[p0]]*/5471 if (C) {5472 B = true;5473 /*[[p1]]*/5474 }5475 if (B) {5476 (void)0;5477 /*[[p2]]*/5478 }5479 }5480 )";5481 runDataflow(5482 Code,5483 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5484 ASTContext &ASTCtx) {5485 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p0", "p1", "p2"));5486 5487 const ValueDecl *CDecl = findValueDecl(ASTCtx, "C");5488 ASSERT_THAT(CDecl, NotNull());5489 5490 {5491 const Environment &Env = getEnvironmentAtAnnotation(Results, "p0");5492 const ValueDecl *BDecl = findValueDecl(ASTCtx, "B");5493 ASSERT_THAT(BDecl, NotNull());5494 auto &BVal = getFormula(*BDecl, Env);5495 5496 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BVal)));5497 }5498 5499 {5500 const Environment &Env = getEnvironmentAtAnnotation(Results, "p1");5501 auto &CVal = getFormula(*CDecl, Env);5502 EXPECT_TRUE(Env.proves(CVal));5503 }5504 5505 {5506 const Environment &Env = getEnvironmentAtAnnotation(Results, "p2");5507 auto &CVal = getFormula(*CDecl, Env);5508 EXPECT_TRUE(Env.proves(CVal));5509 }5510 });5511}5512 5513TEST(TransferTest, LoopWithAssignmentConverges) {5514 std::string Code = R"(5515 bool foo();5516 5517 void target() {5518 do {5519 bool Bar = foo();5520 if (Bar) break;5521 (void)Bar;5522 /*[[p]]*/5523 } while (true);5524 }5525 )";5526 // The key property that we are verifying is implicit in `runDataflow` --5527 // namely, that the analysis succeeds, rather than hitting the maximum number5528 // of iterations.5529 runDataflow(5530 Code,5531 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5532 ASTContext &ASTCtx) {5533 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));5534 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5535 5536 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");5537 ASSERT_THAT(BarDecl, NotNull());5538 5539 auto &BarVal = getFormula(*BarDecl, Env);5540 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal)));5541 });5542}5543 5544TEST(TransferTest, LoopWithStagedAssignments) {5545 std::string Code = R"(5546 bool foo();5547 5548 void target() {5549 bool Bar = false;5550 bool Err = false;5551 while (foo()) {5552 if (Bar)5553 Err = true;5554 Bar = true;5555 /*[[p]]*/5556 }5557 }5558 )";5559 runDataflow(5560 Code,5561 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5562 ASTContext &ASTCtx) {5563 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));5564 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5565 5566 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");5567 ASSERT_THAT(BarDecl, NotNull());5568 const ValueDecl *ErrDecl = findValueDecl(ASTCtx, "Err");5569 ASSERT_THAT(ErrDecl, NotNull());5570 5571 auto &BarVal = getFormula(*BarDecl, Env);5572 auto &ErrVal = getFormula(*ErrDecl, Env);5573 EXPECT_TRUE(Env.proves(BarVal));5574 // An unsound analysis, for example only evaluating the loop once, can5575 // conclude that `Err` is false. So, we test that this conclusion is not5576 // reached.5577 EXPECT_FALSE(Env.proves(Env.arena().makeNot(ErrVal)));5578 });5579}5580 5581TEST(TransferTest, LoopWithReferenceAssignmentConverges) {5582 std::string Code = R"(5583 bool &foo();5584 5585 void target() {5586 do {5587 bool& Bar = foo();5588 if (Bar) break;5589 (void)Bar;5590 /*[[p]]*/5591 } while (true);5592 }5593 )";5594 // The key property that we are verifying is that the analysis succeeds,5595 // rather than hitting the maximum number of iterations.5596 runDataflow(5597 Code,5598 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5599 ASTContext &ASTCtx) {5600 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));5601 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5602 5603 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");5604 ASSERT_THAT(BarDecl, NotNull());5605 5606 auto &BarVal = getFormula(*BarDecl, Env);5607 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal)));5608 });5609}5610 5611TEST(TransferTest, LoopWithStructReferenceAssignmentConverges) {5612 std::string Code = R"(5613 struct Lookup {5614 int x;5615 };5616 5617 void target(Lookup val, bool b) {5618 const Lookup* l = nullptr;5619 while (b) {5620 l = &val;5621 /*[[p-inner]]*/5622 }5623 (void)0;5624 /*[[p-outer]]*/5625 }5626 )";5627 // The key property that we are verifying is implicit in `runDataflow` --5628 // namely, that the analysis succeeds, rather than hitting the maximum number5629 // of iterations.5630 runDataflow(5631 Code,5632 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5633 ASTContext &ASTCtx) {5634 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p-inner", "p-outer"));5635 const Environment &InnerEnv =5636 getEnvironmentAtAnnotation(Results, "p-inner");5637 const Environment &OuterEnv =5638 getEnvironmentAtAnnotation(Results, "p-outer");5639 5640 const ValueDecl *ValDecl = findValueDecl(ASTCtx, "val");5641 ASSERT_THAT(ValDecl, NotNull());5642 5643 const ValueDecl *LDecl = findValueDecl(ASTCtx, "l");5644 ASSERT_THAT(LDecl, NotNull());5645 5646 // Inner.5647 auto *LVal = dyn_cast<PointerValue>(InnerEnv.getValue(*LDecl));5648 ASSERT_THAT(LVal, NotNull());5649 5650 EXPECT_EQ(&LVal->getPointeeLoc(),5651 InnerEnv.getStorageLocation(*ValDecl));5652 5653 // Outer.5654 LVal = dyn_cast<PointerValue>(OuterEnv.getValue(*LDecl));5655 ASSERT_THAT(LVal, NotNull());5656 5657 // The loop body may not have been executed, so we should not conclude5658 // that `l` points to `val`.5659 EXPECT_NE(&LVal->getPointeeLoc(),5660 OuterEnv.getStorageLocation(*ValDecl));5661 });5662}5663 5664TEST(TransferTest, LoopDereferencingChangingPointerConverges) {5665 std::string Code = R"cc(5666 bool some_condition();5667 5668 void target(int i1, int i2) {5669 int *p = &i1;5670 while (true) {5671 (void)*p;5672 if (some_condition())5673 p = &i1;5674 else5675 p = &i2;5676 }5677 }5678 )cc";5679 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded());5680}5681 5682TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) {5683 std::string Code = R"cc(5684 struct Lookup {5685 int x;5686 };5687 5688 bool some_condition();5689 5690 void target(Lookup l1, Lookup l2) {5691 Lookup *l = &l1;5692 while (true) {5693 (void)l->x;5694 if (some_condition())5695 l = &l1;5696 else5697 l = &l2;5698 }5699 }5700 )cc";5701 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded());5702}5703 5704TEST(TransferTest, LoopWithShortCircuitedConditionConverges) {5705 std::string Code = R"cc(5706 bool foo();5707 5708 void target() {5709 bool c = false;5710 while (foo() || foo()) {5711 c = true;5712 }5713 }5714 )cc";5715 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code), llvm::Succeeded());5716}5717 5718TEST(TransferTest, LoopCanProveInvariantForBoolean) {5719 // Check that we can prove `b` is always false in the loop.5720 // This test exercises the logic in `widenDistinctValues()` that preserves5721 // information if the boolean can be proved to be either true or false in both5722 // the previous and current iteration.5723 std::string Code = R"cc(5724 int return_int();5725 void target() {5726 bool b = return_int() == 0;5727 if (b) return;5728 while (true) {5729 b;5730 // [[p]]5731 b = return_int() == 0;5732 if (b) return;5733 }5734 }5735 )cc";5736 runDataflow(5737 Code,5738 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5739 ASTContext &ASTCtx) {5740 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5741 auto &BVal = getValueForDecl<BoolValue>(ASTCtx, Env, "b");5742 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BVal.formula())));5743 });5744}5745 5746TEST(TransferTest, DoesNotCrashOnUnionThisExpr) {5747 std::string Code = R"cc(5748 union Union {5749 int A;5750 float B;5751 };5752 5753 void foo() {5754 Union A;5755 Union B;5756 A = B;5757 }5758 )cc";5759 // This is a crash regression test when calling the transfer function on a5760 // `CXXThisExpr` that refers to a union.5761 runDataflow(5762 Code,5763 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,5764 ASTContext &) {},5765 LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "operator=");5766}5767 5768TEST(TransferTest, DoesNotCrashOnNullChildren) {5769 std::string Code = (CoroutineLibrary + R"cc(5770 task target() noexcept {5771 co_return;5772 }5773 )cc")5774 .str();5775 // This is a crash regression test when calling `AdornedCFG::build` on a5776 // statement (in this case, the `CoroutineBodyStmt`) with null children.5777 runDataflow(5778 Code,5779 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,5780 ASTContext &) {},5781 LangStandard::lang_cxx20, /*ApplyBuiltinTransfer=*/true);5782}5783 5784TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToRefs) {5785 std::string Code = R"(5786 struct A {5787 int Foo;5788 int Bar;5789 };5790 5791 void target() {5792 int Qux;5793 A Baz;5794 Baz.Foo = Qux;5795 auto &FooRef = Baz.Foo;5796 auto &BarRef = Baz.Bar;5797 auto &[BoundFooRef, BoundBarRef] = Baz;5798 // [[p]]5799 }5800 )";5801 runDataflow(5802 Code,5803 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5804 ASTContext &ASTCtx) {5805 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));5806 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5807 5808 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef");5809 ASSERT_THAT(FooRefDecl, NotNull());5810 5811 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef");5812 ASSERT_THAT(BarRefDecl, NotNull());5813 5814 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");5815 ASSERT_THAT(QuxDecl, NotNull());5816 5817 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef");5818 ASSERT_THAT(BoundFooRefDecl, NotNull());5819 5820 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef");5821 ASSERT_THAT(BoundBarRefDecl, NotNull());5822 5823 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl);5824 ASSERT_THAT(FooRefLoc, NotNull());5825 5826 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl);5827 ASSERT_THAT(BarRefLoc, NotNull());5828 5829 const Value *QuxVal = Env.getValue(*QuxDecl);5830 ASSERT_THAT(QuxVal, NotNull());5831 5832 const StorageLocation *BoundFooRefLoc =5833 Env.getStorageLocation(*BoundFooRefDecl);5834 EXPECT_EQ(BoundFooRefLoc, FooRefLoc);5835 5836 const StorageLocation *BoundBarRefLoc =5837 Env.getStorageLocation(*BoundBarRefDecl);5838 EXPECT_EQ(BoundBarRefLoc, BarRefLoc);5839 5840 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal);5841 });5842}5843 5844TEST(TransferTest, StructuredBindingAssignFromStructRefMembersToRefs) {5845 std::string Code = R"(5846 struct A {5847 int &Foo;5848 int &Bar;5849 };5850 5851 void target(A Baz) {5852 int Qux;5853 Baz.Foo = Qux;5854 auto &FooRef = Baz.Foo;5855 auto &BarRef = Baz.Bar;5856 auto &[BoundFooRef, BoundBarRef] = Baz;5857 // [[p]]5858 }5859 )";5860 runDataflow(5861 Code,5862 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5863 ASTContext &ASTCtx) {5864 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));5865 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5866 5867 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef");5868 ASSERT_THAT(FooRefDecl, NotNull());5869 5870 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef");5871 ASSERT_THAT(BarRefDecl, NotNull());5872 5873 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");5874 ASSERT_THAT(QuxDecl, NotNull());5875 5876 const ValueDecl *BoundFooRefDecl = findValueDecl(ASTCtx, "BoundFooRef");5877 ASSERT_THAT(BoundFooRefDecl, NotNull());5878 5879 const ValueDecl *BoundBarRefDecl = findValueDecl(ASTCtx, "BoundBarRef");5880 ASSERT_THAT(BoundBarRefDecl, NotNull());5881 5882 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl);5883 ASSERT_THAT(FooRefLoc, NotNull());5884 5885 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl);5886 ASSERT_THAT(BarRefLoc, NotNull());5887 5888 const Value *QuxVal = Env.getValue(*QuxDecl);5889 ASSERT_THAT(QuxVal, NotNull());5890 5891 const StorageLocation *BoundFooRefLoc =5892 Env.getStorageLocation(*BoundFooRefDecl);5893 EXPECT_EQ(BoundFooRefLoc, FooRefLoc);5894 5895 const StorageLocation *BoundBarRefLoc =5896 Env.getStorageLocation(*BoundBarRefDecl);5897 EXPECT_EQ(BoundBarRefLoc, BarRefLoc);5898 5899 EXPECT_EQ(Env.getValue(*BoundFooRefDecl), QuxVal);5900 });5901}5902 5903TEST(TransferTest, StructuredBindingAssignFromStructIntMembersToInts) {5904 std::string Code = R"(5905 struct A {5906 int Foo;5907 int Bar;5908 };5909 5910 void target() {5911 int Qux;5912 A Baz;5913 Baz.Foo = Qux;5914 auto &FooRef = Baz.Foo;5915 auto &BarRef = Baz.Bar;5916 auto [BoundFoo, BoundBar] = Baz;5917 // [[p]]5918 }5919 )";5920 runDataflow(5921 Code,5922 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,5923 ASTContext &ASTCtx) {5924 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));5925 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");5926 5927 const ValueDecl *FooRefDecl = findValueDecl(ASTCtx, "FooRef");5928 ASSERT_THAT(FooRefDecl, NotNull());5929 5930 const ValueDecl *BarRefDecl = findValueDecl(ASTCtx, "BarRef");5931 ASSERT_THAT(BarRefDecl, NotNull());5932 5933 const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo");5934 ASSERT_THAT(BoundFooDecl, NotNull());5935 5936 const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");5937 ASSERT_THAT(BoundBarDecl, NotNull());5938 5939 const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");5940 ASSERT_THAT(QuxDecl, NotNull());5941 5942 const StorageLocation *FooRefLoc = Env.getStorageLocation(*FooRefDecl);5943 ASSERT_THAT(FooRefLoc, NotNull());5944 5945 const StorageLocation *BarRefLoc = Env.getStorageLocation(*BarRefDecl);5946 ASSERT_THAT(BarRefLoc, NotNull());5947 5948 const Value *QuxVal = Env.getValue(*QuxDecl);5949 ASSERT_THAT(QuxVal, NotNull());5950 5951 const StorageLocation *BoundFooLoc =5952 Env.getStorageLocation(*BoundFooDecl);5953 EXPECT_NE(BoundFooLoc, FooRefLoc);5954 5955 const StorageLocation *BoundBarLoc =5956 Env.getStorageLocation(*BoundBarDecl);5957 EXPECT_NE(BoundBarLoc, BarRefLoc);5958 5959 EXPECT_EQ(Env.getValue(*BoundFooDecl), QuxVal);5960 });5961}5962 5963TEST(TransferTest, StructuredBindingAssignFromTupleLikeType) {5964 std::string Code = R"(5965 namespace std {5966 using size_t = int;5967 template <class> struct tuple_size;5968 template <std::size_t, class> struct tuple_element;5969 template <class...> class tuple;5970 5971 namespace {5972 template <class T, T v>5973 struct size_helper { static const T value = v; };5974 } // namespace5975 5976 template <class... T>5977 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {};5978 5979 template <std::size_t I, class... T>5980 struct tuple_element<I, tuple<T...>> {5981 using type = __type_pack_element<I, T...>;5982 };5983 5984 template <class...> class tuple {};5985 5986 template <std::size_t I, class... T>5987 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);5988 } // namespace std5989 5990 std::tuple<bool, int> makeTuple();5991 5992 void target(bool B) {5993 auto [BoundFoo, BoundBar] = makeTuple();5994 bool Baz;5995 // Include if-then-else to test interaction of `BindingDecl` with join.5996 if (B) {5997 Baz = BoundFoo;5998 (void)BoundBar;5999 // [[p1]]6000 } else {6001 Baz = BoundFoo;6002 }6003 (void)0;6004 // [[p2]]6005 }6006 )";6007 runDataflow(6008 Code,6009 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6010 ASTContext &ASTCtx) {6011 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));6012 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");6013 6014 const ValueDecl *BoundFooDecl = findBindingDecl(ASTCtx, "BoundFoo");6015 ASSERT_THAT(BoundFooDecl, NotNull());6016 6017 const ValueDecl *BoundBarDecl = findBindingDecl(ASTCtx, "BoundBar");6018 ASSERT_THAT(BoundBarDecl, NotNull());6019 6020 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");6021 ASSERT_THAT(BazDecl, NotNull());6022 6023 // BindingDecls always map to references -- either lvalue or rvalue, so6024 // we still need to skip here.6025 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl);6026 ASSERT_THAT(BoundFooValue, NotNull());6027 EXPECT_TRUE(isa<BoolValue>(BoundFooValue));6028 6029 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl);6030 ASSERT_THAT(BoundBarValue, NotNull());6031 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue));6032 6033 // Test that a `DeclRefExpr` to a `BindingDecl` works as expected.6034 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue);6035 6036 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");6037 6038 // Test that `BoundFooDecl` retains the value we expect, after the join.6039 BoundFooValue = Env2.getValue(*BoundFooDecl);6040 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue);6041 });6042}6043 6044TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) {6045 std::string Code = R"(6046 namespace std {6047 using size_t = int;6048 template <class> struct tuple_size;6049 template <std::size_t, class> struct tuple_element;6050 template <class...> class tuple;6051 6052 namespace {6053 template <class T, T v>6054 struct size_helper { static const T value = v; };6055 } // namespace6056 6057 template <class... T>6058 struct tuple_size<tuple<T...>> : size_helper<std::size_t, sizeof...(T)> {};6059 6060 template <std::size_t I, class... T>6061 struct tuple_element<I, tuple<T...>> {6062 using type = __type_pack_element<I, T...>;6063 };6064 6065 template <class...> class tuple {};6066 6067 template <std::size_t I, class... T>6068 typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);6069 } // namespace std6070 6071 std::tuple<bool, int> &getTuple();6072 6073 void target(bool B) {6074 auto &[BoundFoo, BoundBar] = getTuple();6075 bool Baz;6076 // Include if-then-else to test interaction of `BindingDecl` with join.6077 if (B) {6078 Baz = BoundFoo;6079 (void)BoundBar;6080 // [[p1]]6081 } else {6082 Baz = BoundFoo;6083 }6084 (void)0;6085 // [[p2]]6086 }6087 )";6088 runDataflow(6089 Code,6090 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6091 ASTContext &ASTCtx) {6092 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));6093 const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");6094 6095 const ValueDecl *BoundFooDecl = findBindingDecl(ASTCtx, "BoundFoo");6096 ASSERT_THAT(BoundFooDecl, NotNull());6097 6098 const ValueDecl *BoundBarDecl = findBindingDecl(ASTCtx, "BoundBar");6099 ASSERT_THAT(BoundBarDecl, NotNull());6100 6101 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");6102 ASSERT_THAT(BazDecl, NotNull());6103 6104 const Value *BoundFooValue = Env1.getValue(*BoundFooDecl);6105 ASSERT_THAT(BoundFooValue, NotNull());6106 EXPECT_TRUE(isa<BoolValue>(BoundFooValue));6107 6108 const Value *BoundBarValue = Env1.getValue(*BoundBarDecl);6109 ASSERT_THAT(BoundBarValue, NotNull());6110 EXPECT_TRUE(isa<IntegerValue>(BoundBarValue));6111 6112 // Test that a `DeclRefExpr` to a `BindingDecl` (with reference type)6113 // works as expected. We don't test aliasing properties of the6114 // reference, because we don't model `std::get` and so have no way to6115 // equate separate references into the tuple.6116 EXPECT_EQ(Env1.getValue(*BazDecl), BoundFooValue);6117 6118 const Environment &Env2 = getEnvironmentAtAnnotation(Results, "p2");6119 6120 // Test that `BoundFooDecl` retains the value we expect, after the join.6121 BoundFooValue = Env2.getValue(*BoundFooDecl);6122 EXPECT_EQ(Env2.getValue(*BazDecl), BoundFooValue);6123 });6124}6125 6126TEST(TransferTest, BinaryOperatorComma) {6127 std::string Code = R"(6128 void target(int Foo, int Bar) {6129 int &Baz = (Foo, Bar);6130 // [[p]]6131 }6132 )";6133 runDataflow(6134 Code,6135 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6136 ASTContext &ASTCtx) {6137 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));6138 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");6139 6140 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");6141 ASSERT_THAT(BarDecl, NotNull());6142 6143 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");6144 ASSERT_THAT(BazDecl, NotNull());6145 6146 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);6147 ASSERT_THAT(BarLoc, NotNull());6148 6149 const StorageLocation *BazLoc = Env.getStorageLocation(*BazDecl);6150 EXPECT_EQ(BazLoc, BarLoc);6151 });6152}6153 6154TEST(TransferTest, ConditionalOperatorValue) {6155 std::string Code = R"(6156 void target(bool Cond, bool B1, bool B2) {6157 bool JoinSame = Cond ? B1 : B1;6158 bool JoinDifferent = Cond ? B1 : B2;6159 // [[p]]6160 }6161 )";6162 runDataflow(6163 Code,6164 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6165 ASTContext &ASTCtx) {6166 Environment Env = getEnvironmentAtAnnotation(Results, "p").fork();6167 6168 auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, "B1");6169 auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, "B2");6170 auto &JoinSame = getValueForDecl<BoolValue>(ASTCtx, Env, "JoinSame");6171 auto &JoinDifferent =6172 getValueForDecl<BoolValue>(ASTCtx, Env, "JoinDifferent");6173 6174 EXPECT_EQ(&JoinSame, &B1);6175 6176 const Formula &JoinDifferentEqB1 =6177 Env.arena().makeEquals(JoinDifferent.formula(), B1.formula());6178 EXPECT_TRUE(Env.allows(JoinDifferentEqB1));6179 EXPECT_FALSE(Env.proves(JoinDifferentEqB1));6180 6181 const Formula &JoinDifferentEqB2 =6182 Env.arena().makeEquals(JoinDifferent.formula(), B2.formula());6183 EXPECT_TRUE(Env.allows(JoinDifferentEqB2));6184 EXPECT_FALSE(Env.proves(JoinDifferentEqB1));6185 });6186}6187 6188TEST(TransferTest, ConditionalOperatorValuesTested) {6189 // We should be able to show that the result of the conditional operator,6190 // JoinResultMustBeB1, must be equal to B1, because the condition is checking6191 // `B1 == B2` and selecting B1 on the false branch, or B2 on the true branch.6192 // Similarly, for JoinResultMustBeB2 == B2.6193 // Note that the conditional operator involves a join of two *different*6194 // glvalues, before casting the lvalue to an rvalue, which may affect the6195 // implementation of the transfer function, and thus affect whether or not we6196 // can prove that IsB1 == B1.6197 std::string Code = R"(6198 void target(bool B1, bool B2) {6199 bool JoinResultMustBeB1 = (B1 == B2) ? B2 : B1;6200 bool JoinResultMustBeB2 = (B1 == B2) ? B1 : B2;6201 // [[p]]6202 }6203 )";6204 runDataflow(6205 Code,6206 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6207 ASTContext &ASTCtx) {6208 Environment Env = getEnvironmentAtAnnotation(Results, "p").fork();6209 6210 auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, "B1");6211 auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, "B2");6212 auto &JoinResultMustBeB1 =6213 getValueForDecl<BoolValue>(ASTCtx, Env, "JoinResultMustBeB1");6214 auto &JoinResultMustBeB2 =6215 getValueForDecl<BoolValue>(ASTCtx, Env, "JoinResultMustBeB2");6216 6217 const Formula &MustBeB1_Eq_B1 =6218 Env.arena().makeEquals(JoinResultMustBeB1.formula(), B1.formula());6219 EXPECT_TRUE(Env.proves(MustBeB1_Eq_B1));6220 6221 const Formula &MustBeB2_Eq_B2 =6222 Env.arena().makeEquals(JoinResultMustBeB2.formula(), B2.formula());6223 EXPECT_TRUE(Env.proves(MustBeB2_Eq_B2));6224 });6225}6226 6227TEST(TransferTest, ConditionalOperatorLocation) {6228 std::string Code = R"(6229 void target(bool Cond, int I1, int I2) {6230 int &JoinSame = Cond ? I1 : I1;6231 int &JoinDifferent = Cond ? I1 : I2;6232 // [[p]]6233 }6234 )";6235 runDataflow(6236 Code,6237 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6238 ASTContext &ASTCtx) {6239 Environment Env = getEnvironmentAtAnnotation(Results, "p").fork();6240 6241 StorageLocation &I1 = getLocForDecl(ASTCtx, Env, "I1");6242 StorageLocation &I2 = getLocForDecl(ASTCtx, Env, "I2");6243 StorageLocation &JoinSame = getLocForDecl(ASTCtx, Env, "JoinSame");6244 StorageLocation &JoinDifferent =6245 getLocForDecl(ASTCtx, Env, "JoinDifferent");6246 6247 EXPECT_EQ(&JoinSame, &I1);6248 6249 EXPECT_NE(&JoinDifferent, &I1);6250 EXPECT_NE(&JoinDifferent, &I2);6251 });6252}6253 6254TEST(TransferTest, ConditionalOperatorLocationUpdatedAfter) {6255 // We don't currently model a Conditional Operator with an LValue result6256 // as having aliases to the LHS and RHS (if it isn't just the same LValue6257 // on both sides). We also don't model that the update "may" happen6258 // (a weak update). So, we don't consider the LHS and RHS as being weakly6259 // updated at [[after_diff]].6260 std::string Code = R"(6261 void target(bool Cond, bool B1, bool B2) {6262 (void)0;6263 // [[before_same]]6264 (Cond ? B1 : B1) = !B1;6265 // [[after_same]]6266 (Cond ? B1 : B2) = !B1;6267 // [[after_diff]]6268 }6269 )";6270 runDataflow(6271 Code,6272 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6273 ASTContext &ASTCtx) {6274 Environment BeforeSameEnv =6275 getEnvironmentAtAnnotation(Results, "before_same").fork();6276 Environment AfterSameEnv =6277 getEnvironmentAtAnnotation(Results, "after_same").fork();6278 Environment AfterDiffEnv =6279 getEnvironmentAtAnnotation(Results, "after_diff").fork();6280 6281 auto &BeforeSameB1 =6282 getValueForDecl<BoolValue>(ASTCtx, BeforeSameEnv, "B1");6283 auto &AfterSameB1 =6284 getValueForDecl<BoolValue>(ASTCtx, AfterSameEnv, "B1");6285 auto &AfterDiffB1 =6286 getValueForDecl<BoolValue>(ASTCtx, AfterDiffEnv, "B1");6287 6288 EXPECT_NE(&BeforeSameB1, &AfterSameB1);6289 EXPECT_NE(&BeforeSameB1, &AfterDiffB1);6290 // FIXME: The formula for AfterSameB1 should be different from6291 // AfterDiffB1 to reflect that B1 may be updated.6292 EXPECT_EQ(&AfterSameB1, &AfterDiffB1);6293 6294 // The value of B1 is definitely different from before_same vs6295 // after_same.6296 const Formula &B1ChangedForSame =6297 AfterSameEnv.arena().makeNot(AfterSameEnv.arena().makeEquals(6298 AfterSameB1.formula(), BeforeSameB1.formula()));6299 EXPECT_TRUE(AfterSameEnv.allows(B1ChangedForSame));6300 EXPECT_TRUE(AfterSameEnv.proves(B1ChangedForSame));6301 6302 const Formula &B1ChangedForDiff =6303 AfterDiffEnv.arena().makeNot(AfterDiffEnv.arena().makeEquals(6304 AfterDiffB1.formula(), AfterSameB1.formula()));6305 // FIXME: It should be possible that B1 *may* be updated, so it may be6306 // that AfterSameB1 != AfterDiffB1 or AfterSameB1 == AfterDiffB1.6307 EXPECT_FALSE(AfterSameEnv.allows(B1ChangedForDiff));6308 // proves() should be false, since B1 may or may not have changed6309 // depending on `Cond`.6310 EXPECT_FALSE(AfterSameEnv.proves(B1ChangedForDiff));6311 });6312}6313 6314TEST(TransferTest, ConditionalOperatorOnConstantExpr) {6315 // This is a regression test: We used to crash when a `ConstantExpr` was used6316 // in the branches of a conditional operator.6317 std::string Code = R"cc(6318 consteval bool identity(bool B) { return B; }6319 void target(bool Cond) {6320 bool JoinTrueTrue = Cond ? identity(true) : identity(true);6321 bool JoinTrueFalse = Cond ? identity(true) : identity(false);6322 // [[p]]6323 }6324 )cc";6325 runDataflow(6326 Code,6327 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6328 ASTContext &ASTCtx) {6329 Environment Env = getEnvironmentAtAnnotation(Results, "p").fork();6330 6331 auto &JoinTrueTrue =6332 getValueForDecl<BoolValue>(ASTCtx, Env, "JoinTrueTrue");6333 // FIXME: This test documents the current behavior, namely that we6334 // don't actually use the constant result of the `ConstantExpr` and6335 // instead treat it like a normal function call.6336 EXPECT_EQ(JoinTrueTrue.formula().kind(), Formula::Kind::AtomRef);6337 // EXPECT_TRUE(JoinTrueTrue.formula().literal());6338 6339 auto &JoinTrueFalse =6340 getValueForDecl<BoolValue>(ASTCtx, Env, "JoinTrueFalse");6341 EXPECT_EQ(JoinTrueFalse.formula().kind(), Formula::Kind::AtomRef);6342 },6343 LangStandard::lang_cxx20);6344}6345 6346TEST(TransferTest, IfStmtBranchExtendsFlowCondition) {6347 std::string Code = R"(6348 void target(bool Foo) {6349 if (Foo) {6350 (void)0;6351 // [[if_then]]6352 } else {6353 (void)0;6354 // [[if_else]]6355 }6356 }6357 )";6358 runDataflow(6359 Code,6360 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6361 ASTContext &ASTCtx) {6362 ASSERT_THAT(Results.keys(), UnorderedElementsAre("if_then", "if_else"));6363 const Environment &ThenEnv =6364 getEnvironmentAtAnnotation(Results, "if_then");6365 const Environment &ElseEnv =6366 getEnvironmentAtAnnotation(Results, "if_else");6367 6368 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");6369 ASSERT_THAT(FooDecl, NotNull());6370 6371 auto &ThenFooVal= getFormula(*FooDecl, ThenEnv);6372 EXPECT_TRUE(ThenEnv.proves(ThenFooVal));6373 6374 auto &ElseFooVal = getFormula(*FooDecl, ElseEnv);6375 EXPECT_TRUE(ElseEnv.proves(ElseEnv.arena().makeNot(ElseFooVal)));6376 });6377}6378 6379TEST(TransferTest, WhileStmtBranchExtendsFlowCondition) {6380 std::string Code = R"(6381 void target(bool Foo) {6382 while (Foo) {6383 (void)0;6384 // [[loop_body]]6385 }6386 (void)0;6387 // [[after_loop]]6388 }6389 )";6390 runDataflow(6391 Code,6392 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6393 ASTContext &ASTCtx) {6394 ASSERT_THAT(Results.keys(),6395 UnorderedElementsAre("loop_body", "after_loop"));6396 const Environment &LoopBodyEnv =6397 getEnvironmentAtAnnotation(Results, "loop_body");6398 const Environment &AfterLoopEnv =6399 getEnvironmentAtAnnotation(Results, "after_loop");6400 6401 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");6402 ASSERT_THAT(FooDecl, NotNull());6403 6404 auto &LoopBodyFooVal = getFormula(*FooDecl, LoopBodyEnv);6405 EXPECT_TRUE(LoopBodyEnv.proves(LoopBodyFooVal));6406 6407 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv);6408 EXPECT_TRUE(6409 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal)));6410 });6411}6412 6413TEST(TransferTest, DoWhileStmtBranchExtendsFlowCondition) {6414 std::string Code = R"(6415 void target(bool Foo) {6416 bool Bar = true;6417 do {6418 (void)0;6419 // [[loop_body]]6420 Bar = false;6421 } while (Foo);6422 (void)0;6423 // [[after_loop]]6424 }6425 )";6426 runDataflow(6427 Code,6428 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6429 ASTContext &ASTCtx) {6430 ASSERT_THAT(Results.keys(),6431 UnorderedElementsAre("loop_body", "after_loop"));6432 const Environment &LoopBodyEnv =6433 getEnvironmentAtAnnotation(Results, "loop_body");6434 const Environment &AfterLoopEnv =6435 getEnvironmentAtAnnotation(Results, "after_loop");6436 auto &A = AfterLoopEnv.arena();6437 6438 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");6439 ASSERT_THAT(FooDecl, NotNull());6440 6441 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");6442 ASSERT_THAT(BarDecl, NotNull());6443 6444 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv);6445 auto &LoopBodyBarVal = getFormula(*BarDecl, LoopBodyEnv);6446 EXPECT_TRUE(6447 LoopBodyEnv.proves(A.makeOr(LoopBodyBarVal, LoopBodyFooVal)));6448 6449 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv);6450 auto &AfterLoopBarVal = getFormula(*BarDecl, AfterLoopEnv);6451 EXPECT_TRUE(AfterLoopEnv.proves(A.makeNot(AfterLoopFooVal)));6452 EXPECT_TRUE(AfterLoopEnv.proves(A.makeNot(AfterLoopBarVal)));6453 });6454}6455 6456TEST(TransferTest, ForStmtBranchExtendsFlowCondition) {6457 std::string Code = R"(6458 void target(bool Foo) {6459 for (; Foo;) {6460 (void)0;6461 // [[loop_body]]6462 }6463 (void)0;6464 // [[after_loop]]6465 }6466 )";6467 runDataflow(6468 Code,6469 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6470 ASTContext &ASTCtx) {6471 ASSERT_THAT(Results.keys(),6472 UnorderedElementsAre("loop_body", "after_loop"));6473 const Environment &LoopBodyEnv =6474 getEnvironmentAtAnnotation(Results, "loop_body");6475 const Environment &AfterLoopEnv =6476 getEnvironmentAtAnnotation(Results, "after_loop");6477 6478 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");6479 ASSERT_THAT(FooDecl, NotNull());6480 6481 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv);6482 EXPECT_TRUE(LoopBodyEnv.proves(LoopBodyFooVal));6483 6484 auto &AfterLoopFooVal = getFormula(*FooDecl, AfterLoopEnv);6485 EXPECT_TRUE(6486 AfterLoopEnv.proves(AfterLoopEnv.arena().makeNot(AfterLoopFooVal)));6487 });6488}6489 6490TEST(TransferTest, ForStmtBranchWithoutConditionDoesNotExtendFlowCondition) {6491 std::string Code = R"(6492 void target(bool Foo) {6493 for (;;) {6494 (void)0;6495 // [[loop_body]]6496 }6497 }6498 )";6499 runDataflow(6500 Code,6501 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6502 ASTContext &ASTCtx) {6503 ASSERT_THAT(Results.keys(), UnorderedElementsAre("loop_body"));6504 const Environment &LoopBodyEnv =6505 getEnvironmentAtAnnotation(Results, "loop_body");6506 6507 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");6508 ASSERT_THAT(FooDecl, NotNull());6509 6510 auto &LoopBodyFooVal= getFormula(*FooDecl, LoopBodyEnv);6511 EXPECT_FALSE(LoopBodyEnv.proves(LoopBodyFooVal));6512 });6513}6514 6515TEST(TransferTest, ContextSensitiveOptionDisabled) {6516 std::string Code = R"(6517 bool GiveBool();6518 void SetBool(bool &Var) { Var = true; }6519 6520 void target() {6521 bool Foo = GiveBool();6522 SetBool(Foo);6523 // [[p]]6524 }6525 )";6526 runDataflow(6527 Code,6528 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6529 ASTContext &ASTCtx) {6530 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));6531 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");6532 6533 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");6534 ASSERT_THAT(FooDecl, NotNull());6535 6536 auto &FooVal = getFormula(*FooDecl, Env);6537 EXPECT_FALSE(Env.proves(FooVal));6538 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));6539 },6540 {BuiltinOptions{/*.ContextSensitiveOpts=*/std::nullopt}});6541}6542 6543TEST(TransferTest, ContextSensitiveReturnReference) {6544 std::string Code = R"(6545 class S {};6546 S& target(bool b, S &s) {6547 return s;6548 // [[p]]6549 }6550 )";6551 runDataflow(6552 Code,6553 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6554 ASTContext &ASTCtx) {6555 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");6556 6557 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s");6558 ASSERT_THAT(SDecl, NotNull());6559 6560 auto *SLoc = Env.getStorageLocation(*SDecl);6561 ASSERT_THAT(SLoc, NotNull());6562 6563 ASSERT_THAT(Env.getReturnStorageLocation(), Eq(SLoc));6564 },6565 {BuiltinOptions{ContextSensitiveOptions{}}});6566}6567 6568// This test is a regression test, based on a real crash.6569TEST(TransferTest, ContextSensitiveReturnReferenceWithConditionalOperator) {6570 std::string Code = R"(6571 class S {};6572 S& target(bool b, S &s) {6573 return b ? s : s;6574 // [[p]]6575 }6576 )";6577 runDataflow(6578 Code,6579 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6580 ASTContext &ASTCtx) {6581 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));6582 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");6583 6584 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s");6585 ASSERT_THAT(SDecl, NotNull());6586 6587 auto *SLoc = Env.getStorageLocation(*SDecl);6588 EXPECT_THAT(SLoc, NotNull());6589 6590 auto *Loc = Env.getReturnStorageLocation();6591 EXPECT_THAT(Loc, NotNull());6592 6593 EXPECT_EQ(Loc, SLoc);6594 },6595 {BuiltinOptions{ContextSensitiveOptions{}}});6596}6597 6598TEST(TransferTest, ContextSensitiveReturnOneOfTwoReferences) {6599 std::string Code = R"(6600 class S {};6601 S &callee(bool b, S &s1_parm, S &s2_parm) {6602 if (b)6603 return s1_parm;6604 else6605 return s2_parm;6606 }6607 void target(bool b) {6608 S s1;6609 S s2;6610 S &return_s1 = s1;6611 S &return_s2 = s2;6612 S &return_dont_know = callee(b, s1, s2);6613 // [[p]]6614 }6615 )";6616 runDataflow(6617 Code,6618 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6619 ASTContext &ASTCtx) {6620 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");6621 6622 const ValueDecl *S1 = findValueDecl(ASTCtx, "s1");6623 ASSERT_THAT(S1, NotNull());6624 const ValueDecl *S2 = findValueDecl(ASTCtx, "s2");6625 ASSERT_THAT(S2, NotNull());6626 const ValueDecl *ReturnS1 = findValueDecl(ASTCtx, "return_s1");6627 ASSERT_THAT(ReturnS1, NotNull());6628 const ValueDecl *ReturnS2 = findValueDecl(ASTCtx, "return_s2");6629 ASSERT_THAT(ReturnS2, NotNull());6630 const ValueDecl *ReturnDontKnow =6631 findValueDecl(ASTCtx, "return_dont_know");6632 ASSERT_THAT(ReturnDontKnow, NotNull());6633 6634 StorageLocation *S1Loc = Env.getStorageLocation(*S1);6635 StorageLocation *S2Loc = Env.getStorageLocation(*S2);6636 6637 EXPECT_THAT(Env.getStorageLocation(*ReturnS1), Eq(S1Loc));6638 EXPECT_THAT(Env.getStorageLocation(*ReturnS2), Eq(S2Loc));6639 6640 // In the case where we don't have a consistent storage location for6641 // the return value, the framework creates a new storage location, which6642 // should be different from the storage locations of `s1` and `s2`.6643 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S1Loc));6644 EXPECT_THAT(Env.getStorageLocation(*ReturnDontKnow), Ne(S2Loc));6645 },6646 {BuiltinOptions{ContextSensitiveOptions{}}});6647}6648 6649TEST(TransferTest, ContextSensitiveDepthZero) {6650 std::string Code = R"(6651 bool GiveBool();6652 void SetBool(bool &Var) { Var = true; }6653 6654 void target() {6655 bool Foo = GiveBool();6656 SetBool(Foo);6657 // [[p]]6658 }6659 )";6660 runDataflow(6661 Code,6662 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6663 ASTContext &ASTCtx) {6664 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));6665 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");6666 6667 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");6668 ASSERT_THAT(FooDecl, NotNull());6669 6670 auto &FooVal = getFormula(*FooDecl, Env);6671 EXPECT_FALSE(Env.proves(FooVal));6672 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));6673 },6674 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/0}}});6675}6676 6677TEST(TransferTest, ContextSensitiveSetTrue) {6678 std::string Code = R"(6679 bool GiveBool();6680 void SetBool(bool &Var) { Var = true; }6681 6682 void target() {6683 bool Foo = GiveBool();6684 SetBool(Foo);6685 // [[p]]6686 }6687 )";6688 runDataflow(6689 Code,6690 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6691 ASTContext &ASTCtx) {6692 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));6693 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");6694 6695 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");6696 ASSERT_THAT(FooDecl, NotNull());6697 6698 auto &FooVal = getFormula(*FooDecl, Env);6699 EXPECT_TRUE(Env.proves(FooVal));6700 },6701 {BuiltinOptions{ContextSensitiveOptions{}}});6702}6703 6704TEST(TransferTest, ContextSensitiveSetFalse) {6705 std::string Code = R"(6706 bool GiveBool();6707 void SetBool(bool &Var) { Var = false; }6708 6709 void target() {6710 bool Foo = GiveBool();6711 SetBool(Foo);6712 // [[p]]6713 }6714 )";6715 runDataflow(6716 Code,6717 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6718 ASTContext &ASTCtx) {6719 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));6720 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");6721 6722 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");6723 ASSERT_THAT(FooDecl, NotNull());6724 6725 auto &FooVal = getFormula(*FooDecl, Env);6726 EXPECT_TRUE(Env.proves(Env.arena().makeNot(FooVal)));6727 },6728 {BuiltinOptions{ContextSensitiveOptions{}}});6729}6730 6731TEST(TransferTest, ContextSensitiveSetBothTrueAndFalse) {6732 std::string Code = R"(6733 bool GiveBool();6734 void SetBool(bool &Var, bool Val) { Var = Val; }6735 6736 void target() {6737 bool Foo = GiveBool();6738 bool Bar = GiveBool();6739 SetBool(Foo, true);6740 SetBool(Bar, false);6741 // [[p]]6742 }6743 )";6744 runDataflow(6745 Code,6746 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6747 ASTContext &ASTCtx) {6748 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));6749 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");6750 auto &A = Env.arena();6751 6752 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");6753 ASSERT_THAT(FooDecl, NotNull());6754 6755 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");6756 ASSERT_THAT(BarDecl, NotNull());6757 6758 auto &FooVal = getFormula(*FooDecl, Env);6759 EXPECT_TRUE(Env.proves(FooVal));6760 EXPECT_FALSE(Env.proves(A.makeNot(FooVal)));6761 6762 auto &BarVal = getFormula(*BarDecl, Env);6763 EXPECT_FALSE(Env.proves(BarVal));6764 EXPECT_TRUE(Env.proves(A.makeNot(BarVal)));6765 },6766 {BuiltinOptions{ContextSensitiveOptions{}}});6767}6768 6769TEST(TransferTest, ContextSensitiveSetTwoLayersDepthOne) {6770 std::string Code = R"(6771 bool GiveBool();6772 void SetBool1(bool &Var) { Var = true; }6773 void SetBool2(bool &Var) { SetBool1(Var); }6774 6775 void target() {6776 bool Foo = GiveBool();6777 SetBool2(Foo);6778 // [[p]]6779 }6780 )";6781 runDataflow(6782 Code,6783 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6784 ASTContext &ASTCtx) {6785 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));6786 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");6787 6788 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");6789 ASSERT_THAT(FooDecl, NotNull());6790 6791 auto &FooVal = getFormula(*FooDecl, Env);6792 EXPECT_FALSE(Env.proves(FooVal));6793 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));6794 },6795 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/1}}});6796}6797 6798TEST(TransferTest, ContextSensitiveSetTwoLayersDepthTwo) {6799 std::string Code = R"(6800 bool GiveBool();6801 void SetBool1(bool &Var) { Var = true; }6802 void SetBool2(bool &Var) { SetBool1(Var); }6803 6804 void target() {6805 bool Foo = GiveBool();6806 SetBool2(Foo);6807 // [[p]]6808 }6809 )";6810 runDataflow(6811 Code,6812 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6813 ASTContext &ASTCtx) {6814 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));6815 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");6816 6817 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");6818 ASSERT_THAT(FooDecl, NotNull());6819 6820 auto &FooVal = getFormula(*FooDecl, Env);6821 EXPECT_TRUE(Env.proves(FooVal));6822 },6823 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}});6824}6825 6826TEST(TransferTest, ContextSensitiveSetThreeLayersDepthTwo) {6827 std::string Code = R"(6828 bool GiveBool();6829 void SetBool1(bool &Var) { Var = true; }6830 void SetBool2(bool &Var) { SetBool1(Var); }6831 void SetBool3(bool &Var) { SetBool2(Var); }6832 6833 void target() {6834 bool Foo = GiveBool();6835 SetBool3(Foo);6836 // [[p]]6837 }6838 )";6839 runDataflow(6840 Code,6841 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6842 ASTContext &ASTCtx) {6843 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));6844 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");6845 6846 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");6847 ASSERT_THAT(FooDecl, NotNull());6848 6849 auto &FooVal = getFormula(*FooDecl, Env);6850 EXPECT_FALSE(Env.proves(FooVal));6851 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));6852 },6853 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/2}}});6854}6855 6856TEST(TransferTest, ContextSensitiveSetThreeLayersDepthThree) {6857 std::string Code = R"(6858 bool GiveBool();6859 void SetBool1(bool &Var) { Var = true; }6860 void SetBool2(bool &Var) { SetBool1(Var); }6861 void SetBool3(bool &Var) { SetBool2(Var); }6862 6863 void target() {6864 bool Foo = GiveBool();6865 SetBool3(Foo);6866 // [[p]]6867 }6868 )";6869 runDataflow(6870 Code,6871 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6872 ASTContext &ASTCtx) {6873 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));6874 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");6875 6876 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");6877 ASSERT_THAT(FooDecl, NotNull());6878 6879 auto &FooVal = getFormula(*FooDecl, Env);6880 EXPECT_TRUE(Env.proves(FooVal));6881 },6882 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/3}}});6883}6884 6885TEST(TransferTest, ContextSensitiveMutualRecursion) {6886 std::string Code = R"(6887 bool Pong(bool X, bool Y);6888 6889 bool Ping(bool X, bool Y) {6890 if (X) {6891 return Y;6892 } else {6893 return Pong(!X, Y);6894 }6895 }6896 6897 bool Pong(bool X, bool Y) {6898 if (Y) {6899 return X;6900 } else {6901 return Ping(X, !Y);6902 }6903 }6904 6905 void target() {6906 bool Foo = Ping(false, false);6907 // [[p]]6908 }6909 )";6910 runDataflow(6911 Code,6912 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6913 ASTContext &ASTCtx) {6914 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));6915 // The analysis doesn't crash...6916 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");6917 6918 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");6919 ASSERT_THAT(FooDecl, NotNull());6920 6921 auto &FooVal = getFormula(*FooDecl, Env);6922 // ... but it also can't prove anything here.6923 EXPECT_FALSE(Env.proves(FooVal));6924 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));6925 },6926 {BuiltinOptions{ContextSensitiveOptions{/*.Depth=*/4}}});6927}6928 6929TEST(TransferTest, ContextSensitiveSetMultipleLines) {6930 std::string Code = R"(6931 void SetBools(bool &Var1, bool &Var2) {6932 Var1 = true;6933 Var2 = false;6934 }6935 6936 void target() {6937 bool Foo = false;6938 bool Bar = true;6939 SetBools(Foo, Bar);6940 // [[p]]6941 }6942 )";6943 runDataflow(6944 Code,6945 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6946 ASTContext &ASTCtx) {6947 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));6948 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");6949 6950 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");6951 ASSERT_THAT(FooDecl, NotNull());6952 6953 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");6954 ASSERT_THAT(BarDecl, NotNull());6955 6956 auto &FooVal = getFormula(*FooDecl, Env);6957 EXPECT_TRUE(Env.proves(FooVal));6958 EXPECT_FALSE(Env.proves(Env.arena().makeNot(FooVal)));6959 6960 auto &BarVal = getFormula(*BarDecl, Env);6961 EXPECT_FALSE(Env.proves(BarVal));6962 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal)));6963 },6964 {BuiltinOptions{ContextSensitiveOptions{}}});6965}6966 6967TEST(TransferTest, ContextSensitiveSetMultipleBlocks) {6968 std::string Code = R"(6969 void IfCond(bool Cond, bool &Then, bool &Else) {6970 if (Cond) {6971 Then = true;6972 } else {6973 Else = true;6974 }6975 }6976 6977 void target() {6978 bool Foo = false;6979 bool Bar = false;6980 bool Baz = false;6981 IfCond(Foo, Bar, Baz);6982 // [[p]]6983 }6984 )";6985 runDataflow(6986 Code,6987 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,6988 ASTContext &ASTCtx) {6989 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));6990 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");6991 6992 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");6993 ASSERT_THAT(BarDecl, NotNull());6994 6995 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");6996 ASSERT_THAT(BazDecl, NotNull());6997 6998 auto &BarVal = getFormula(*BarDecl, Env);6999 EXPECT_FALSE(Env.proves(BarVal));7000 EXPECT_TRUE(Env.proves(Env.arena().makeNot(BarVal)));7001 7002 auto &BazVal = getFormula(*BazDecl, Env);7003 EXPECT_TRUE(Env.proves(BazVal));7004 EXPECT_FALSE(Env.proves(Env.arena().makeNot(BazVal)));7005 },7006 {BuiltinOptions{ContextSensitiveOptions{}}});7007}7008 7009TEST(TransferTest, ContextSensitiveReturnVoid) {7010 std::string Code = R"(7011 void Noop() { return; }7012 7013 void target() {7014 Noop();7015 // [[p]]7016 }7017 )";7018 runDataflow(7019 Code,7020 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7021 ASTContext &ASTCtx) {7022 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));7023 // This just tests that the analysis doesn't crash.7024 },7025 {BuiltinOptions{ContextSensitiveOptions{}}});7026}7027 7028TEST(TransferTest, ContextSensitiveReturnTrue) {7029 std::string Code = R"(7030 bool GiveBool() { return true; }7031 7032 void target() {7033 bool Foo = GiveBool();7034 // [[p]]7035 }7036 )";7037 runDataflow(7038 Code,7039 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7040 ASTContext &ASTCtx) {7041 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));7042 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7043 7044 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");7045 ASSERT_THAT(FooDecl, NotNull());7046 7047 auto &FooVal = getFormula(*FooDecl, Env);7048 EXPECT_TRUE(Env.proves(FooVal));7049 },7050 {BuiltinOptions{ContextSensitiveOptions{}}});7051}7052 7053TEST(TransferTest, ContextSensitiveReturnFalse) {7054 std::string Code = R"(7055 bool GiveBool() { return false; }7056 7057 void target() {7058 bool Foo = GiveBool();7059 // [[p]]7060 }7061 )";7062 runDataflow(7063 Code,7064 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7065 ASTContext &ASTCtx) {7066 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));7067 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7068 7069 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");7070 ASSERT_THAT(FooDecl, NotNull());7071 7072 auto &FooVal = getFormula(*FooDecl, Env);7073 EXPECT_TRUE(Env.proves(Env.arena().makeNot(FooVal)));7074 },7075 {BuiltinOptions{ContextSensitiveOptions{}}});7076}7077 7078TEST(TransferTest, ContextSensitiveReturnArg) {7079 std::string Code = R"(7080 bool GiveBool();7081 bool GiveBack(bool Arg) { return Arg; }7082 7083 void target() {7084 bool Foo = GiveBool();7085 bool Bar = GiveBack(Foo);7086 bool Baz = Foo == Bar;7087 // [[p]]7088 }7089 )";7090 runDataflow(7091 Code,7092 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7093 ASTContext &ASTCtx) {7094 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));7095 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7096 7097 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");7098 ASSERT_THAT(BazDecl, NotNull());7099 7100 auto &BazVal = getFormula(*BazDecl, Env);7101 EXPECT_TRUE(Env.proves(BazVal));7102 },7103 {BuiltinOptions{ContextSensitiveOptions{}}});7104}7105 7106TEST(TransferTest, ContextSensitiveReturnInt) {7107 std::string Code = R"(7108 int identity(int x) { return x; }7109 7110 void target() {7111 int y = identity(42);7112 // [[p]]7113 }7114 )";7115 runDataflow(7116 Code,7117 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7118 ASTContext &ASTCtx) {7119 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));7120 // This just tests that the analysis doesn't crash.7121 },7122 {BuiltinOptions{ContextSensitiveOptions{}}});7123}7124 7125TEST(TransferTest, ContextSensitiveReturnRecord) {7126 std::string Code = R"(7127 struct S {7128 bool B;7129 };7130 7131 S makeS(bool BVal) { return {BVal}; }7132 7133 void target() {7134 S FalseS = makeS(false);7135 S TrueS = makeS(true);7136 // [[p]]7137 }7138 )";7139 runDataflow(7140 Code,7141 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7142 ASTContext &ASTCtx) {7143 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7144 7145 auto &FalseSLoc =7146 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "FalseS");7147 auto &TrueSLoc =7148 getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "TrueS");7149 7150 EXPECT_EQ(getFieldValue(&FalseSLoc, "B", ASTCtx, Env),7151 &Env.getBoolLiteralValue(false));7152 EXPECT_EQ(getFieldValue(&TrueSLoc, "B", ASTCtx, Env),7153 &Env.getBoolLiteralValue(true));7154 },7155 {BuiltinOptions{ContextSensitiveOptions{}}});7156}7157 7158TEST(TransferTest, ContextSensitiveReturnSelfReferentialRecord) {7159 std::string Code = R"(7160 struct S {7161 S() { self = this; }7162 S *self;7163 };7164 7165 S makeS() {7166 // RVO guarantees that this will be constructed directly into `MyS`.7167 return S();7168 }7169 7170 void target() {7171 S MyS = makeS();7172 // [[p]]7173 }7174 )";7175 runDataflow(7176 Code,7177 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7178 ASTContext &ASTCtx) {7179 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7180 7181 auto &MySLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "MyS");7182 7183 auto *SelfVal =7184 cast<PointerValue>(getFieldValue(&MySLoc, "self", ASTCtx, Env));7185 EXPECT_EQ(&SelfVal->getPointeeLoc(), &MySLoc);7186 },7187 {BuiltinOptions{ContextSensitiveOptions{}}});7188}7189 7190TEST(TransferTest, ContextSensitiveMethodLiteral) {7191 std::string Code = R"(7192 class MyClass {7193 public:7194 bool giveBool() { return true; }7195 };7196 7197 void target() {7198 MyClass MyObj;7199 bool Foo = MyObj.giveBool();7200 // [[p]]7201 }7202 )";7203 runDataflow(7204 Code,7205 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7206 ASTContext &ASTCtx) {7207 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));7208 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7209 7210 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");7211 ASSERT_THAT(FooDecl, NotNull());7212 7213 auto &FooVal = getFormula(*FooDecl, Env);7214 EXPECT_TRUE(Env.proves(FooVal));7215 },7216 {BuiltinOptions{ContextSensitiveOptions{}}});7217}7218 7219TEST(TransferTest, ContextSensitiveMethodGetter) {7220 std::string Code = R"(7221 class MyClass {7222 public:7223 bool getField() { return Field; }7224 7225 bool Field;7226 };7227 7228 void target() {7229 MyClass MyObj;7230 MyObj.Field = true;7231 bool Foo = MyObj.getField();7232 // [[p]]7233 }7234 )";7235 runDataflow(7236 Code,7237 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7238 ASTContext &ASTCtx) {7239 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));7240 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7241 7242 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");7243 ASSERT_THAT(FooDecl, NotNull());7244 7245 auto &FooVal = getFormula(*FooDecl, Env);7246 EXPECT_TRUE(Env.proves(FooVal));7247 },7248 {BuiltinOptions{ContextSensitiveOptions{}}});7249}7250 7251TEST(TransferTest, ContextSensitiveMethodSetter) {7252 std::string Code = R"(7253 class MyClass {7254 public:7255 void setField(bool Val) { Field = Val; }7256 7257 bool Field;7258 };7259 7260 void target() {7261 MyClass MyObj;7262 MyObj.setField(true);7263 bool Foo = MyObj.Field;7264 // [[p]]7265 }7266 )";7267 runDataflow(7268 Code,7269 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7270 ASTContext &ASTCtx) {7271 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));7272 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7273 7274 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");7275 ASSERT_THAT(FooDecl, NotNull());7276 7277 auto &FooVal = getFormula(*FooDecl, Env);7278 EXPECT_TRUE(Env.proves(FooVal));7279 },7280 {BuiltinOptions{ContextSensitiveOptions{}}});7281}7282 7283TEST(TransferTest, ContextSensitiveMethodGetterAndSetter) {7284 std::string Code = R"(7285 class MyClass {7286 public:7287 bool getField() { return Field; }7288 void setField(bool Val) { Field = Val; }7289 7290 private:7291 bool Field;7292 };7293 7294 void target() {7295 MyClass MyObj;7296 MyObj.setField(true);7297 bool Foo = MyObj.getField();7298 // [[p]]7299 }7300 )";7301 runDataflow(7302 Code,7303 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7304 ASTContext &ASTCtx) {7305 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));7306 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7307 7308 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");7309 ASSERT_THAT(FooDecl, NotNull());7310 7311 auto &FooVal = getFormula(*FooDecl, Env);7312 EXPECT_TRUE(Env.proves(FooVal));7313 },7314 {BuiltinOptions{ContextSensitiveOptions{}}});7315}7316 7317 7318TEST(TransferTest, ContextSensitiveMethodTwoLayersVoid) {7319 std::string Code = R"(7320 class MyClass {7321 public:7322 void Inner() { MyField = true; }7323 void Outer() { Inner(); }7324 7325 bool MyField;7326 };7327 7328 void target() {7329 MyClass MyObj;7330 MyObj.Outer();7331 bool Foo = MyObj.MyField;7332 // [[p]]7333 }7334 )";7335 runDataflow(7336 Code,7337 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7338 ASTContext &ASTCtx) {7339 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));7340 ;7341 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7342 7343 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");7344 ASSERT_THAT(FooDecl, NotNull());7345 7346 auto &FooVal = getFormula(*FooDecl, Env);7347 EXPECT_TRUE(Env.proves(FooVal));7348 },7349 {BuiltinOptions{ContextSensitiveOptions{}}});7350}7351 7352TEST(TransferTest, ContextSensitiveMethodTwoLayersReturn) {7353 std::string Code = R"(7354 class MyClass {7355 public:7356 bool Inner() { return MyField; }7357 bool Outer() { return Inner(); }7358 7359 bool MyField;7360 };7361 7362 void target() {7363 MyClass MyObj;7364 MyObj.MyField = true;7365 bool Foo = MyObj.Outer();7366 // [[p]]7367 }7368 )";7369 runDataflow(7370 Code,7371 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7372 ASTContext &ASTCtx) {7373 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));7374 ;7375 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7376 7377 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");7378 ASSERT_THAT(FooDecl, NotNull());7379 7380 auto &FooVal = getFormula(*FooDecl, Env);7381 EXPECT_TRUE(Env.proves(FooVal));7382 },7383 {BuiltinOptions{ContextSensitiveOptions{}}});7384}7385 7386TEST(TransferTest, ContextSensitiveConstructorBody) {7387 std::string Code = R"(7388 class MyClass {7389 public:7390 MyClass() { MyField = true; }7391 7392 bool MyField;7393 };7394 7395 void target() {7396 MyClass MyObj;7397 bool Foo = MyObj.MyField;7398 // [[p]]7399 }7400 )";7401 runDataflow(7402 Code,7403 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7404 ASTContext &ASTCtx) {7405 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));7406 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7407 7408 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");7409 ASSERT_THAT(FooDecl, NotNull());7410 7411 auto &FooVal = getFormula(*FooDecl, Env);7412 EXPECT_TRUE(Env.proves(FooVal));7413 },7414 {BuiltinOptions{ContextSensitiveOptions{}}});7415}7416 7417TEST(TransferTest, ContextSensitiveConstructorInitializer) {7418 std::string Code = R"(7419 class MyClass {7420 public:7421 MyClass() : MyField(true) {}7422 7423 bool MyField;7424 };7425 7426 void target() {7427 MyClass MyObj;7428 bool Foo = MyObj.MyField;7429 // [[p]]7430 }7431 )";7432 runDataflow(7433 Code,7434 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7435 ASTContext &ASTCtx) {7436 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));7437 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7438 7439 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");7440 ASSERT_THAT(FooDecl, NotNull());7441 7442 auto &FooVal = getFormula(*FooDecl, Env);7443 EXPECT_TRUE(Env.proves(FooVal));7444 },7445 {BuiltinOptions{ContextSensitiveOptions{}}});7446}7447 7448TEST(TransferTest, ContextSensitiveConstructorDefault) {7449 std::string Code = R"(7450 class MyClass {7451 public:7452 MyClass() = default;7453 7454 bool MyField = true;7455 };7456 7457 void target() {7458 MyClass MyObj;7459 bool Foo = MyObj.MyField;7460 // [[p]]7461 }7462 )";7463 runDataflow(7464 Code,7465 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7466 ASTContext &ASTCtx) {7467 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));7468 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7469 7470 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");7471 ASSERT_THAT(FooDecl, NotNull());7472 7473 auto &FooVal = getFormula(*FooDecl, Env);7474 EXPECT_TRUE(Env.proves(FooVal));7475 },7476 {BuiltinOptions{ContextSensitiveOptions{}}});7477}7478 7479TEST(TransferTest, ContextSensitiveSelfReferentialClass) {7480 // Test that the `this` pointer seen in the constructor has the same value7481 // as the address of the variable the object is constructed into.7482 std::string Code = R"(7483 class MyClass {7484 public:7485 MyClass() : Self(this) {}7486 MyClass *Self;7487 };7488 7489 void target() {7490 MyClass MyObj;7491 MyClass *SelfPtr = MyObj.Self;7492 // [[p]]7493 }7494 )";7495 runDataflow(7496 Code,7497 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7498 ASTContext &ASTCtx) {7499 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));7500 7501 const ValueDecl *MyObjDecl = findValueDecl(ASTCtx, "MyObj");7502 ASSERT_THAT(MyObjDecl, NotNull());7503 7504 const ValueDecl *SelfDecl = findValueDecl(ASTCtx, "SelfPtr");7505 ASSERT_THAT(SelfDecl, NotNull());7506 7507 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7508 auto &SelfVal = *cast<PointerValue>(Env.getValue(*SelfDecl));7509 EXPECT_EQ(Env.getStorageLocation(*MyObjDecl), &SelfVal.getPointeeLoc());7510 },7511 {BuiltinOptions{ContextSensitiveOptions{}}});7512}7513 7514TEST(TransferTest, UnnamedBitfieldInitializer) {7515 std::string Code = R"(7516 struct B {};7517 struct A {7518 unsigned a;7519 unsigned : 4;7520 unsigned c;7521 B b;7522 };7523 void target() {7524 A a = {};7525 A test = a;7526 (void)test.c;7527 }7528 )";7529 runDataflow(7530 Code,7531 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7532 ASTContext &ASTCtx) {7533 // This doesn't need a body because this test was crashing the framework7534 // before handling correctly Unnamed bitfields in `InitListExpr`.7535 });7536}7537 7538// Repro for a crash that used to occur with chained short-circuiting logical7539// operators.7540TEST(TransferTest, ChainedLogicalOps) {7541 std::string Code = R"(7542 bool target() {7543 bool b = true || false || false || false;7544 // [[p]]7545 return b;7546 }7547 )";7548 runDataflow(7549 Code,7550 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7551 ASTContext &ASTCtx) {7552 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7553 auto &B = getValueForDecl<BoolValue>(ASTCtx, Env, "b").formula();7554 EXPECT_TRUE(Env.proves(B));7555 });7556}7557 7558// Repro for a crash that used to occur when we call a `noreturn` function7559// within one of the operands of a `&&` or `||` operator.7560TEST(TransferTest, NoReturnFunctionInsideShortCircuitedBooleanOp) {7561 std::string Code = R"(7562 __attribute__((noreturn)) int doesnt_return();7563 bool some_condition();7564 void target(bool b1, bool b2) {7565 // Neither of these should crash. In addition, if we don't terminate the7566 // program, we know that the operators need to trigger the short-circuit7567 // logic, so `NoreturnOnRhsOfAnd` will be false and `NoreturnOnRhsOfOr`7568 // will be true.7569 bool NoreturnOnRhsOfAnd = b1 && doesnt_return() > 0;7570 bool NoreturnOnRhsOfOr = b2 || doesnt_return() > 0;7571 7572 // Calling a `noreturn` function on the LHS of an `&&` or `||` makes the7573 // entire expression unreachable. So we know that in both of the following7574 // cases, if `target()` terminates, the `else` branch was taken.7575 bool NoreturnOnLhsMakesAndUnreachable = false;7576 if (some_condition())7577 doesnt_return() > 0 && some_condition();7578 else7579 NoreturnOnLhsMakesAndUnreachable = true;7580 7581 bool NoreturnOnLhsMakesOrUnreachable = false;7582 if (some_condition())7583 doesnt_return() > 0 || some_condition();7584 else7585 NoreturnOnLhsMakesOrUnreachable = true;7586 7587 // [[p]]7588 }7589 )";7590 runDataflow(7591 Code,7592 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7593 ASTContext &ASTCtx) {7594 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));7595 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7596 auto &A = Env.arena();7597 7598 // Check that [[p]] is reachable with a non-false flow condition.7599 EXPECT_FALSE(Env.proves(A.makeLiteral(false)));7600 7601 auto &B1 = getValueForDecl<BoolValue>(ASTCtx, Env, "b1").formula();7602 EXPECT_TRUE(Env.proves(A.makeNot(B1)));7603 7604 auto &NoreturnOnRhsOfAnd =7605 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfAnd").formula();7606 EXPECT_TRUE(Env.proves(A.makeNot(NoreturnOnRhsOfAnd)));7607 7608 auto &B2 = getValueForDecl<BoolValue>(ASTCtx, Env, "b2").formula();7609 EXPECT_TRUE(Env.proves(B2));7610 7611 auto &NoreturnOnRhsOfOr =7612 getValueForDecl<BoolValue>(ASTCtx, Env, "NoreturnOnRhsOfOr")7613 .formula();7614 EXPECT_TRUE(Env.proves(NoreturnOnRhsOfOr));7615 7616 auto &NoreturnOnLhsMakesAndUnreachable = getValueForDecl<BoolValue>(7617 ASTCtx, Env, "NoreturnOnLhsMakesAndUnreachable").formula();7618 EXPECT_TRUE(Env.proves(NoreturnOnLhsMakesAndUnreachable));7619 7620 auto &NoreturnOnLhsMakesOrUnreachable = getValueForDecl<BoolValue>(7621 ASTCtx, Env, "NoreturnOnLhsMakesOrUnreachable").formula();7622 EXPECT_TRUE(Env.proves(NoreturnOnLhsMakesOrUnreachable));7623 });7624}7625 7626TEST(TransferTest, NewExpressions) {7627 std::string Code = R"(7628 void target() {7629 int *p = new int(42);7630 // [[after_new]]7631 }7632 )";7633 runDataflow(7634 Code,7635 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7636 ASTContext &ASTCtx) {7637 const Environment &Env =7638 getEnvironmentAtAnnotation(Results, "after_new");7639 7640 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p");7641 7642 EXPECT_THAT(Env.getValue(P.getPointeeLoc()), NotNull());7643 });7644}7645 7646TEST(TransferTest, NewExpressions_Structs) {7647 std::string Code = R"(7648 struct Inner {7649 int InnerField;7650 };7651 7652 struct Outer {7653 Inner OuterField;7654 };7655 7656 void target() {7657 Outer *p = new Outer;7658 // Access the fields to make sure the analysis actually generates children7659 // for them in the `RecordStorageLocation`.7660 p->OuterField.InnerField;7661 // [[after_new]]7662 }7663 )";7664 runDataflow(7665 Code,7666 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7667 ASTContext &ASTCtx) {7668 const Environment &Env =7669 getEnvironmentAtAnnotation(Results, "after_new");7670 7671 const ValueDecl *OuterField = findValueDecl(ASTCtx, "OuterField");7672 const ValueDecl *InnerField = findValueDecl(ASTCtx, "InnerField");7673 7674 auto &P = getValueForDecl<PointerValue>(ASTCtx, Env, "p");7675 7676 auto &OuterLoc = cast<RecordStorageLocation>(P.getPointeeLoc());7677 auto &OuterFieldLoc =7678 *cast<RecordStorageLocation>(OuterLoc.getChild(*OuterField));7679 auto &InnerFieldLoc = *OuterFieldLoc.getChild(*InnerField);7680 7681 EXPECT_THAT(Env.getValue(InnerFieldLoc), NotNull());7682 });7683}7684 7685TEST(TransferTest, FunctionToPointerDecayHasValue) {7686 std::string Code = R"(7687 struct A { static void static_member_func(); };7688 void target() {7689 // To check that we're treating function-to-pointer decay correctly,7690 // create two pointers, then verify they refer to the same storage7691 // location.7692 // We need to do the test this way because even if an initializer (in this7693 // case, the function-to-pointer decay) does not create a value, we still7694 // create a value for the variable.7695 void (*non_member_p1)() = target;7696 void (*non_member_p2)() = target;7697 7698 // Do the same thing but for a static member function.7699 void (*member_p1)() = A::static_member_func;7700 void (*member_p2)() = A::static_member_func;7701 // [[p]]7702 }7703 )";7704 runDataflow(7705 Code,7706 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7707 ASTContext &ASTCtx) {7708 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7709 7710 auto &NonMemberP1 =7711 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p1");7712 auto &NonMemberP2 =7713 getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p2");7714 EXPECT_EQ(&NonMemberP1.getPointeeLoc(), &NonMemberP2.getPointeeLoc());7715 7716 auto &MemberP1 =7717 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p1");7718 auto &MemberP2 =7719 getValueForDecl<PointerValue>(ASTCtx, Env, "member_p2");7720 EXPECT_EQ(&MemberP1.getPointeeLoc(), &MemberP2.getPointeeLoc());7721 });7722}7723 7724// Check that a builtin function is not associated with a value. (It's only7725// possible to call builtin functions directly, not take their address.)7726TEST(TransferTest, BuiltinFunctionModeled) {7727 std::string Code = R"(7728 void target() {7729 __builtin_expect(0, 0);7730 // [[p]]7731 }7732 )";7733 runDataflow(7734 Code,7735 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7736 ASTContext &ASTCtx) {7737 using ast_matchers::selectFirst;7738 using ast_matchers::match;7739 using ast_matchers::traverse;7740 using ast_matchers::implicitCastExpr;7741 using ast_matchers::hasCastKind;7742 7743 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7744 7745 auto *ImplicitCast = selectFirst<ImplicitCastExpr>(7746 "implicit_cast",7747 match(traverse(TK_AsIs,7748 implicitCastExpr(hasCastKind(CK_BuiltinFnToFnPtr))7749 .bind("implicit_cast")),7750 ASTCtx));7751 7752 ASSERT_THAT(ImplicitCast, NotNull());7753 EXPECT_THAT(Env.getValue(*ImplicitCast), IsNull());7754 });7755}7756 7757// Check that a callee of a member operator call is modeled as a `PointerValue`.7758// Member operator calls are unusual in that their callee is a pointer that7759// stems from a `FunctionToPointerDecay`. In calls to non-operator non-static7760// member functions, the callee is a `MemberExpr` (which does not have pointer7761// type).7762// We want to make sure that we produce a pointer value for the callee in this7763// specific scenario and that its storage location is durable (for convergence).7764TEST(TransferTest, MemberOperatorCallModelsPointerForCallee) {7765 std::string Code = R"(7766 struct S {7767 bool operator!=(S s);7768 };7769 void target() {7770 S s;7771 (void)(s != s);7772 (void)(s != s);7773 // [[p]]7774 }7775 )";7776 runDataflow(7777 Code,7778 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7779 ASTContext &ASTCtx) {7780 using ast_matchers::selectFirst;7781 using ast_matchers::match;7782 using ast_matchers::traverse;7783 using ast_matchers::cxxOperatorCallExpr;7784 7785 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7786 7787 auto Matches = match(7788 traverse(TK_AsIs, cxxOperatorCallExpr().bind("call")), ASTCtx);7789 7790 ASSERT_EQ(Matches.size(), 2UL);7791 7792 auto *Call1 = Matches[0].getNodeAs<CXXOperatorCallExpr>("call");7793 auto *Call2 = Matches[1].getNodeAs<CXXOperatorCallExpr>("call");7794 7795 ASSERT_THAT(Call1, NotNull());7796 ASSERT_THAT(Call2, NotNull());7797 7798 EXPECT_EQ(cast<ImplicitCastExpr>(Call1->getCallee())->getCastKind(),7799 CK_FunctionToPointerDecay);7800 EXPECT_EQ(cast<ImplicitCastExpr>(Call2->getCallee())->getCastKind(),7801 CK_FunctionToPointerDecay);7802 7803 auto *Ptr1 = cast<PointerValue>(Env.getValue(*Call1->getCallee()));7804 auto *Ptr2 = cast<PointerValue>(Env.getValue(*Call2->getCallee()));7805 7806 ASSERT_EQ(&Ptr1->getPointeeLoc(), &Ptr2->getPointeeLoc());7807 });7808}7809 7810// Check that fields of anonymous records are modeled.7811TEST(TransferTest, AnonymousStruct) {7812 std::string Code = R"(7813 struct S {7814 struct {7815 bool b;7816 };7817 };7818 void target() {7819 S s;7820 s.b = true;7821 // [[p]]7822 }7823 )";7824 runDataflow(7825 Code,7826 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7827 ASTContext &ASTCtx) {7828 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7829 const ValueDecl *SDecl = findValueDecl(ASTCtx, "s");7830 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b");7831 const IndirectFieldDecl *IndirectField =7832 findIndirectFieldDecl(ASTCtx, "b");7833 7834 auto *S = cast<RecordStorageLocation>(Env.getStorageLocation(*SDecl));7835 auto &AnonStruct = *cast<RecordStorageLocation>(7836 S->getChild(*cast<ValueDecl>(IndirectField->chain().front())));7837 7838 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env));7839 ASSERT_TRUE(Env.proves(B->formula()));7840 });7841}7842 7843TEST(TransferTest, AnonymousStructWithInitializer) {7844 std::string Code = R"(7845 struct target {7846 target() {7847 (void)0;7848 // [[p]]7849 }7850 struct {7851 bool b = true;7852 };7853 };7854 )";7855 runDataflow(7856 Code,7857 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7858 ASTContext &ASTCtx) {7859 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7860 const ValueDecl *BDecl = findValueDecl(ASTCtx, "b");7861 const IndirectFieldDecl *IndirectField =7862 findIndirectFieldDecl(ASTCtx, "b");7863 7864 auto *ThisLoc =7865 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation());7866 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild(7867 *cast<ValueDecl>(IndirectField->chain().front())));7868 7869 auto *B = cast<BoolValue>(getFieldValue(&AnonStruct, *BDecl, Env));7870 ASSERT_TRUE(Env.proves(B->formula()));7871 });7872}7873 7874TEST(TransferTest, AnonymousStructWithReferenceField) {7875 std::string Code = R"(7876 int global_i = 0;7877 struct target {7878 target() {7879 (void)0;7880 // [[p]]7881 }7882 struct {7883 int &i = global_i;7884 };7885 };7886 )";7887 runDataflow(7888 Code,7889 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7890 ASTContext &ASTCtx) {7891 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7892 const ValueDecl *GlobalIDecl = findValueDecl(ASTCtx, "global_i");7893 const ValueDecl *IDecl = findValueDecl(ASTCtx, "i");7894 const IndirectFieldDecl *IndirectField =7895 findIndirectFieldDecl(ASTCtx, "i");7896 7897 auto *ThisLoc =7898 cast<RecordStorageLocation>(Env.getThisPointeeStorageLocation());7899 auto &AnonStruct = *cast<RecordStorageLocation>(ThisLoc->getChild(7900 *cast<ValueDecl>(IndirectField->chain().front())));7901 7902 ASSERT_EQ(AnonStruct.getChild(*IDecl),7903 Env.getStorageLocation(*GlobalIDecl));7904 });7905}7906 7907TEST(TransferTest, EvaluateBlockWithUnreachablePreds) {7908 // This is a crash repro.7909 // `false` block may not have been processed when we try to evaluate the `||`7910 // after visiting `true`, because it is not necessary (and therefore the edge7911 // is marked unreachable). Trying to get the analysis state via7912 // `getEnvironment` for the subexpression still should not crash.7913 std::string Code = R"(7914 int target(int i) {7915 if ((i < 0 && true) || false) {7916 return 0;7917 }7918 return 0;7919 }7920 )";7921 runDataflow(7922 Code,7923 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7924 ASTContext &ASTCtx) {});7925}7926 7927TEST(TransferTest, LambdaCaptureByCopy) {7928 std::string Code = R"(7929 void target(int Foo, int Bar) {7930 [Foo]() {7931 (void)0;7932 // [[p]]7933 }();7934 }7935 )";7936 runDataflowOnLambda(7937 Code,7938 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7939 ASTContext &ASTCtx) {7940 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));7941 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7942 7943 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");7944 ASSERT_THAT(FooDecl, NotNull());7945 7946 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);7947 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));7948 7949 const Value *FooVal = Env.getValue(*FooLoc);7950 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));7951 7952 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");7953 ASSERT_THAT(BarDecl, NotNull());7954 7955 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);7956 EXPECT_THAT(BarLoc, IsNull());7957 });7958}7959 7960TEST(TransferTest, LambdaCaptureByReference) {7961 std::string Code = R"(7962 void target(int Foo, int Bar) {7963 [&Foo]() {7964 (void)0;7965 // [[p]]7966 }();7967 }7968 )";7969 runDataflowOnLambda(7970 Code,7971 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,7972 ASTContext &ASTCtx) {7973 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));7974 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");7975 7976 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");7977 ASSERT_THAT(FooDecl, NotNull());7978 7979 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);7980 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));7981 7982 const Value *FooVal = Env.getValue(*FooLoc);7983 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));7984 7985 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");7986 ASSERT_THAT(BarDecl, NotNull());7987 7988 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);7989 EXPECT_THAT(BarLoc, IsNull());7990 });7991}7992 7993TEST(TransferTest, LambdaCaptureWithInitializer) {7994 std::string Code = R"(7995 void target(int Bar) {7996 [Foo=Bar]() {7997 (void)0;7998 // [[p]]7999 }();8000 }8001 )";8002 runDataflowOnLambda(8003 Code,8004 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,8005 ASTContext &ASTCtx) {8006 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));8007 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");8008 8009 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");8010 ASSERT_THAT(FooDecl, NotNull());8011 8012 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);8013 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));8014 8015 const Value *FooVal = Env.getValue(*FooLoc);8016 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));8017 8018 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");8019 ASSERT_THAT(BarDecl, NotNull());8020 8021 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);8022 EXPECT_THAT(BarLoc, IsNull());8023 });8024}8025 8026TEST(TransferTest, LambdaCaptureByCopyImplicit) {8027 std::string Code = R"(8028 void target(int Foo, int Bar) {8029 [=]() {8030 Foo;8031 // [[p]]8032 }();8033 }8034 )";8035 runDataflowOnLambda(8036 Code,8037 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,8038 ASTContext &ASTCtx) {8039 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));8040 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");8041 8042 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");8043 ASSERT_THAT(FooDecl, NotNull());8044 8045 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);8046 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));8047 8048 const Value *FooVal = Env.getValue(*FooLoc);8049 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));8050 8051 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");8052 ASSERT_THAT(BarDecl, NotNull());8053 8054 // There is no storage location for `Bar` because it isn't used in the8055 // body of the lambda.8056 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);8057 EXPECT_THAT(BarLoc, IsNull());8058 });8059}8060 8061TEST(TransferTest, LambdaCaptureByReferenceImplicit) {8062 std::string Code = R"(8063 void target(int Foo, int Bar) {8064 [&]() {8065 Foo;8066 // [[p]]8067 }();8068 }8069 )";8070 runDataflowOnLambda(8071 Code,8072 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,8073 ASTContext &ASTCtx) {8074 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));8075 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");8076 8077 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");8078 ASSERT_THAT(FooDecl, NotNull());8079 8080 const StorageLocation *FooLoc = Env.getStorageLocation(*FooDecl);8081 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));8082 8083 const Value *FooVal = Env.getValue(*FooLoc);8084 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));8085 8086 const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");8087 ASSERT_THAT(BarDecl, NotNull());8088 8089 // There is no storage location for `Bar` because it isn't used in the8090 // body of the lambda.8091 const StorageLocation *BarLoc = Env.getStorageLocation(*BarDecl);8092 EXPECT_THAT(BarLoc, IsNull());8093 });8094}8095 8096TEST(TransferTest, LambdaCaptureThis) {8097 std::string Code = R"(8098 struct Bar {8099 int Foo;8100 8101 void target() {8102 [this]() {8103 Foo;8104 // [[p]]8105 }();8106 }8107 };8108 )";8109 runDataflowOnLambda(8110 Code,8111 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,8112 ASTContext &ASTCtx) {8113 ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));8114 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");8115 8116 const RecordStorageLocation *ThisPointeeLoc =8117 Env.getThisPointeeStorageLocation();8118 ASSERT_THAT(ThisPointeeLoc, NotNull());8119 8120 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");8121 ASSERT_THAT(FooDecl, NotNull());8122 8123 const StorageLocation *FooLoc = ThisPointeeLoc->getChild(*FooDecl);8124 ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));8125 8126 const Value *FooVal = Env.getValue(*FooLoc);8127 EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));8128 });8129}8130 8131// This test verifies correct modeling of a relational dependency that goes8132// through unmodeled functions (the simple `cond()` in this case).8133TEST(TransferTest, ConditionalRelation) {8134 std::string Code = R"(8135 bool cond();8136 void target() {8137 bool a = true;8138 bool b = true;8139 if (cond()) {8140 a = false;8141 if (cond()) {8142 b = false;8143 }8144 }8145 (void)0;8146 // [[p]]8147 }8148 )";8149 runDataflow(8150 Code,8151 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,8152 ASTContext &ASTCtx) {8153 const Environment &Env = getEnvironmentAtAnnotation(Results, "p");8154 auto &A = Env.arena();8155 auto &VarA = getValueForDecl<BoolValue>(ASTCtx, Env, "a").formula();8156 auto &VarB = getValueForDecl<BoolValue>(ASTCtx, Env, "b").formula();8157 8158 EXPECT_FALSE(Env.allows(A.makeAnd(VarA, A.makeNot(VarB))));8159 });8160}8161 8162// This is a crash repro.8163// We used to crash while transferring `S().i` because Clang contained a bug8164// causing the AST to be malformed.8165TEST(TransferTest, AnonymousUnionMemberExprInTemplate) {8166 using ast_matchers::functionDecl;8167 using ast_matchers::hasName;8168 using ast_matchers::unless;8169 8170 std::string Code = R"cc(8171 struct S {8172 struct {8173 int i;8174 };8175 };8176 8177 template <class>8178 void target() {8179 S().i;8180 }8181 8182 template void target<int>();8183 )cc";8184 auto Matcher = functionDecl(hasName("target"), unless(isTemplated()));8185 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(Code, Matcher),8186 llvm::Succeeded());8187}8188 8189} // namespace8190