brintos

brintos / llvm-project-archived public Read only

0
0
Text · 46.7 KiB · f14cb43 Raw
1259 lines · cpp
1//===-- DataflowEnvironment.cpp ---------------------------------*- C++ -*-===//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//  This file defines an Environment class that is used by dataflow analyses10//  that run over Control-Flow Graphs (CFGs) to keep track of the state of the11//  program at given program points.12//13//===----------------------------------------------------------------------===//14 15#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"16#include "clang/AST/Decl.h"17#include "clang/AST/DeclCXX.h"18#include "clang/AST/ExprCXX.h"19#include "clang/AST/Stmt.h"20#include "clang/AST/Type.h"21#include "clang/Analysis/FlowSensitive/ASTOps.h"22#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"23#include "clang/Analysis/FlowSensitive/DataflowLattice.h"24#include "clang/Analysis/FlowSensitive/Value.h"25#include "llvm/ADT/DenseMap.h"26#include "llvm/ADT/DenseSet.h"27#include "llvm/ADT/MapVector.h"28#include "llvm/ADT/STLExtras.h"29#include "llvm/ADT/ScopeExit.h"30#include "llvm/Support/ErrorHandling.h"31#include <cassert>32#include <memory>33#include <utility>34 35#define DEBUG_TYPE "dataflow"36 37namespace clang {38namespace dataflow {39 40// FIXME: convert these to parameters of the analysis or environment. Current41// settings have been experimentaly validated, but only for a particular42// analysis.43static constexpr int MaxCompositeValueDepth = 3;44static constexpr int MaxCompositeValueSize = 1000;45 46/// Returns a map consisting of key-value entries that are present in both maps.47static llvm::DenseMap<const ValueDecl *, StorageLocation *> intersectDeclToLoc(48    const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc1,49    const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc2) {50  llvm::DenseMap<const ValueDecl *, StorageLocation *> Result;51  for (auto &Entry : DeclToLoc1) {52    auto It = DeclToLoc2.find(Entry.first);53    if (It != DeclToLoc2.end() && Entry.second == It->second)54      Result.insert({Entry.first, Entry.second});55  }56  return Result;57}58 59// Performs a join on either `ExprToLoc` or `ExprToVal`.60// The maps must be consistent in the sense that any entries for the same61// expression must map to the same location / value. This is the case if we are62// performing a join for control flow within a full-expression (which is the63// only case when this function should be used).64template <typename MapT>65static MapT joinExprMaps(const MapT &Map1, const MapT &Map2) {66  MapT Result = Map1;67 68  for (const auto &Entry : Map2) {69    [[maybe_unused]] auto [It, Inserted] = Result.insert(Entry);70    // If there was an existing entry, its value should be the same as for the71    // entry we were trying to insert.72    assert(It->second == Entry.second);73  }74 75  return Result;76}77 78// Whether to consider equivalent two values with an unknown relation.79//80// FIXME: this function is a hack enabling unsoundness to support81// convergence. Once we have widening support for the reference/pointer and82// struct built-in models, this should be unconditionally `false` (and inlined83// as such at its call sites).84static bool equateUnknownValues(Value::Kind K) {85  switch (K) {86  case Value::Kind::Integer:87  case Value::Kind::Pointer:88    return true;89  default:90    return false;91  }92}93 94static bool compareDistinctValues(QualType Type, Value &Val1,95                                  const Environment &Env1, Value &Val2,96                                  const Environment &Env2,97                                  Environment::ValueModel &Model) {98  // Note: Potentially costly, but, for booleans, we could check whether both99  // can be proven equivalent in their respective environments.100 101  // FIXME: move the reference/pointers logic from `areEquivalentValues` to here102  // and implement separate, join/widen specific handling for103  // reference/pointers.104  switch (Model.compare(Type, Val1, Env1, Val2, Env2)) {105  case ComparisonResult::Same:106    return true;107  case ComparisonResult::Different:108    return false;109  case ComparisonResult::Unknown:110    return equateUnknownValues(Val1.getKind());111  }112  llvm_unreachable("All cases covered in switch");113}114 115/// Attempts to join distinct values `Val1` and `Val2` in `Env1` and `Env2`,116/// respectively, of the same type `Type`. Joining generally produces a single117/// value that (soundly) approximates the two inputs, although the actual118/// meaning depends on `Model`.119static Value *joinDistinctValues(QualType Type, Value &Val1,120                                 const Environment &Env1, Value &Val2,121                                 const Environment &Env2,122                                 Environment &JoinedEnv,123                                 Environment::ValueModel &Model) {124  // Join distinct boolean values preserving information about the constraints125  // in the respective path conditions.126  if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) {127    // FIXME: Checking both values should be unnecessary, since they should have128    // a consistent shape.  However, right now we can end up with BoolValue's in129    // integer-typed variables due to our incorrect handling of130    // boolean-to-integer casts (we just propagate the BoolValue to the result131    // of the cast). So, a join can encounter an integer in one branch but a132    // bool in the other.133    // For example:134    // ```135    // std::optional<bool> o;136    // int x;137    // if (o.has_value())138    //   x = o.value();139    // ```140    auto &Expr1 = cast<BoolValue>(Val1).formula();141    auto &Expr2 = cast<BoolValue>(Val2).formula();142    auto &A = JoinedEnv.arena();143    auto &JoinedVal = A.makeAtomRef(A.makeAtom());144    JoinedEnv.assume(145        A.makeOr(A.makeAnd(A.makeAtomRef(Env1.getFlowConditionToken()),146                           A.makeEquals(JoinedVal, Expr1)),147                 A.makeAnd(A.makeAtomRef(Env2.getFlowConditionToken()),148                           A.makeEquals(JoinedVal, Expr2))));149    return &A.makeBoolValue(JoinedVal);150  }151 152  Value *JoinedVal = JoinedEnv.createValue(Type);153  if (JoinedVal)154    Model.join(Type, Val1, Env1, Val2, Env2, *JoinedVal, JoinedEnv);155 156  return JoinedVal;157}158 159static WidenResult widenDistinctValues(QualType Type, Value &Prev,160                                       const Environment &PrevEnv,161                                       Value &Current, Environment &CurrentEnv,162                                       Environment::ValueModel &Model) {163  // Boolean-model widening.164  if (isa<BoolValue>(Prev) && isa<BoolValue>(Current)) {165    // FIXME: Checking both values should be unnecessary, but we can currently166    // end up with `BoolValue`s in integer-typed variables. See comment in167    // `joinDistinctValues()` for details.168    auto &PrevBool = cast<BoolValue>(Prev);169    auto &CurBool = cast<BoolValue>(Current);170 171    if (isa<TopBoolValue>(Prev))172      // Safe to return `Prev` here, because Top is never dependent on the173      // environment.174      return {&Prev, LatticeEffect::Unchanged};175 176    // We may need to widen to Top, but before we do so, check whether both177    // values are implied to be either true or false in the current environment.178    // In that case, we can simply return a literal instead.179    bool TruePrev = PrevEnv.proves(PrevBool.formula());180    bool TrueCur = CurrentEnv.proves(CurBool.formula());181    if (TruePrev && TrueCur)182      return {&CurrentEnv.getBoolLiteralValue(true), LatticeEffect::Unchanged};183    if (!TruePrev && !TrueCur &&184        PrevEnv.proves(PrevEnv.arena().makeNot(PrevBool.formula())) &&185        CurrentEnv.proves(CurrentEnv.arena().makeNot(CurBool.formula())))186      return {&CurrentEnv.getBoolLiteralValue(false), LatticeEffect::Unchanged};187 188    return {&CurrentEnv.makeTopBoolValue(), LatticeEffect::Changed};189  }190 191  // FIXME: Add other built-in model widening.192 193  // Custom-model widening.194  if (auto Result = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv))195    return *Result;196 197  return {&Current, equateUnknownValues(Prev.getKind())198                        ? LatticeEffect::Unchanged199                        : LatticeEffect::Changed};200}201 202// Returns whether the values in `Map1` and `Map2` compare equal for those203// keys that `Map1` and `Map2` have in common.204template <typename Key>205static bool compareKeyToValueMaps(const llvm::MapVector<Key, Value *> &Map1,206                                  const llvm::MapVector<Key, Value *> &Map2,207                                  const Environment &Env1,208                                  const Environment &Env2,209                                  Environment::ValueModel &Model) {210  for (auto &Entry : Map1) {211    Key K = Entry.first;212    assert(K != nullptr);213 214    Value *Val = Entry.second;215    assert(Val != nullptr);216 217    auto It = Map2.find(K);218    if (It == Map2.end())219      continue;220    assert(It->second != nullptr);221 222    if (!areEquivalentValues(*Val, *It->second) &&223        !compareDistinctValues(K->getType(), *Val, Env1, *It->second, Env2,224                               Model))225      return false;226  }227 228  return true;229}230 231// Perform a join on two `LocToVal` maps.232static llvm::MapVector<const StorageLocation *, Value *>233joinLocToVal(const llvm::MapVector<const StorageLocation *, Value *> &LocToVal,234             const llvm::MapVector<const StorageLocation *, Value *> &LocToVal2,235             const Environment &Env1, const Environment &Env2,236             Environment &JoinedEnv, Environment::ValueModel &Model) {237  llvm::MapVector<const StorageLocation *, Value *> Result;238  for (auto &Entry : LocToVal) {239    const StorageLocation *Loc = Entry.first;240    assert(Loc != nullptr);241 242    Value *Val = Entry.second;243    assert(Val != nullptr);244 245    auto It = LocToVal2.find(Loc);246    if (It == LocToVal2.end())247      continue;248    assert(It->second != nullptr);249 250    if (Value *JoinedVal = Environment::joinValues(251            Loc->getType(), Val, Env1, It->second, Env2, JoinedEnv, Model)) {252      Result.insert({Loc, JoinedVal});253    }254  }255 256  return Result;257}258 259// Perform widening on either `LocToVal` or `ExprToVal`. `Key` must be either260// `const StorageLocation *` or `const Expr *`.261template <typename Key>262static llvm::MapVector<Key, Value *>263widenKeyToValueMap(const llvm::MapVector<Key, Value *> &CurMap,264                   const llvm::MapVector<Key, Value *> &PrevMap,265                   Environment &CurEnv, const Environment &PrevEnv,266                   Environment::ValueModel &Model, LatticeEffect &Effect) {267  llvm::MapVector<Key, Value *> WidenedMap;268  for (auto &Entry : CurMap) {269    Key K = Entry.first;270    assert(K != nullptr);271 272    Value *Val = Entry.second;273    assert(Val != nullptr);274 275    auto PrevIt = PrevMap.find(K);276    if (PrevIt == PrevMap.end())277      continue;278    assert(PrevIt->second != nullptr);279 280    if (areEquivalentValues(*Val, *PrevIt->second)) {281      WidenedMap.insert({K, Val});282      continue;283    }284 285    auto [WidenedVal, ValEffect] = widenDistinctValues(286        K->getType(), *PrevIt->second, PrevEnv, *Val, CurEnv, Model);287    WidenedMap.insert({K, WidenedVal});288    if (ValEffect == LatticeEffect::Changed)289      Effect = LatticeEffect::Changed;290  }291 292  return WidenedMap;293}294 295namespace {296 297// Visitor that builds a map from record prvalues to result objects.298// For each result object that it encounters, it propagates the storage location299// of the result object to all record prvalues that can initialize it.300class ResultObjectVisitor : public AnalysisASTVisitor {301public:302  // `ResultObjectMap` will be filled with a map from record prvalues to result303  // object. If this visitor will traverse a function that returns a record by304  // value, `LocForRecordReturnVal` is the location to which this record should305  // be written; otherwise, it is null.306  explicit ResultObjectVisitor(307      llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap,308      RecordStorageLocation *LocForRecordReturnVal,309      DataflowAnalysisContext &DACtx)310      : ResultObjectMap(ResultObjectMap),311        LocForRecordReturnVal(LocForRecordReturnVal), DACtx(DACtx) {}312 313  // Traverse all member and base initializers of `Ctor`. This function is not314  // called by `RecursiveASTVisitor`; it should be called manually if we are315  // analyzing a constructor. `ThisPointeeLoc` is the storage location that316  // `this` points to.317  void traverseConstructorInits(const CXXConstructorDecl *Ctor,318                                RecordStorageLocation *ThisPointeeLoc) {319    assert(ThisPointeeLoc != nullptr);320    for (const CXXCtorInitializer *Init : Ctor->inits()) {321      Expr *InitExpr = Init->getInit();322      if (FieldDecl *Field = Init->getMember();323          Field != nullptr && Field->getType()->isRecordType()) {324        PropagateResultObject(InitExpr, cast<RecordStorageLocation>(325                                            ThisPointeeLoc->getChild(*Field)));326      } else if (Init->getBaseClass()) {327        PropagateResultObject(InitExpr, ThisPointeeLoc);328      }329 330      // Ensure that any result objects within `InitExpr` (e.g. temporaries)331      // are also propagated to the prvalues that initialize them.332      TraverseStmt(InitExpr);333 334      // If this is a `CXXDefaultInitExpr`, also propagate any result objects335      // within the default expression.336      if (auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(InitExpr))337        TraverseStmt(DefaultInit->getExpr());338    }339  }340 341  bool VisitVarDecl(VarDecl *VD) override {342    if (VD->getType()->isRecordType() && VD->hasInit())343      PropagateResultObject(344          VD->getInit(),345          &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*VD)));346    return true;347  }348 349  bool VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE) override {350    if (MTE->getType()->isRecordType())351      PropagateResultObject(352          MTE->getSubExpr(),353          &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*MTE)));354    return true;355  }356 357  bool VisitReturnStmt(ReturnStmt *Return) override {358    Expr *RetValue = Return->getRetValue();359    if (RetValue != nullptr && RetValue->getType()->isRecordType() &&360        RetValue->isPRValue())361      PropagateResultObject(RetValue, LocForRecordReturnVal);362    return true;363  }364 365  bool VisitExpr(Expr *E) override {366    // Clang's AST can have record-type prvalues without a result object -- for367    // example as full-expressions contained in a compound statement or as368    // arguments of call expressions. We notice this if we get here and a369    // storage location has not yet been associated with `E`. In this case,370    // treat this as if it was a `MaterializeTemporaryExpr`.371    if (E->isPRValue() && E->getType()->isRecordType() &&372        !ResultObjectMap.contains(E))373      PropagateResultObject(374          E, &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*E)));375    return true;376  }377 378  void379  PropagateResultObjectToRecordInitList(const RecordInitListHelper &InitList,380                                        RecordStorageLocation *Loc) {381    for (auto [Base, Init] : InitList.base_inits()) {382      assert(Base->getType().getCanonicalType() ==383             Init->getType().getCanonicalType());384 385      // Storage location for the base class is the same as that of the386      // derived class because we "flatten" the object hierarchy and put all387      // fields in `RecordStorageLocation` of the derived class.388      PropagateResultObject(Init, Loc);389    }390 391    for (auto [Field, Init] : InitList.field_inits()) {392      // Fields of non-record type are handled in393      // `TransferVisitor::VisitInitListExpr()`.394      if (Field->getType()->isRecordType())395        PropagateResultObject(396            Init, cast<RecordStorageLocation>(Loc->getChild(*Field)));397    }398  }399 400  // Assigns `Loc` as the result object location of `E`, then propagates the401  // location to all lower-level prvalues that initialize the same object as402  // `E` (or one of its base classes or member variables).403  void PropagateResultObject(Expr *E, RecordStorageLocation *Loc) {404    if (!E->isPRValue() || !E->getType()->isRecordType()) {405      assert(false);406      // Ensure we don't propagate the result object if we hit this in a407      // release build.408      return;409    }410 411    ResultObjectMap[E] = Loc;412 413    // The following AST node kinds are "original initializers": They are the414    // lowest-level AST node that initializes a given object, and nothing415    // below them can initialize the same object (or part of it).416    if (isa<CXXConstructExpr>(E) || isa<CallExpr>(E) || isa<LambdaExpr>(E) ||417        isa<CXXDefaultArgExpr>(E) || isa<CXXStdInitializerListExpr>(E) ||418        isa<AtomicExpr>(E) || isa<CXXInheritedCtorInitExpr>(E) ||419        // We treat `BuiltinBitCastExpr` as an "original initializer" too as420        // it may not even be casting from a record type -- and even if it is,421        // the two objects are in general of unrelated type.422        isa<BuiltinBitCastExpr>(E)) {423      return;424    }425    if (auto *Op = dyn_cast<BinaryOperator>(E);426        Op && Op->getOpcode() == BO_Cmp) {427      // Builtin `<=>` returns a `std::strong_ordering` object.428      return;429    }430 431    if (auto *InitList = dyn_cast<InitListExpr>(E)) {432      if (!InitList->isSemanticForm())433        return;434      if (InitList->isTransparent()) {435        PropagateResultObject(InitList->getInit(0), Loc);436        return;437      }438 439      PropagateResultObjectToRecordInitList(RecordInitListHelper(InitList),440                                            Loc);441      return;442    }443 444    if (auto *ParenInitList = dyn_cast<CXXParenListInitExpr>(E)) {445      PropagateResultObjectToRecordInitList(RecordInitListHelper(ParenInitList),446                                            Loc);447      return;448    }449 450    if (auto *Op = dyn_cast<BinaryOperator>(E); Op && Op->isCommaOp()) {451      PropagateResultObject(Op->getRHS(), Loc);452      return;453    }454 455    if (auto *Cond = dyn_cast<AbstractConditionalOperator>(E)) {456      PropagateResultObject(Cond->getTrueExpr(), Loc);457      PropagateResultObject(Cond->getFalseExpr(), Loc);458      return;459    }460 461    if (auto *SE = dyn_cast<StmtExpr>(E)) {462      PropagateResultObject(cast<Expr>(SE->getSubStmt()->body_back()), Loc);463      return;464    }465 466    if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(E)) {467      PropagateResultObject(DIE->getExpr(), Loc);468      return;469    }470 471    // All other expression nodes that propagate a record prvalue should have472    // exactly one child.473    SmallVector<Stmt *, 1> Children(E->child_begin(), E->child_end());474    LLVM_DEBUG({475      if (Children.size() != 1)476        E->dump();477    });478    assert(Children.size() == 1);479    for (Stmt *S : Children)480      PropagateResultObject(cast<Expr>(S), Loc);481  }482 483private:484  llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap;485  RecordStorageLocation *LocForRecordReturnVal;486  DataflowAnalysisContext &DACtx;487};488 489} // namespace490 491void Environment::initialize() {492  if (InitialTargetStmt == nullptr)493    return;494 495  if (InitialTargetFunc == nullptr) {496    initFieldsGlobalsAndFuncs(getReferencedDecls(*InitialTargetStmt));497    ResultObjectMap =498        std::make_shared<PrValueToResultObject>(buildResultObjectMap(499            DACtx, InitialTargetStmt, getThisPointeeStorageLocation(),500            /*LocForRecordReturnValue=*/nullptr));501    return;502  }503 504  initFieldsGlobalsAndFuncs(getReferencedDecls(*InitialTargetFunc));505 506  for (const auto *ParamDecl : InitialTargetFunc->parameters()) {507    assert(ParamDecl != nullptr);508    setStorageLocation(*ParamDecl, createObject(*ParamDecl, nullptr));509  }510 511  if (InitialTargetFunc->getReturnType()->isRecordType())512    LocForRecordReturnVal = &cast<RecordStorageLocation>(513        createStorageLocation(InitialTargetFunc->getReturnType()));514 515  if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(InitialTargetFunc)) {516    auto *Parent = MethodDecl->getParent();517    assert(Parent != nullptr);518 519    if (Parent->isLambda()) {520      for (const auto &Capture : Parent->captures()) {521        if (Capture.capturesVariable()) {522          const auto *VarDecl = Capture.getCapturedVar();523          assert(VarDecl != nullptr);524          setStorageLocation(*VarDecl, createObject(*VarDecl, nullptr));525        } else if (Capture.capturesThis()) {526          if (auto *Ancestor = InitialTargetFunc->getNonClosureAncestor()) {527            const auto *SurroundingMethodDecl = cast<CXXMethodDecl>(Ancestor);528            QualType ThisPointeeType =529                SurroundingMethodDecl->getFunctionObjectParameterType();530            setThisPointeeStorageLocation(531                cast<RecordStorageLocation>(createObject(ThisPointeeType)));532          } else if (auto *FieldBeingInitialized =533                         dyn_cast<FieldDecl>(Parent->getLambdaContextDecl())) {534            // This is in a field initializer, rather than a method.535            const RecordDecl *RD = FieldBeingInitialized->getParent();536            const ASTContext &Ctx = RD->getASTContext();537            CanQualType T = Ctx.getCanonicalTagType(RD);538            setThisPointeeStorageLocation(539                cast<RecordStorageLocation>(createObject(T)));540          } else {541            assert(false && "Unexpected this-capturing lambda context.");542          }543        }544      }545    } else if (MethodDecl->isImplicitObjectMemberFunction()) {546      QualType ThisPointeeType = MethodDecl->getFunctionObjectParameterType();547      auto &ThisLoc =548          cast<RecordStorageLocation>(createStorageLocation(ThisPointeeType));549      setThisPointeeStorageLocation(ThisLoc);550      // Initialize fields of `*this` with values, but only if we're not551      // analyzing a constructor; after all, it's the constructor's job to do552      // this (and we want to be able to test that).553      if (!isa<CXXConstructorDecl>(MethodDecl))554        initializeFieldsWithValues(ThisLoc);555    }556  }557 558  // We do this below the handling of `CXXMethodDecl` above so that we can559  // be sure that the storage location for `this` has been set.560  ResultObjectMap =561      std::make_shared<PrValueToResultObject>(buildResultObjectMap(562          DACtx, InitialTargetFunc, getThisPointeeStorageLocation(),563          LocForRecordReturnVal));564}565 566// FIXME: Add support for resetting globals after function calls to enable the567// implementation of sound analyses.568 569void Environment::initFieldsGlobalsAndFuncs(const ReferencedDecls &Referenced) {570  // These have to be added before the lines that follow to ensure that571  // `create*` work correctly for structs.572  DACtx->addModeledFields(Referenced.Fields);573 574  for (const VarDecl *D : Referenced.Globals) {575    if (getStorageLocation(*D) != nullptr)576      continue;577 578    // We don't run transfer functions on the initializers of global variables,579    // so they won't be associated with a value or storage location. We580    // therefore intentionally don't pass an initializer to `createObject()`; in581    // particular, this ensures that `createObject()` will initialize the fields582    // of record-type variables with values.583    setStorageLocation(*D, createObject(*D, nullptr));584  }585 586  for (const FunctionDecl *FD : Referenced.Functions) {587    if (getStorageLocation(*FD) != nullptr)588      continue;589    auto &Loc = createStorageLocation(*FD);590    setStorageLocation(*FD, Loc);591  }592}593 594Environment Environment::fork() const {595  Environment Copy(*this);596  Copy.FlowConditionToken = DACtx->forkFlowCondition(FlowConditionToken);597  return Copy;598}599 600bool Environment::canDescend(unsigned MaxDepth,601                             const FunctionDecl *Callee) const {602  return CallStack.size() < MaxDepth && !llvm::is_contained(CallStack, Callee);603}604 605Environment Environment::pushCall(const CallExpr *Call) const {606  Environment Env(*this);607 608  if (const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(Call)) {609    if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) {610      if (!isa<CXXThisExpr>(Arg))611        Env.ThisPointeeLoc =612            cast<RecordStorageLocation>(getStorageLocation(*Arg));613      // Otherwise (when the argument is `this`), retain the current614      // environment's `ThisPointeeLoc`.615    }616  }617 618  if (Call->getType()->isRecordType() && Call->isPRValue())619    Env.LocForRecordReturnVal = &Env.getResultObjectLocation(*Call);620 621  Env.pushCallInternal(Call->getDirectCallee(),622                       llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));623 624  return Env;625}626 627Environment Environment::pushCall(const CXXConstructExpr *Call) const {628  Environment Env(*this);629 630  Env.ThisPointeeLoc = &Env.getResultObjectLocation(*Call);631  Env.LocForRecordReturnVal = &Env.getResultObjectLocation(*Call);632 633  Env.pushCallInternal(Call->getConstructor(),634                       llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));635 636  return Env;637}638 639void Environment::pushCallInternal(const FunctionDecl *FuncDecl,640                                   ArrayRef<const Expr *> Args) {641  // Canonicalize to the definition of the function. This ensures that we're642  // putting arguments into the same `ParamVarDecl`s` that the callee will later643  // be retrieving them from.644  assert(FuncDecl->getDefinition() != nullptr);645  FuncDecl = FuncDecl->getDefinition();646 647  CallStack.push_back(FuncDecl);648 649  initFieldsGlobalsAndFuncs(getReferencedDecls(*FuncDecl));650 651  const auto *ParamIt = FuncDecl->param_begin();652 653  // FIXME: Parameters don't always map to arguments 1:1; examples include654  // overloaded operators implemented as member functions, and parameter packs.655  for (unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) {656    assert(ParamIt != FuncDecl->param_end());657    const VarDecl *Param = *ParamIt;658    setStorageLocation(*Param, createObject(*Param, Args[ArgIndex]));659  }660 661  ResultObjectMap = std::make_shared<PrValueToResultObject>(662      buildResultObjectMap(DACtx, FuncDecl, getThisPointeeStorageLocation(),663                           LocForRecordReturnVal));664}665 666void Environment::popCall(const CallExpr *Call, const Environment &CalleeEnv) {667  // We ignore some entries of `CalleeEnv`:668  // - `DACtx` because is already the same in both669  // - We don't want the callee's `DeclCtx`, `ReturnVal`, `ReturnLoc` or670  //   `ThisPointeeLoc` because they don't apply to us.671  // - `DeclToLoc`, `ExprToLoc`, and `ExprToVal` capture information from the672  //   callee's local scope, so when popping that scope, we do not propagate673  //   the maps.674  this->LocToVal = std::move(CalleeEnv.LocToVal);675  this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);676 677  if (Call->isGLValue()) {678    if (CalleeEnv.ReturnLoc != nullptr)679      setStorageLocation(*Call, *CalleeEnv.ReturnLoc);680  } else if (!Call->getType()->isVoidType()) {681    if (CalleeEnv.ReturnVal != nullptr)682      setValue(*Call, *CalleeEnv.ReturnVal);683  }684}685 686void Environment::popCall(const CXXConstructExpr *Call,687                          const Environment &CalleeEnv) {688  // See also comment in `popCall(const CallExpr *, const Environment &)` above.689  this->LocToVal = std::move(CalleeEnv.LocToVal);690  this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);691}692 693bool Environment::equivalentTo(const Environment &Other,694                               Environment::ValueModel &Model) const {695  assert(DACtx == Other.DACtx);696 697  if (ReturnVal != Other.ReturnVal)698    return false;699 700  if (ReturnLoc != Other.ReturnLoc)701    return false;702 703  if (LocForRecordReturnVal != Other.LocForRecordReturnVal)704    return false;705 706  if (ThisPointeeLoc != Other.ThisPointeeLoc)707    return false;708 709  if (DeclToLoc != Other.DeclToLoc)710    return false;711 712  if (ExprToLoc != Other.ExprToLoc)713    return false;714 715  if (!compareKeyToValueMaps(ExprToVal, Other.ExprToVal, *this, Other, Model))716    return false;717 718  if (!compareKeyToValueMaps(LocToVal, Other.LocToVal, *this, Other, Model))719    return false;720 721  return true;722}723 724LatticeEffect Environment::widen(const Environment &PrevEnv,725                                 Environment::ValueModel &Model) {726  assert(DACtx == PrevEnv.DACtx);727  assert(ReturnVal == PrevEnv.ReturnVal);728  assert(ReturnLoc == PrevEnv.ReturnLoc);729  assert(LocForRecordReturnVal == PrevEnv.LocForRecordReturnVal);730  assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc);731  assert(CallStack == PrevEnv.CallStack);732  assert(ResultObjectMap == PrevEnv.ResultObjectMap);733  assert(InitialTargetFunc == PrevEnv.InitialTargetFunc);734  assert(InitialTargetStmt == PrevEnv.InitialTargetStmt);735 736  auto Effect = LatticeEffect::Unchanged;737 738  // By the API, `PrevEnv` is a previous version of the environment for the same739  // block, so we have some guarantees about its shape. In particular, it will740  // be the result of a join or widen operation on previous values for this741  // block. For `DeclToLoc`, `ExprToVal`, and `ExprToLoc`, join guarantees that742  // these maps are subsets of the maps in `PrevEnv`. So, as long as we maintain743  // this property here, we don't need change their current values to widen.744  assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size());745  assert(ExprToVal.size() <= PrevEnv.ExprToVal.size());746  assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size());747 748  ExprToVal = widenKeyToValueMap(ExprToVal, PrevEnv.ExprToVal, *this, PrevEnv,749                                 Model, Effect);750 751  LocToVal = widenKeyToValueMap(LocToVal, PrevEnv.LocToVal, *this, PrevEnv,752                                Model, Effect);753  if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() ||754      ExprToLoc.size() != PrevEnv.ExprToLoc.size() ||755      ExprToVal.size() != PrevEnv.ExprToVal.size() ||756      LocToVal.size() != PrevEnv.LocToVal.size())757    Effect = LatticeEffect::Changed;758 759  return Effect;760}761 762Environment Environment::join(const Environment &EnvA, const Environment &EnvB,763                              Environment::ValueModel &Model,764                              ExprJoinBehavior ExprBehavior) {765  assert(EnvA.DACtx == EnvB.DACtx);766  assert(EnvA.LocForRecordReturnVal == EnvB.LocForRecordReturnVal);767  assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc);768  assert(EnvA.CallStack == EnvB.CallStack);769  assert(EnvA.ResultObjectMap == EnvB.ResultObjectMap);770  assert(EnvA.InitialTargetFunc == EnvB.InitialTargetFunc);771  assert(EnvA.InitialTargetStmt == EnvB.InitialTargetStmt);772 773  Environment JoinedEnv(*EnvA.DACtx);774 775  JoinedEnv.CallStack = EnvA.CallStack;776  JoinedEnv.ResultObjectMap = EnvA.ResultObjectMap;777  JoinedEnv.LocForRecordReturnVal = EnvA.LocForRecordReturnVal;778  JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc;779  JoinedEnv.InitialTargetFunc = EnvA.InitialTargetFunc;780  JoinedEnv.InitialTargetStmt = EnvA.InitialTargetStmt;781 782  const FunctionDecl *Func = EnvA.getCurrentFunc();783  if (!Func) {784    JoinedEnv.ReturnVal = nullptr;785  } else {786    JoinedEnv.ReturnVal =787        joinValues(Func->getReturnType(), EnvA.ReturnVal, EnvA, EnvB.ReturnVal,788                   EnvB, JoinedEnv, Model);789  }790 791  if (EnvA.ReturnLoc == EnvB.ReturnLoc)792    JoinedEnv.ReturnLoc = EnvA.ReturnLoc;793  else794    JoinedEnv.ReturnLoc = nullptr;795 796  JoinedEnv.DeclToLoc = intersectDeclToLoc(EnvA.DeclToLoc, EnvB.DeclToLoc);797 798  // FIXME: update join to detect backedges and simplify the flow condition799  // accordingly.800  JoinedEnv.FlowConditionToken = EnvA.DACtx->joinFlowConditions(801      EnvA.FlowConditionToken, EnvB.FlowConditionToken);802 803  JoinedEnv.LocToVal =804      joinLocToVal(EnvA.LocToVal, EnvB.LocToVal, EnvA, EnvB, JoinedEnv, Model);805 806  if (ExprBehavior == KeepExprState) {807    JoinedEnv.ExprToVal = joinExprMaps(EnvA.ExprToVal, EnvB.ExprToVal);808    JoinedEnv.ExprToLoc = joinExprMaps(EnvA.ExprToLoc, EnvB.ExprToLoc);809  }810 811  return JoinedEnv;812}813 814Value *Environment::joinValues(QualType Ty, Value *Val1,815                               const Environment &Env1, Value *Val2,816                               const Environment &Env2, Environment &JoinedEnv,817                               Environment::ValueModel &Model) {818  if (Val1 == nullptr || Val2 == nullptr)819    // We can't say anything about the joined value -- even if one of the values820    // is non-null, we don't want to simply propagate it, because it would be821    // too specific: Because the other value is null, that means we have no822    // information at all about the value (i.e. the value is unconstrained).823    return nullptr;824 825  if (areEquivalentValues(*Val1, *Val2))826    // Arbitrarily return one of the two values.827    return Val1;828 829  return joinDistinctValues(Ty, *Val1, Env1, *Val2, Env2, JoinedEnv, Model);830}831 832StorageLocation &Environment::createStorageLocation(QualType Type) {833  return DACtx->createStorageLocation(Type);834}835 836StorageLocation &Environment::createStorageLocation(const ValueDecl &D) {837  // Evaluated declarations are always assigned the same storage locations to838  // ensure that the environment stabilizes across loop iterations. Storage839  // locations for evaluated declarations are stored in the analysis context.840  return DACtx->getStableStorageLocation(D);841}842 843StorageLocation &Environment::createStorageLocation(const Expr &E) {844  // Evaluated expressions are always assigned the same storage locations to845  // ensure that the environment stabilizes across loop iterations. Storage846  // locations for evaluated expressions are stored in the analysis context.847  return DACtx->getStableStorageLocation(E);848}849 850void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {851  assert(!DeclToLoc.contains(&D));852  // The only kinds of declarations that may have a "variable" storage location853  // are declarations of reference type and `BindingDecl`. For all other854  // declaration, the storage location should be the stable storage location855  // returned by `createStorageLocation()`.856  assert(D.getType()->isReferenceType() || isa<BindingDecl>(D) ||857         &Loc == &createStorageLocation(D));858  DeclToLoc[&D] = &Loc;859}860 861StorageLocation *Environment::getStorageLocation(const ValueDecl &D) const {862  auto It = DeclToLoc.find(&D);863  if (It == DeclToLoc.end())864    return nullptr;865 866  StorageLocation *Loc = It->second;867 868  return Loc;869}870 871void Environment::removeDecl(const ValueDecl &D) { DeclToLoc.erase(&D); }872 873void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {874  // `DeclRefExpr`s to builtin function types aren't glvalues, for some reason,875  // but we still want to be able to associate a `StorageLocation` with them,876  // so allow these as an exception.877  assert(E.isGLValue() ||878         E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));879  const Expr &CanonE = ignoreCFGOmittedNodes(E);880  assert(!ExprToLoc.contains(&CanonE));881  ExprToLoc[&CanonE] = &Loc;882}883 884StorageLocation *Environment::getStorageLocation(const Expr &E) const {885  // See comment in `setStorageLocation()`.886  assert(E.isGLValue() ||887         E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));888  auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));889  return It == ExprToLoc.end() ? nullptr : &*It->second;890}891 892RecordStorageLocation &893Environment::getResultObjectLocation(const Expr &RecordPRValue) const {894  assert(RecordPRValue.getType()->isRecordType());895  assert(RecordPRValue.isPRValue());896 897  assert(ResultObjectMap != nullptr);898  RecordStorageLocation *Loc = ResultObjectMap->lookup(&RecordPRValue);899  assert(Loc != nullptr);900  // In release builds, use the "stable" storage location if the map lookup901  // failed.902  if (Loc == nullptr)903    return cast<RecordStorageLocation>(904        DACtx->getStableStorageLocation(RecordPRValue));905  return *Loc;906}907 908PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) {909  return DACtx->getOrCreateNullPointerValue(PointeeType);910}911 912void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc,913                                             QualType Type) {914  llvm::DenseSet<QualType> Visited;915  int CreatedValuesCount = 0;916  initializeFieldsWithValues(Loc, Type, Visited, 0, CreatedValuesCount);917  if (CreatedValuesCount > MaxCompositeValueSize) {918    llvm::errs() << "Attempting to initialize a huge value of type: " << Type919                 << '\n';920  }921}922 923void Environment::setValue(const StorageLocation &Loc, Value &Val) {924  // Records should not be associated with values.925  assert(!isa<RecordStorageLocation>(Loc));926  LocToVal[&Loc] = &Val;927}928 929void Environment::setValue(const Expr &E, Value &Val) {930  const Expr &CanonE = ignoreCFGOmittedNodes(E);931 932  assert(CanonE.isPRValue());933  // Records should not be associated with values.934  assert(!CanonE.getType()->isRecordType());935  ExprToVal[&CanonE] = &Val;936}937 938Value *Environment::getValue(const StorageLocation &Loc) const {939  // Records should not be associated with values.940  assert(!isa<RecordStorageLocation>(Loc));941  return LocToVal.lookup(&Loc);942}943 944Value *Environment::getValue(const ValueDecl &D) const {945  auto *Loc = getStorageLocation(D);946  if (Loc == nullptr)947    return nullptr;948  return getValue(*Loc);949}950 951Value *Environment::getValue(const Expr &E) const {952  // Records should not be associated with values.953  assert(!E.getType()->isRecordType());954 955  if (E.isPRValue()) {956    auto It = ExprToVal.find(&ignoreCFGOmittedNodes(E));957    return It == ExprToVal.end() ? nullptr : It->second;958  }959 960  auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));961  if (It == ExprToLoc.end())962    return nullptr;963  return getValue(*It->second);964}965 966Value *Environment::createValue(QualType Type) {967  llvm::DenseSet<QualType> Visited;968  int CreatedValuesCount = 0;969  Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0,970                                                CreatedValuesCount);971  if (CreatedValuesCount > MaxCompositeValueSize) {972    llvm::errs() << "Attempting to initialize a huge value of type: " << Type973                 << '\n';974  }975  return Val;976}977 978Value *Environment::createValueUnlessSelfReferential(979    QualType Type, llvm::DenseSet<QualType> &Visited, int Depth,980    int &CreatedValuesCount) {981  assert(!Type.isNull());982  assert(!Type->isReferenceType());983  assert(!Type->isRecordType());984 985  // Allow unlimited fields at depth 1; only cap at deeper nesting levels.986  if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) ||987      Depth > MaxCompositeValueDepth)988    return nullptr;989 990  if (Type->isBooleanType()) {991    CreatedValuesCount++;992    return &makeAtomicBoolValue();993  }994 995  if (Type->isIntegerType()) {996    // FIXME: consider instead `return nullptr`, given that we do nothing useful997    // with integers, and so distinguishing them serves no purpose, but could998    // prevent convergence.999    CreatedValuesCount++;1000    return &arena().create<IntegerValue>();1001  }1002 1003  if (Type->isPointerType()) {1004    CreatedValuesCount++;1005    QualType PointeeType = Type->getPointeeType();1006    StorageLocation &PointeeLoc =1007        createLocAndMaybeValue(PointeeType, Visited, Depth, CreatedValuesCount);1008 1009    return &arena().create<PointerValue>(PointeeLoc);1010  }1011 1012  return nullptr;1013}1014 1015StorageLocation &1016Environment::createLocAndMaybeValue(QualType Ty,1017                                    llvm::DenseSet<QualType> &Visited,1018                                    int Depth, int &CreatedValuesCount) {1019  if (!Visited.insert(Ty.getCanonicalType()).second)1020    return createStorageLocation(Ty.getNonReferenceType());1021  auto EraseVisited = llvm::make_scope_exit(1022      [&Visited, Ty] { Visited.erase(Ty.getCanonicalType()); });1023 1024  Ty = Ty.getNonReferenceType();1025 1026  if (Ty->isRecordType()) {1027    auto &Loc = cast<RecordStorageLocation>(createStorageLocation(Ty));1028    initializeFieldsWithValues(Loc, Ty, Visited, Depth, CreatedValuesCount);1029    return Loc;1030  }1031 1032  StorageLocation &Loc = createStorageLocation(Ty);1033 1034  if (Value *Val = createValueUnlessSelfReferential(Ty, Visited, Depth,1035                                                    CreatedValuesCount))1036    setValue(Loc, *Val);1037 1038  return Loc;1039}1040 1041void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc,1042                                             QualType Type,1043                                             llvm::DenseSet<QualType> &Visited,1044                                             int Depth,1045                                             int &CreatedValuesCount) {1046  auto initField = [&](QualType FieldType, StorageLocation &FieldLoc) {1047    if (FieldType->isRecordType()) {1048      auto &FieldRecordLoc = cast<RecordStorageLocation>(FieldLoc);1049      initializeFieldsWithValues(FieldRecordLoc, FieldRecordLoc.getType(),1050                                 Visited, Depth + 1, CreatedValuesCount);1051    } else {1052      if (getValue(FieldLoc) != nullptr)1053        return;1054      if (!Visited.insert(FieldType.getCanonicalType()).second)1055        return;1056      if (Value *Val = createValueUnlessSelfReferential(1057              FieldType, Visited, Depth + 1, CreatedValuesCount))1058        setValue(FieldLoc, *Val);1059      Visited.erase(FieldType.getCanonicalType());1060    }1061  };1062 1063  for (const FieldDecl *Field : DACtx->getModeledFields(Type)) {1064    assert(Field != nullptr);1065    QualType FieldType = Field->getType();1066 1067    if (FieldType->isReferenceType()) {1068      Loc.setChild(*Field,1069                   &createLocAndMaybeValue(FieldType, Visited, Depth + 1,1070                                           CreatedValuesCount));1071    } else {1072      StorageLocation *FieldLoc = Loc.getChild(*Field);1073      assert(FieldLoc != nullptr);1074      initField(FieldType, *FieldLoc);1075    }1076  }1077  for (const auto &[FieldName, FieldType] : DACtx->getSyntheticFields(Type)) {1078    // Synthetic fields cannot have reference type, so we don't need to deal1079    // with this case.1080    assert(!FieldType->isReferenceType());1081    initField(FieldType, Loc.getSyntheticField(FieldName));1082  }1083}1084 1085StorageLocation &Environment::createObjectInternal(const ValueDecl *D,1086                                                   QualType Ty,1087                                                   const Expr *InitExpr) {1088  if (Ty->isReferenceType()) {1089    // Although variables of reference type always need to be initialized, it1090    // can happen that we can't see the initializer, so `InitExpr` may still1091    // be null.1092    if (InitExpr) {1093      if (auto *InitExprLoc = getStorageLocation(*InitExpr))1094        return *InitExprLoc;1095    }1096 1097    // Even though we have an initializer, we might not get an1098    // InitExprLoc, for example if the InitExpr is a CallExpr for which we1099    // don't have a function body. In this case, we just invent a storage1100    // location and value -- it's the best we can do.1101    return createObjectInternal(D, Ty.getNonReferenceType(), nullptr);1102  }1103 1104  StorageLocation &Loc =1105      D ? createStorageLocation(*D) : createStorageLocation(Ty);1106 1107  if (Ty->isRecordType()) {1108    auto &RecordLoc = cast<RecordStorageLocation>(Loc);1109    if (!InitExpr)1110      initializeFieldsWithValues(RecordLoc);1111  } else {1112    Value *Val = nullptr;1113    if (InitExpr)1114      // In the (few) cases where an expression is intentionally1115      // "uninterpreted", `InitExpr` is not associated with a value.  There are1116      // two ways to handle this situation: propagate the status, so that1117      // uninterpreted initializers result in uninterpreted variables, or1118      // provide a default value. We choose the latter so that later refinements1119      // of the variable can be used for reasoning about the surrounding code.1120      // For this reason, we let this case be handled by the `createValue()`1121      // call below.1122      //1123      // FIXME. If and when we interpret all language cases, change this to1124      // assert that `InitExpr` is interpreted, rather than supplying a1125      // default value (assuming we don't update the environment API to return1126      // references).1127      Val = getValue(*InitExpr);1128    if (!Val)1129      Val = createValue(Ty);1130    if (Val)1131      setValue(Loc, *Val);1132  }1133 1134  return Loc;1135}1136 1137void Environment::assume(const Formula &F) {1138  DACtx->addFlowConditionConstraint(FlowConditionToken, F);1139}1140 1141bool Environment::proves(const Formula &F) const {1142  return DACtx->flowConditionImplies(FlowConditionToken, F);1143}1144 1145bool Environment::allows(const Formula &F) const {1146  return DACtx->flowConditionAllows(FlowConditionToken, F);1147}1148 1149void Environment::dump(raw_ostream &OS) const {1150  llvm::DenseMap<const StorageLocation *, std::string> LocToName;1151  if (LocForRecordReturnVal != nullptr)1152    LocToName[LocForRecordReturnVal] = "(returned record)";1153  if (ThisPointeeLoc != nullptr)1154    LocToName[ThisPointeeLoc] = "this";1155 1156  OS << "DeclToLoc:\n";1157  for (auto [D, L] : DeclToLoc) {1158    auto Iter = LocToName.insert({L, D->getNameAsString()}).first;1159    OS << "  [" << Iter->second << ", " << L << "]\n";1160  }1161  OS << "ExprToLoc:\n";1162  for (auto [E, L] : ExprToLoc)1163    OS << "  [" << E << ", " << L << "]\n";1164 1165  OS << "ExprToVal:\n";1166  for (auto [E, V] : ExprToVal)1167    OS << "  [" << E << ", " << V << ": " << *V << "]\n";1168 1169  OS << "LocToVal:\n";1170  for (auto [L, V] : LocToVal) {1171    OS << "  [" << L;1172    if (auto Iter = LocToName.find(L); Iter != LocToName.end())1173      OS << " (" << Iter->second << ")";1174    OS << ", " << V << ": " << *V << "]\n";1175  }1176 1177  if (const FunctionDecl *Func = getCurrentFunc()) {1178    if (Func->getReturnType()->isReferenceType()) {1179      OS << "ReturnLoc: " << ReturnLoc;1180      if (auto Iter = LocToName.find(ReturnLoc); Iter != LocToName.end())1181        OS << " (" << Iter->second << ")";1182      OS << "\n";1183    } else if (Func->getReturnType()->isRecordType() ||1184               isa<CXXConstructorDecl>(Func)) {1185      OS << "LocForRecordReturnVal: " << LocForRecordReturnVal << "\n";1186    } else if (!Func->getReturnType()->isVoidType()) {1187      if (ReturnVal == nullptr)1188        OS << "ReturnVal: nullptr\n";1189      else1190        OS << "ReturnVal: " << *ReturnVal << "\n";1191    }1192 1193    if (isa<CXXMethodDecl>(Func)) {1194      OS << "ThisPointeeLoc: " << ThisPointeeLoc << "\n";1195    }1196  }1197 1198  OS << "\n";1199  DACtx->dumpFlowCondition(FlowConditionToken, OS);1200}1201 1202void Environment::dump() const { dump(llvm::dbgs()); }1203 1204Environment::PrValueToResultObject Environment::buildResultObjectMap(1205    DataflowAnalysisContext *DACtx, const FunctionDecl *FuncDecl,1206    RecordStorageLocation *ThisPointeeLoc,1207    RecordStorageLocation *LocForRecordReturnVal) {1208  assert(FuncDecl->doesThisDeclarationHaveABody());1209 1210  PrValueToResultObject Map = buildResultObjectMap(1211      DACtx, FuncDecl->getBody(), ThisPointeeLoc, LocForRecordReturnVal);1212 1213  ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);1214  if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(FuncDecl))1215    Visitor.traverseConstructorInits(Ctor, ThisPointeeLoc);1216 1217  return Map;1218}1219 1220Environment::PrValueToResultObject Environment::buildResultObjectMap(1221    DataflowAnalysisContext *DACtx, Stmt *S,1222    RecordStorageLocation *ThisPointeeLoc,1223    RecordStorageLocation *LocForRecordReturnVal) {1224  PrValueToResultObject Map;1225  ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);1226  Visitor.TraverseStmt(S);1227  return Map;1228}1229 1230RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE,1231                                                 const Environment &Env) {1232  Expr *ImplicitObject = MCE.getImplicitObjectArgument();1233  if (ImplicitObject == nullptr)1234    return nullptr;1235  if (ImplicitObject->getType()->isPointerType()) {1236    if (auto *Val = Env.get<PointerValue>(*ImplicitObject))1237      return &cast<RecordStorageLocation>(Val->getPointeeLoc());1238    return nullptr;1239  }1240  return cast_or_null<RecordStorageLocation>(1241      Env.getStorageLocation(*ImplicitObject));1242}1243 1244RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,1245                                             const Environment &Env) {1246  Expr *Base = ME.getBase();1247  if (Base == nullptr)1248    return nullptr;1249  if (ME.isArrow()) {1250    if (auto *Val = Env.get<PointerValue>(*Base))1251      return &cast<RecordStorageLocation>(Val->getPointeeLoc());1252    return nullptr;1253  }1254  return Env.get<RecordStorageLocation>(*Base);1255}1256 1257} // namespace dataflow1258} // namespace clang1259