brintos

brintos / llvm-project-archived public Read only

0
0
Text · 250.6 KiB · a6308d1 Raw
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