104eeddc0SDimitry Andric //===-- DataflowEnvironment.cpp ---------------------------------*- C++ -*-===// 204eeddc0SDimitry Andric // 304eeddc0SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 404eeddc0SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 504eeddc0SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 604eeddc0SDimitry Andric // 704eeddc0SDimitry Andric //===----------------------------------------------------------------------===// 804eeddc0SDimitry Andric // 904eeddc0SDimitry Andric // This file defines an Environment class that is used by dataflow analyses 1004eeddc0SDimitry Andric // that run over Control-Flow Graphs (CFGs) to keep track of the state of the 1104eeddc0SDimitry Andric // program at given program points. 1204eeddc0SDimitry Andric // 1304eeddc0SDimitry Andric //===----------------------------------------------------------------------===// 1404eeddc0SDimitry Andric 1504eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" 1604eeddc0SDimitry Andric #include "clang/AST/Decl.h" 1704eeddc0SDimitry Andric #include "clang/AST/DeclCXX.h" 1804eeddc0SDimitry Andric #include "clang/AST/Type.h" 1904eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowLattice.h" 2004eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h" 2104eeddc0SDimitry Andric #include "llvm/ADT/DenseMap.h" 2204eeddc0SDimitry Andric #include "llvm/ADT/DenseSet.h" 2306c3fb27SDimitry Andric #include "llvm/ADT/MapVector.h" 24bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h" 2504eeddc0SDimitry Andric #include "llvm/Support/ErrorHandling.h" 2681ad6265SDimitry Andric #include <cassert> 2704eeddc0SDimitry Andric #include <utility> 2804eeddc0SDimitry Andric 2904eeddc0SDimitry Andric namespace clang { 3004eeddc0SDimitry Andric namespace dataflow { 3104eeddc0SDimitry Andric 3281ad6265SDimitry Andric // FIXME: convert these to parameters of the analysis or environment. Current 3381ad6265SDimitry Andric // settings have been experimentaly validated, but only for a particular 3481ad6265SDimitry Andric // analysis. 3581ad6265SDimitry Andric static constexpr int MaxCompositeValueDepth = 3; 3681ad6265SDimitry Andric static constexpr int MaxCompositeValueSize = 1000; 3781ad6265SDimitry Andric 3804eeddc0SDimitry Andric /// Returns a map consisting of key-value entries that are present in both maps. 39*5f757f3fSDimitry Andric static llvm::DenseMap<const ValueDecl *, StorageLocation *> intersectDeclToLoc( 40*5f757f3fSDimitry Andric const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc1, 41*5f757f3fSDimitry Andric const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc2) { 42*5f757f3fSDimitry Andric llvm::DenseMap<const ValueDecl *, StorageLocation *> Result; 43*5f757f3fSDimitry Andric for (auto &Entry : DeclToLoc1) { 44*5f757f3fSDimitry Andric auto It = DeclToLoc2.find(Entry.first); 45*5f757f3fSDimitry Andric if (It != DeclToLoc2.end() && Entry.second == It->second) 4604eeddc0SDimitry Andric Result.insert({Entry.first, Entry.second}); 4704eeddc0SDimitry Andric } 4804eeddc0SDimitry Andric return Result; 4904eeddc0SDimitry Andric } 5004eeddc0SDimitry Andric 51*5f757f3fSDimitry Andric // Whether to consider equivalent two values with an unknown relation. 52*5f757f3fSDimitry Andric // 53*5f757f3fSDimitry Andric // FIXME: this function is a hack enabling unsoundness to support 54*5f757f3fSDimitry Andric // convergence. Once we have widening support for the reference/pointer and 55*5f757f3fSDimitry Andric // struct built-in models, this should be unconditionally `false` (and inlined 56*5f757f3fSDimitry Andric // as such at its call sites). 57*5f757f3fSDimitry Andric static bool equateUnknownValues(Value::Kind K) { 58*5f757f3fSDimitry Andric switch (K) { 59*5f757f3fSDimitry Andric case Value::Kind::Integer: 60*5f757f3fSDimitry Andric case Value::Kind::Pointer: 61*5f757f3fSDimitry Andric case Value::Kind::Record: 62*5f757f3fSDimitry Andric return true; 63*5f757f3fSDimitry Andric default: 64*5f757f3fSDimitry Andric return false; 65*5f757f3fSDimitry Andric } 66*5f757f3fSDimitry Andric } 67*5f757f3fSDimitry Andric 68bdd1243dSDimitry Andric static bool compareDistinctValues(QualType Type, Value &Val1, 69bdd1243dSDimitry Andric const Environment &Env1, Value &Val2, 7081ad6265SDimitry Andric const Environment &Env2, 7181ad6265SDimitry Andric Environment::ValueModel &Model) { 72bdd1243dSDimitry Andric // Note: Potentially costly, but, for booleans, we could check whether both 73bdd1243dSDimitry Andric // can be proven equivalent in their respective environments. 74bdd1243dSDimitry Andric 75bdd1243dSDimitry Andric // FIXME: move the reference/pointers logic from `areEquivalentValues` to here 76bdd1243dSDimitry Andric // and implement separate, join/widen specific handling for 77bdd1243dSDimitry Andric // reference/pointers. 78bdd1243dSDimitry Andric switch (Model.compare(Type, Val1, Env1, Val2, Env2)) { 79bdd1243dSDimitry Andric case ComparisonResult::Same: 80bdd1243dSDimitry Andric return true; 81bdd1243dSDimitry Andric case ComparisonResult::Different: 82bdd1243dSDimitry Andric return false; 83bdd1243dSDimitry Andric case ComparisonResult::Unknown: 84*5f757f3fSDimitry Andric return equateUnknownValues(Val1.getKind()); 85bdd1243dSDimitry Andric } 86bdd1243dSDimitry Andric llvm_unreachable("All cases covered in switch"); 8781ad6265SDimitry Andric } 8881ad6265SDimitry Andric 8981ad6265SDimitry Andric /// Attempts to merge distinct values `Val1` and `Val2` in `Env1` and `Env2`, 9081ad6265SDimitry Andric /// respectively, of the same type `Type`. Merging generally produces a single 9181ad6265SDimitry Andric /// value that (soundly) approximates the two inputs, although the actual 9281ad6265SDimitry Andric /// meaning depends on `Model`. 93bdd1243dSDimitry Andric static Value *mergeDistinctValues(QualType Type, Value &Val1, 94bdd1243dSDimitry Andric const Environment &Env1, Value &Val2, 9581ad6265SDimitry Andric const Environment &Env2, 9681ad6265SDimitry Andric Environment &MergedEnv, 9781ad6265SDimitry Andric Environment::ValueModel &Model) { 9881ad6265SDimitry Andric // Join distinct boolean values preserving information about the constraints 9981ad6265SDimitry Andric // in the respective path conditions. 100bdd1243dSDimitry Andric if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) { 101bdd1243dSDimitry Andric // FIXME: Checking both values should be unnecessary, since they should have 102bdd1243dSDimitry Andric // a consistent shape. However, right now we can end up with BoolValue's in 103bdd1243dSDimitry Andric // integer-typed variables due to our incorrect handling of 104bdd1243dSDimitry Andric // boolean-to-integer casts (we just propagate the BoolValue to the result 105bdd1243dSDimitry Andric // of the cast). So, a join can encounter an integer in one branch but a 106bdd1243dSDimitry Andric // bool in the other. 107bdd1243dSDimitry Andric // For example: 108bdd1243dSDimitry Andric // ``` 109bdd1243dSDimitry Andric // std::optional<bool> o; 110bdd1243dSDimitry Andric // int x; 111bdd1243dSDimitry Andric // if (o.has_value()) 112bdd1243dSDimitry Andric // x = o.value(); 113bdd1243dSDimitry Andric // ``` 11406c3fb27SDimitry Andric auto &Expr1 = cast<BoolValue>(Val1).formula(); 11506c3fb27SDimitry Andric auto &Expr2 = cast<BoolValue>(Val2).formula(); 11606c3fb27SDimitry Andric auto &A = MergedEnv.arena(); 11706c3fb27SDimitry Andric auto &MergedVal = A.makeAtomRef(A.makeAtom()); 118*5f757f3fSDimitry Andric MergedEnv.assume( 11906c3fb27SDimitry Andric A.makeOr(A.makeAnd(A.makeAtomRef(Env1.getFlowConditionToken()), 12006c3fb27SDimitry Andric A.makeEquals(MergedVal, Expr1)), 12106c3fb27SDimitry Andric A.makeAnd(A.makeAtomRef(Env2.getFlowConditionToken()), 12206c3fb27SDimitry Andric A.makeEquals(MergedVal, Expr2)))); 12306c3fb27SDimitry Andric return &A.makeBoolValue(MergedVal); 12406c3fb27SDimitry Andric } 12506c3fb27SDimitry Andric 12606c3fb27SDimitry Andric Value *MergedVal = nullptr; 127*5f757f3fSDimitry Andric if (auto *RecordVal1 = dyn_cast<RecordValue>(&Val1)) { 128*5f757f3fSDimitry Andric auto *RecordVal2 = cast<RecordValue>(&Val2); 12906c3fb27SDimitry Andric 130*5f757f3fSDimitry Andric if (&RecordVal1->getLoc() == &RecordVal2->getLoc()) 131*5f757f3fSDimitry Andric // `RecordVal1` and `RecordVal2` may have different properties associated 132*5f757f3fSDimitry Andric // with them. Create a new `RecordValue` with the same location but 133*5f757f3fSDimitry Andric // without any properties so that we soundly approximate both values. If a 134*5f757f3fSDimitry Andric // particular analysis needs to merge properties, it should do so in 135*5f757f3fSDimitry Andric // `DataflowAnalysis::merge()`. 136*5f757f3fSDimitry Andric MergedVal = &MergedEnv.create<RecordValue>(RecordVal1->getLoc()); 137*5f757f3fSDimitry Andric else 138*5f757f3fSDimitry Andric // If the locations for the two records are different, need to create a 139*5f757f3fSDimitry Andric // completely new value. 140*5f757f3fSDimitry Andric MergedVal = MergedEnv.createValue(Type); 14106c3fb27SDimitry Andric } else { 14206c3fb27SDimitry Andric MergedVal = MergedEnv.createValue(Type); 14381ad6265SDimitry Andric } 14481ad6265SDimitry Andric 14581ad6265SDimitry Andric // FIXME: Consider destroying `MergedValue` immediately if `ValueModel::merge` 14681ad6265SDimitry Andric // returns false to avoid storing unneeded values in `DACtx`. 14706c3fb27SDimitry Andric if (MergedVal) 148bdd1243dSDimitry Andric if (Model.merge(Type, Val1, Env1, Val2, Env2, *MergedVal, MergedEnv)) 14981ad6265SDimitry Andric return MergedVal; 15081ad6265SDimitry Andric 15181ad6265SDimitry Andric return nullptr; 15281ad6265SDimitry Andric } 15381ad6265SDimitry Andric 154bdd1243dSDimitry Andric // When widening does not change `Current`, return value will equal `&Prev`. 155bdd1243dSDimitry Andric static Value &widenDistinctValues(QualType Type, Value &Prev, 156bdd1243dSDimitry Andric const Environment &PrevEnv, Value &Current, 157bdd1243dSDimitry Andric Environment &CurrentEnv, 158bdd1243dSDimitry Andric Environment::ValueModel &Model) { 159bdd1243dSDimitry Andric // Boolean-model widening. 160*5f757f3fSDimitry Andric if (auto *PrevBool = dyn_cast<BoolValue>(&Prev)) { 161*5f757f3fSDimitry Andric // If previous value was already Top, re-use that to (implicitly) indicate 162*5f757f3fSDimitry Andric // that no change occurred. 163bdd1243dSDimitry Andric if (isa<TopBoolValue>(Prev)) 164bdd1243dSDimitry Andric return Prev; 165*5f757f3fSDimitry Andric 166*5f757f3fSDimitry Andric // We may need to widen to Top, but before we do so, check whether both 167*5f757f3fSDimitry Andric // values are implied to be either true or false in the current environment. 168*5f757f3fSDimitry Andric // In that case, we can simply return a literal instead. 169*5f757f3fSDimitry Andric auto &CurBool = cast<BoolValue>(Current); 170*5f757f3fSDimitry Andric bool TruePrev = PrevEnv.proves(PrevBool->formula()); 171*5f757f3fSDimitry Andric bool TrueCur = CurrentEnv.proves(CurBool.formula()); 172*5f757f3fSDimitry Andric if (TruePrev && TrueCur) 173*5f757f3fSDimitry Andric return CurrentEnv.getBoolLiteralValue(true); 174*5f757f3fSDimitry Andric if (!TruePrev && !TrueCur && 175*5f757f3fSDimitry Andric PrevEnv.proves(PrevEnv.arena().makeNot(PrevBool->formula())) && 176*5f757f3fSDimitry Andric CurrentEnv.proves(CurrentEnv.arena().makeNot(CurBool.formula()))) 177*5f757f3fSDimitry Andric return CurrentEnv.getBoolLiteralValue(false); 178*5f757f3fSDimitry Andric 179bdd1243dSDimitry Andric return CurrentEnv.makeTopBoolValue(); 180bdd1243dSDimitry Andric } 18181ad6265SDimitry Andric 182bdd1243dSDimitry Andric // FIXME: Add other built-in model widening. 183bdd1243dSDimitry Andric 184bdd1243dSDimitry Andric // Custom-model widening. 185bdd1243dSDimitry Andric if (auto *W = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv)) 186bdd1243dSDimitry Andric return *W; 187bdd1243dSDimitry Andric 188*5f757f3fSDimitry Andric return equateUnknownValues(Prev.getKind()) ? Prev : Current; 189*5f757f3fSDimitry Andric } 190*5f757f3fSDimitry Andric 191*5f757f3fSDimitry Andric // Returns whether the values in `Map1` and `Map2` compare equal for those 192*5f757f3fSDimitry Andric // keys that `Map1` and `Map2` have in common. 193*5f757f3fSDimitry Andric template <typename Key> 194*5f757f3fSDimitry Andric bool compareKeyToValueMaps(const llvm::MapVector<Key, Value *> &Map1, 195*5f757f3fSDimitry Andric const llvm::MapVector<Key, Value *> &Map2, 196*5f757f3fSDimitry Andric const Environment &Env1, const Environment &Env2, 197*5f757f3fSDimitry Andric Environment::ValueModel &Model) { 198*5f757f3fSDimitry Andric for (auto &Entry : Map1) { 199*5f757f3fSDimitry Andric Key K = Entry.first; 200*5f757f3fSDimitry Andric assert(K != nullptr); 201*5f757f3fSDimitry Andric 202*5f757f3fSDimitry Andric Value *Val = Entry.second; 203*5f757f3fSDimitry Andric assert(Val != nullptr); 204*5f757f3fSDimitry Andric 205*5f757f3fSDimitry Andric auto It = Map2.find(K); 206*5f757f3fSDimitry Andric if (It == Map2.end()) 207*5f757f3fSDimitry Andric continue; 208*5f757f3fSDimitry Andric assert(It->second != nullptr); 209*5f757f3fSDimitry Andric 210*5f757f3fSDimitry Andric if (!areEquivalentValues(*Val, *It->second) && 211*5f757f3fSDimitry Andric !compareDistinctValues(K->getType(), *Val, Env1, *It->second, Env2, 212*5f757f3fSDimitry Andric Model)) 213*5f757f3fSDimitry Andric return false; 214*5f757f3fSDimitry Andric } 215*5f757f3fSDimitry Andric 216*5f757f3fSDimitry Andric return true; 217*5f757f3fSDimitry Andric } 218*5f757f3fSDimitry Andric 219*5f757f3fSDimitry Andric // Perform a join on two `LocToVal` maps. 220*5f757f3fSDimitry Andric static llvm::MapVector<const StorageLocation *, Value *> 221*5f757f3fSDimitry Andric joinLocToVal(const llvm::MapVector<const StorageLocation *, Value *> &LocToVal, 222*5f757f3fSDimitry Andric const llvm::MapVector<const StorageLocation *, Value *> &LocToVal2, 223*5f757f3fSDimitry Andric const Environment &Env1, const Environment &Env2, 224*5f757f3fSDimitry Andric Environment &JoinedEnv, Environment::ValueModel &Model) { 225*5f757f3fSDimitry Andric llvm::MapVector<const StorageLocation *, Value *> Result; 226*5f757f3fSDimitry Andric for (auto &Entry : LocToVal) { 227*5f757f3fSDimitry Andric const StorageLocation *Loc = Entry.first; 228*5f757f3fSDimitry Andric assert(Loc != nullptr); 229*5f757f3fSDimitry Andric 230*5f757f3fSDimitry Andric Value *Val = Entry.second; 231*5f757f3fSDimitry Andric assert(Val != nullptr); 232*5f757f3fSDimitry Andric 233*5f757f3fSDimitry Andric auto It = LocToVal2.find(Loc); 234*5f757f3fSDimitry Andric if (It == LocToVal2.end()) 235*5f757f3fSDimitry Andric continue; 236*5f757f3fSDimitry Andric assert(It->second != nullptr); 237*5f757f3fSDimitry Andric 238*5f757f3fSDimitry Andric if (areEquivalentValues(*Val, *It->second)) { 239*5f757f3fSDimitry Andric Result.insert({Loc, Val}); 240*5f757f3fSDimitry Andric continue; 241*5f757f3fSDimitry Andric } 242*5f757f3fSDimitry Andric 243*5f757f3fSDimitry Andric if (Value *MergedVal = mergeDistinctValues( 244*5f757f3fSDimitry Andric Loc->getType(), *Val, Env1, *It->second, Env2, JoinedEnv, Model)) { 245*5f757f3fSDimitry Andric Result.insert({Loc, MergedVal}); 246*5f757f3fSDimitry Andric } 247*5f757f3fSDimitry Andric } 248*5f757f3fSDimitry Andric 249*5f757f3fSDimitry Andric return Result; 250*5f757f3fSDimitry Andric } 251*5f757f3fSDimitry Andric 252*5f757f3fSDimitry Andric // Perform widening on either `LocToVal` or `ExprToVal`. `Key` must be either 253*5f757f3fSDimitry Andric // `const StorageLocation *` or `const Expr *`. 254*5f757f3fSDimitry Andric template <typename Key> 255*5f757f3fSDimitry Andric llvm::MapVector<Key, Value *> 256*5f757f3fSDimitry Andric widenKeyToValueMap(const llvm::MapVector<Key, Value *> &CurMap, 257*5f757f3fSDimitry Andric const llvm::MapVector<Key, Value *> &PrevMap, 258*5f757f3fSDimitry Andric Environment &CurEnv, const Environment &PrevEnv, 259*5f757f3fSDimitry Andric Environment::ValueModel &Model, LatticeJoinEffect &Effect) { 260*5f757f3fSDimitry Andric llvm::MapVector<Key, Value *> WidenedMap; 261*5f757f3fSDimitry Andric for (auto &Entry : CurMap) { 262*5f757f3fSDimitry Andric Key K = Entry.first; 263*5f757f3fSDimitry Andric assert(K != nullptr); 264*5f757f3fSDimitry Andric 265*5f757f3fSDimitry Andric Value *Val = Entry.second; 266*5f757f3fSDimitry Andric assert(Val != nullptr); 267*5f757f3fSDimitry Andric 268*5f757f3fSDimitry Andric auto PrevIt = PrevMap.find(K); 269*5f757f3fSDimitry Andric if (PrevIt == PrevMap.end()) 270*5f757f3fSDimitry Andric continue; 271*5f757f3fSDimitry Andric assert(PrevIt->second != nullptr); 272*5f757f3fSDimitry Andric 273*5f757f3fSDimitry Andric if (areEquivalentValues(*Val, *PrevIt->second)) { 274*5f757f3fSDimitry Andric WidenedMap.insert({K, Val}); 275*5f757f3fSDimitry Andric continue; 276*5f757f3fSDimitry Andric } 277*5f757f3fSDimitry Andric 278*5f757f3fSDimitry Andric Value &WidenedVal = widenDistinctValues(K->getType(), *PrevIt->second, 279*5f757f3fSDimitry Andric PrevEnv, *Val, CurEnv, Model); 280*5f757f3fSDimitry Andric WidenedMap.insert({K, &WidenedVal}); 281*5f757f3fSDimitry Andric if (&WidenedVal != PrevIt->second) 282*5f757f3fSDimitry Andric Effect = LatticeJoinEffect::Changed; 283*5f757f3fSDimitry Andric } 284*5f757f3fSDimitry Andric 285*5f757f3fSDimitry Andric return WidenedMap; 28681ad6265SDimitry Andric } 28781ad6265SDimitry Andric 28881ad6265SDimitry Andric /// Initializes a global storage value. 289bdd1243dSDimitry Andric static void insertIfGlobal(const Decl &D, 290bdd1243dSDimitry Andric llvm::DenseSet<const VarDecl *> &Vars) { 29181ad6265SDimitry Andric if (auto *V = dyn_cast<VarDecl>(&D)) 292bdd1243dSDimitry Andric if (V->hasGlobalStorage()) 293bdd1243dSDimitry Andric Vars.insert(V); 29481ad6265SDimitry Andric } 29581ad6265SDimitry Andric 29606c3fb27SDimitry Andric static void insertIfFunction(const Decl &D, 29706c3fb27SDimitry Andric llvm::DenseSet<const FunctionDecl *> &Funcs) { 29806c3fb27SDimitry Andric if (auto *FD = dyn_cast<FunctionDecl>(&D)) 29906c3fb27SDimitry Andric Funcs.insert(FD); 30006c3fb27SDimitry Andric } 30106c3fb27SDimitry Andric 302*5f757f3fSDimitry Andric static MemberExpr *getMemberForAccessor(const CXXMemberCallExpr &C) { 303*5f757f3fSDimitry Andric // Use getCalleeDecl instead of getMethodDecl in order to handle 304*5f757f3fSDimitry Andric // pointer-to-member calls. 305*5f757f3fSDimitry Andric const auto *MethodDecl = dyn_cast_or_null<CXXMethodDecl>(C.getCalleeDecl()); 306*5f757f3fSDimitry Andric if (!MethodDecl) 307*5f757f3fSDimitry Andric return nullptr; 308*5f757f3fSDimitry Andric auto *Body = dyn_cast_or_null<CompoundStmt>(MethodDecl->getBody()); 309*5f757f3fSDimitry Andric if (!Body || Body->size() != 1) 310*5f757f3fSDimitry Andric return nullptr; 311*5f757f3fSDimitry Andric if (auto *RS = dyn_cast<ReturnStmt>(*Body->body_begin())) 312*5f757f3fSDimitry Andric if (auto *Return = RS->getRetValue()) 313*5f757f3fSDimitry Andric return dyn_cast<MemberExpr>(Return->IgnoreParenImpCasts()); 314*5f757f3fSDimitry Andric return nullptr; 315*5f757f3fSDimitry Andric } 316*5f757f3fSDimitry Andric 31706c3fb27SDimitry Andric static void 31806c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(const Decl &D, FieldSet &Fields, 31906c3fb27SDimitry Andric llvm::DenseSet<const VarDecl *> &Vars, 32006c3fb27SDimitry Andric llvm::DenseSet<const FunctionDecl *> &Funcs) { 32106c3fb27SDimitry Andric insertIfGlobal(D, Vars); 32206c3fb27SDimitry Andric insertIfFunction(D, Funcs); 323bdd1243dSDimitry Andric if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D)) 324bdd1243dSDimitry Andric for (const auto *B : Decomp->bindings()) 325bdd1243dSDimitry Andric if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding())) 326bdd1243dSDimitry Andric // FIXME: should we be using `E->getFoundDecl()`? 327bdd1243dSDimitry Andric if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) 328bdd1243dSDimitry Andric Fields.insert(FD); 32981ad6265SDimitry Andric } 33081ad6265SDimitry Andric 33106c3fb27SDimitry Andric /// Traverses `S` and inserts into `Fields`, `Vars` and `Funcs` any fields, 33206c3fb27SDimitry Andric /// global variables and functions that are declared in or referenced from 33306c3fb27SDimitry Andric /// sub-statements. 33406c3fb27SDimitry Andric static void 33506c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(const Stmt &S, FieldSet &Fields, 33606c3fb27SDimitry Andric llvm::DenseSet<const VarDecl *> &Vars, 33706c3fb27SDimitry Andric llvm::DenseSet<const FunctionDecl *> &Funcs) { 338bdd1243dSDimitry Andric for (auto *Child : S.children()) 339bdd1243dSDimitry Andric if (Child != nullptr) 34006c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*Child, Fields, Vars, Funcs); 34106c3fb27SDimitry Andric if (const auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(&S)) 34206c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*DefaultInit->getExpr(), Fields, Vars, Funcs); 343bdd1243dSDimitry Andric 34481ad6265SDimitry Andric if (auto *DS = dyn_cast<DeclStmt>(&S)) { 345bdd1243dSDimitry Andric if (DS->isSingleDecl()) 34606c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*DS->getSingleDecl(), Fields, Vars, Funcs); 347bdd1243dSDimitry Andric else 34881ad6265SDimitry Andric for (auto *D : DS->getDeclGroup()) 34906c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*D, Fields, Vars, Funcs); 35081ad6265SDimitry Andric } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) { 35106c3fb27SDimitry Andric insertIfGlobal(*E->getDecl(), Vars); 35206c3fb27SDimitry Andric insertIfFunction(*E->getDecl(), Funcs); 353*5f757f3fSDimitry Andric } else if (const auto *C = dyn_cast<CXXMemberCallExpr>(&S)) { 354*5f757f3fSDimitry Andric // If this is a method that returns a member variable but does nothing else, 355*5f757f3fSDimitry Andric // model the field of the return value. 356*5f757f3fSDimitry Andric if (MemberExpr *E = getMemberForAccessor(*C)) 357*5f757f3fSDimitry Andric if (const auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) 358*5f757f3fSDimitry Andric Fields.insert(FD); 35981ad6265SDimitry Andric } else if (auto *E = dyn_cast<MemberExpr>(&S)) { 360bdd1243dSDimitry Andric // FIXME: should we be using `E->getFoundDecl()`? 361bdd1243dSDimitry Andric const ValueDecl *VD = E->getMemberDecl(); 36206c3fb27SDimitry Andric insertIfGlobal(*VD, Vars); 36306c3fb27SDimitry Andric insertIfFunction(*VD, Funcs); 364bdd1243dSDimitry Andric if (const auto *FD = dyn_cast<FieldDecl>(VD)) 365bdd1243dSDimitry Andric Fields.insert(FD); 36606c3fb27SDimitry Andric } else if (auto *InitList = dyn_cast<InitListExpr>(&S)) { 36706c3fb27SDimitry Andric if (RecordDecl *RD = InitList->getType()->getAsRecordDecl()) 36806c3fb27SDimitry Andric for (const auto *FD : getFieldsForInitListExpr(RD)) 36906c3fb27SDimitry Andric Fields.insert(FD); 370bdd1243dSDimitry Andric } 371bdd1243dSDimitry Andric } 372bdd1243dSDimitry Andric 373*5f757f3fSDimitry Andric Environment::Environment(DataflowAnalysisContext &DACtx) 374*5f757f3fSDimitry Andric : DACtx(&DACtx), 375*5f757f3fSDimitry Andric FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {} 376*5f757f3fSDimitry Andric 377*5f757f3fSDimitry Andric Environment::Environment(DataflowAnalysisContext &DACtx, 378*5f757f3fSDimitry Andric const DeclContext &DeclCtx) 379*5f757f3fSDimitry Andric : Environment(DACtx) { 380*5f757f3fSDimitry Andric CallStack.push_back(&DeclCtx); 381*5f757f3fSDimitry Andric } 382*5f757f3fSDimitry Andric 383*5f757f3fSDimitry Andric void Environment::initialize() { 384*5f757f3fSDimitry Andric const DeclContext *DeclCtx = getDeclCtx(); 385*5f757f3fSDimitry Andric if (DeclCtx == nullptr) 386*5f757f3fSDimitry Andric return; 387*5f757f3fSDimitry Andric 388*5f757f3fSDimitry Andric if (const auto *FuncDecl = dyn_cast<FunctionDecl>(DeclCtx)) { 389*5f757f3fSDimitry Andric assert(FuncDecl->getBody() != nullptr); 390*5f757f3fSDimitry Andric 391*5f757f3fSDimitry Andric initFieldsGlobalsAndFuncs(FuncDecl); 392*5f757f3fSDimitry Andric 393*5f757f3fSDimitry Andric for (const auto *ParamDecl : FuncDecl->parameters()) { 394*5f757f3fSDimitry Andric assert(ParamDecl != nullptr); 395*5f757f3fSDimitry Andric setStorageLocation(*ParamDecl, createObject(*ParamDecl, nullptr)); 396*5f757f3fSDimitry Andric } 397*5f757f3fSDimitry Andric } 398*5f757f3fSDimitry Andric 399*5f757f3fSDimitry Andric if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(DeclCtx)) { 400*5f757f3fSDimitry Andric auto *Parent = MethodDecl->getParent(); 401*5f757f3fSDimitry Andric assert(Parent != nullptr); 402*5f757f3fSDimitry Andric 403*5f757f3fSDimitry Andric if (Parent->isLambda()) { 404*5f757f3fSDimitry Andric for (auto Capture : Parent->captures()) { 405*5f757f3fSDimitry Andric if (Capture.capturesVariable()) { 406*5f757f3fSDimitry Andric const auto *VarDecl = Capture.getCapturedVar(); 407*5f757f3fSDimitry Andric assert(VarDecl != nullptr); 408*5f757f3fSDimitry Andric setStorageLocation(*VarDecl, createObject(*VarDecl, nullptr)); 409*5f757f3fSDimitry Andric } else if (Capture.capturesThis()) { 410*5f757f3fSDimitry Andric const auto *SurroundingMethodDecl = 411*5f757f3fSDimitry Andric cast<CXXMethodDecl>(DeclCtx->getNonClosureAncestor()); 412*5f757f3fSDimitry Andric QualType ThisPointeeType = 413*5f757f3fSDimitry Andric SurroundingMethodDecl->getFunctionObjectParameterType(); 414*5f757f3fSDimitry Andric setThisPointeeStorageLocation( 415*5f757f3fSDimitry Andric cast<RecordValue>(createValue(ThisPointeeType))->getLoc()); 416*5f757f3fSDimitry Andric } 417*5f757f3fSDimitry Andric } 418*5f757f3fSDimitry Andric } else if (MethodDecl->isImplicitObjectMemberFunction()) { 419*5f757f3fSDimitry Andric QualType ThisPointeeType = MethodDecl->getFunctionObjectParameterType(); 420*5f757f3fSDimitry Andric setThisPointeeStorageLocation( 421*5f757f3fSDimitry Andric cast<RecordValue>(createValue(ThisPointeeType))->getLoc()); 422*5f757f3fSDimitry Andric } 423*5f757f3fSDimitry Andric } 424*5f757f3fSDimitry Andric } 425*5f757f3fSDimitry Andric 426bdd1243dSDimitry Andric // FIXME: Add support for resetting globals after function calls to enable 427bdd1243dSDimitry Andric // the implementation of sound analyses. 42806c3fb27SDimitry Andric void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) { 42906c3fb27SDimitry Andric assert(FuncDecl->getBody() != nullptr); 43006c3fb27SDimitry Andric 43106c3fb27SDimitry Andric FieldSet Fields; 43206c3fb27SDimitry Andric llvm::DenseSet<const VarDecl *> Vars; 43306c3fb27SDimitry Andric llvm::DenseSet<const FunctionDecl *> Funcs; 43406c3fb27SDimitry Andric 43506c3fb27SDimitry Andric // Look for global variable and field references in the 43606c3fb27SDimitry Andric // constructor-initializers. 43706c3fb27SDimitry Andric if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FuncDecl)) { 43806c3fb27SDimitry Andric for (const auto *Init : CtorDecl->inits()) { 43906c3fb27SDimitry Andric if (Init->isMemberInitializer()) { 44006c3fb27SDimitry Andric Fields.insert(Init->getMember()); 44106c3fb27SDimitry Andric } else if (Init->isIndirectMemberInitializer()) { 44206c3fb27SDimitry Andric for (const auto *I : Init->getIndirectMember()->chain()) 44306c3fb27SDimitry Andric Fields.insert(cast<FieldDecl>(I)); 44406c3fb27SDimitry Andric } 44506c3fb27SDimitry Andric const Expr *E = Init->getInit(); 44606c3fb27SDimitry Andric assert(E != nullptr); 44706c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs); 44806c3fb27SDimitry Andric } 44906c3fb27SDimitry Andric // Add all fields mentioned in default member initializers. 45006c3fb27SDimitry Andric for (const FieldDecl *F : CtorDecl->getParent()->fields()) 45106c3fb27SDimitry Andric if (const auto *I = F->getInClassInitializer()) 45206c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*I, Fields, Vars, Funcs); 45306c3fb27SDimitry Andric } 45406c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*FuncDecl->getBody(), Fields, Vars, Funcs); 45506c3fb27SDimitry Andric 45606c3fb27SDimitry Andric // These have to be added before the lines that follow to ensure that 45706c3fb27SDimitry Andric // `create*` work correctly for structs. 45806c3fb27SDimitry Andric DACtx->addModeledFields(Fields); 45906c3fb27SDimitry Andric 460bdd1243dSDimitry Andric for (const VarDecl *D : Vars) { 46106c3fb27SDimitry Andric if (getStorageLocation(*D) != nullptr) 462bdd1243dSDimitry Andric continue; 46306c3fb27SDimitry Andric 46406c3fb27SDimitry Andric setStorageLocation(*D, createObject(*D)); 46506c3fb27SDimitry Andric } 46606c3fb27SDimitry Andric 46706c3fb27SDimitry Andric for (const FunctionDecl *FD : Funcs) { 46806c3fb27SDimitry Andric if (getStorageLocation(*FD) != nullptr) 46906c3fb27SDimitry Andric continue; 47006c3fb27SDimitry Andric auto &Loc = createStorageLocation(FD->getType()); 47106c3fb27SDimitry Andric setStorageLocation(*FD, Loc); 47281ad6265SDimitry Andric } 47381ad6265SDimitry Andric } 47481ad6265SDimitry Andric 47506c3fb27SDimitry Andric Environment Environment::fork() const { 47606c3fb27SDimitry Andric Environment Copy(*this); 47706c3fb27SDimitry Andric Copy.FlowConditionToken = DACtx->forkFlowCondition(FlowConditionToken); 47806c3fb27SDimitry Andric return Copy; 4791fd87a68SDimitry Andric } 4801fd87a68SDimitry Andric 481bdd1243dSDimitry Andric bool Environment::canDescend(unsigned MaxDepth, 482bdd1243dSDimitry Andric const DeclContext *Callee) const { 483bdd1243dSDimitry Andric return CallStack.size() <= MaxDepth && !llvm::is_contained(CallStack, Callee); 48404eeddc0SDimitry Andric } 48504eeddc0SDimitry Andric 486972a253aSDimitry Andric Environment Environment::pushCall(const CallExpr *Call) const { 487972a253aSDimitry Andric Environment Env(*this); 488972a253aSDimitry Andric 489bdd1243dSDimitry Andric if (const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(Call)) { 490bdd1243dSDimitry Andric if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) { 491bdd1243dSDimitry Andric if (!isa<CXXThisExpr>(Arg)) 492*5f757f3fSDimitry Andric Env.ThisPointeeLoc = 493*5f757f3fSDimitry Andric cast<RecordStorageLocation>(getStorageLocation(*Arg)); 494bdd1243dSDimitry Andric // Otherwise (when the argument is `this`), retain the current 495bdd1243dSDimitry Andric // environment's `ThisPointeeLoc`. 496bdd1243dSDimitry Andric } 497bdd1243dSDimitry Andric } 498972a253aSDimitry Andric 499bdd1243dSDimitry Andric Env.pushCallInternal(Call->getDirectCallee(), 500bdd1243dSDimitry Andric llvm::ArrayRef(Call->getArgs(), Call->getNumArgs())); 501bdd1243dSDimitry Andric 502bdd1243dSDimitry Andric return Env; 503bdd1243dSDimitry Andric } 504bdd1243dSDimitry Andric 505bdd1243dSDimitry Andric Environment Environment::pushCall(const CXXConstructExpr *Call) const { 506bdd1243dSDimitry Andric Environment Env(*this); 507bdd1243dSDimitry Andric 50806c3fb27SDimitry Andric Env.ThisPointeeLoc = &Env.getResultObjectLocation(*Call); 509bdd1243dSDimitry Andric 510bdd1243dSDimitry Andric Env.pushCallInternal(Call->getConstructor(), 511bdd1243dSDimitry Andric llvm::ArrayRef(Call->getArgs(), Call->getNumArgs())); 512bdd1243dSDimitry Andric 513bdd1243dSDimitry Andric return Env; 514bdd1243dSDimitry Andric } 515bdd1243dSDimitry Andric 516bdd1243dSDimitry Andric void Environment::pushCallInternal(const FunctionDecl *FuncDecl, 517bdd1243dSDimitry Andric ArrayRef<const Expr *> Args) { 51806c3fb27SDimitry Andric // Canonicalize to the definition of the function. This ensures that we're 51906c3fb27SDimitry Andric // putting arguments into the same `ParamVarDecl`s` that the callee will later 52006c3fb27SDimitry Andric // be retrieving them from. 52106c3fb27SDimitry Andric assert(FuncDecl->getDefinition() != nullptr); 52206c3fb27SDimitry Andric FuncDecl = FuncDecl->getDefinition(); 52306c3fb27SDimitry Andric 524bdd1243dSDimitry Andric CallStack.push_back(FuncDecl); 525bdd1243dSDimitry Andric 52606c3fb27SDimitry Andric initFieldsGlobalsAndFuncs(FuncDecl); 527bdd1243dSDimitry Andric 528bdd1243dSDimitry Andric const auto *ParamIt = FuncDecl->param_begin(); 529972a253aSDimitry Andric 530972a253aSDimitry Andric // FIXME: Parameters don't always map to arguments 1:1; examples include 531972a253aSDimitry Andric // overloaded operators implemented as member functions, and parameter packs. 532bdd1243dSDimitry Andric for (unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) { 533972a253aSDimitry Andric assert(ParamIt != FuncDecl->param_end()); 534972a253aSDimitry Andric const VarDecl *Param = *ParamIt; 53506c3fb27SDimitry Andric setStorageLocation(*Param, createObject(*Param, Args[ArgIndex])); 536bdd1243dSDimitry Andric } 537972a253aSDimitry Andric } 538972a253aSDimitry Andric 53906c3fb27SDimitry Andric void Environment::popCall(const CallExpr *Call, const Environment &CalleeEnv) { 540*5f757f3fSDimitry Andric // We ignore some entries of `CalleeEnv`: 541*5f757f3fSDimitry Andric // - `DACtx` because is already the same in both 542*5f757f3fSDimitry Andric // - We don't want the callee's `DeclCtx`, `ReturnVal`, `ReturnLoc` or 543*5f757f3fSDimitry Andric // `ThisPointeeLoc` because they don't apply to us. 544*5f757f3fSDimitry Andric // - `DeclToLoc`, `ExprToLoc`, and `ExprToVal` capture information from the 545*5f757f3fSDimitry Andric // callee's local scope, so when popping that scope, we do not propagate 546*5f757f3fSDimitry Andric // the maps. 547bdd1243dSDimitry Andric this->LocToVal = std::move(CalleeEnv.LocToVal); 548bdd1243dSDimitry Andric this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken); 54906c3fb27SDimitry Andric 55006c3fb27SDimitry Andric if (Call->isGLValue()) { 55106c3fb27SDimitry Andric if (CalleeEnv.ReturnLoc != nullptr) 552*5f757f3fSDimitry Andric setStorageLocation(*Call, *CalleeEnv.ReturnLoc); 55306c3fb27SDimitry Andric } else if (!Call->getType()->isVoidType()) { 55406c3fb27SDimitry Andric if (CalleeEnv.ReturnVal != nullptr) 555*5f757f3fSDimitry Andric setValue(*Call, *CalleeEnv.ReturnVal); 55606c3fb27SDimitry Andric } 55706c3fb27SDimitry Andric } 55806c3fb27SDimitry Andric 55906c3fb27SDimitry Andric void Environment::popCall(const CXXConstructExpr *Call, 56006c3fb27SDimitry Andric const Environment &CalleeEnv) { 56106c3fb27SDimitry Andric // See also comment in `popCall(const CallExpr *, const Environment &)` above. 56206c3fb27SDimitry Andric this->LocToVal = std::move(CalleeEnv.LocToVal); 56306c3fb27SDimitry Andric this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken); 56406c3fb27SDimitry Andric 56506c3fb27SDimitry Andric if (Value *Val = CalleeEnv.getValue(*CalleeEnv.ThisPointeeLoc)) { 566*5f757f3fSDimitry Andric setValue(*Call, *Val); 56706c3fb27SDimitry Andric } 568972a253aSDimitry Andric } 569972a253aSDimitry Andric 5701fd87a68SDimitry Andric bool Environment::equivalentTo(const Environment &Other, 5711fd87a68SDimitry Andric Environment::ValueModel &Model) const { 57204eeddc0SDimitry Andric assert(DACtx == Other.DACtx); 5731fd87a68SDimitry Andric 57406c3fb27SDimitry Andric if (ReturnVal != Other.ReturnVal) 57506c3fb27SDimitry Andric return false; 57606c3fb27SDimitry Andric 577bdd1243dSDimitry Andric if (ReturnLoc != Other.ReturnLoc) 578bdd1243dSDimitry Andric return false; 579bdd1243dSDimitry Andric 580bdd1243dSDimitry Andric if (ThisPointeeLoc != Other.ThisPointeeLoc) 581bdd1243dSDimitry Andric return false; 582bdd1243dSDimitry Andric 5831fd87a68SDimitry Andric if (DeclToLoc != Other.DeclToLoc) 5841fd87a68SDimitry Andric return false; 5851fd87a68SDimitry Andric 5861fd87a68SDimitry Andric if (ExprToLoc != Other.ExprToLoc) 5871fd87a68SDimitry Andric return false; 5881fd87a68SDimitry Andric 589*5f757f3fSDimitry Andric if (!compareKeyToValueMaps(ExprToVal, Other.ExprToVal, *this, Other, Model)) 5901fd87a68SDimitry Andric return false; 591*5f757f3fSDimitry Andric 592*5f757f3fSDimitry Andric if (!compareKeyToValueMaps(LocToVal, Other.LocToVal, *this, Other, Model)) 593*5f757f3fSDimitry Andric return false; 5941fd87a68SDimitry Andric 5951fd87a68SDimitry Andric return true; 59604eeddc0SDimitry Andric } 59704eeddc0SDimitry Andric 598bdd1243dSDimitry Andric LatticeJoinEffect Environment::widen(const Environment &PrevEnv, 599bdd1243dSDimitry Andric Environment::ValueModel &Model) { 600bdd1243dSDimitry Andric assert(DACtx == PrevEnv.DACtx); 60106c3fb27SDimitry Andric assert(ReturnVal == PrevEnv.ReturnVal); 602bdd1243dSDimitry Andric assert(ReturnLoc == PrevEnv.ReturnLoc); 603bdd1243dSDimitry Andric assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc); 604bdd1243dSDimitry Andric assert(CallStack == PrevEnv.CallStack); 605bdd1243dSDimitry Andric 606bdd1243dSDimitry Andric auto Effect = LatticeJoinEffect::Unchanged; 607bdd1243dSDimitry Andric 608bdd1243dSDimitry Andric // By the API, `PrevEnv` is a previous version of the environment for the same 609bdd1243dSDimitry Andric // block, so we have some guarantees about its shape. In particular, it will 610bdd1243dSDimitry Andric // be the result of a join or widen operation on previous values for this 611*5f757f3fSDimitry Andric // block. For `DeclToLoc`, `ExprToVal`, and `ExprToLoc`, join guarantees that 612*5f757f3fSDimitry Andric // these maps are subsets of the maps in `PrevEnv`. So, as long as we maintain 613*5f757f3fSDimitry Andric // this property here, we don't need change their current values to widen. 614bdd1243dSDimitry Andric assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size()); 615*5f757f3fSDimitry Andric assert(ExprToVal.size() <= PrevEnv.ExprToVal.size()); 616bdd1243dSDimitry Andric assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size()); 617bdd1243dSDimitry Andric 618*5f757f3fSDimitry Andric ExprToVal = widenKeyToValueMap(ExprToVal, PrevEnv.ExprToVal, *this, PrevEnv, 619*5f757f3fSDimitry Andric Model, Effect); 620bdd1243dSDimitry Andric 621*5f757f3fSDimitry Andric LocToVal = widenKeyToValueMap(LocToVal, PrevEnv.LocToVal, *this, PrevEnv, 622*5f757f3fSDimitry Andric Model, Effect); 623bdd1243dSDimitry Andric if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() || 624bdd1243dSDimitry Andric ExprToLoc.size() != PrevEnv.ExprToLoc.size() || 625*5f757f3fSDimitry Andric ExprToVal.size() != PrevEnv.ExprToVal.size() || 62606c3fb27SDimitry Andric LocToVal.size() != PrevEnv.LocToVal.size()) 627bdd1243dSDimitry Andric Effect = LatticeJoinEffect::Changed; 628bdd1243dSDimitry Andric 629bdd1243dSDimitry Andric return Effect; 630bdd1243dSDimitry Andric } 631bdd1243dSDimitry Andric 63206c3fb27SDimitry Andric Environment Environment::join(const Environment &EnvA, const Environment &EnvB, 6331fd87a68SDimitry Andric Environment::ValueModel &Model) { 63406c3fb27SDimitry Andric assert(EnvA.DACtx == EnvB.DACtx); 63506c3fb27SDimitry Andric assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc); 63606c3fb27SDimitry Andric assert(EnvA.CallStack == EnvB.CallStack); 63704eeddc0SDimitry Andric 63806c3fb27SDimitry Andric Environment JoinedEnv(*EnvA.DACtx); 63904eeddc0SDimitry Andric 64006c3fb27SDimitry Andric JoinedEnv.CallStack = EnvA.CallStack; 64106c3fb27SDimitry Andric JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc; 64281ad6265SDimitry Andric 64306c3fb27SDimitry Andric if (EnvA.ReturnVal == nullptr || EnvB.ReturnVal == nullptr) { 64406c3fb27SDimitry Andric // `ReturnVal` might not always get set -- for example if we have a return 64506c3fb27SDimitry Andric // statement of the form `return some_other_func()` and we decide not to 64606c3fb27SDimitry Andric // analyze `some_other_func()`. 64706c3fb27SDimitry Andric // In this case, we can't say anything about the joined return value -- we 64806c3fb27SDimitry Andric // don't simply want to propagate the return value that we do have, because 64906c3fb27SDimitry Andric // it might not be the correct one. 65006c3fb27SDimitry Andric // This occurs for example in the test `ContextSensitiveMutualRecursion`. 65106c3fb27SDimitry Andric JoinedEnv.ReturnVal = nullptr; 65206c3fb27SDimitry Andric } else if (areEquivalentValues(*EnvA.ReturnVal, *EnvB.ReturnVal)) { 65306c3fb27SDimitry Andric JoinedEnv.ReturnVal = EnvA.ReturnVal; 65406c3fb27SDimitry Andric } else { 65506c3fb27SDimitry Andric assert(!EnvA.CallStack.empty()); 65606c3fb27SDimitry Andric // FIXME: Make `CallStack` a vector of `FunctionDecl` so we don't need this 65706c3fb27SDimitry Andric // cast. 65806c3fb27SDimitry Andric auto *Func = dyn_cast<FunctionDecl>(EnvA.CallStack.back()); 65906c3fb27SDimitry Andric assert(Func != nullptr); 66006c3fb27SDimitry Andric if (Value *MergedVal = 66106c3fb27SDimitry Andric mergeDistinctValues(Func->getReturnType(), *EnvA.ReturnVal, EnvA, 66206c3fb27SDimitry Andric *EnvB.ReturnVal, EnvB, JoinedEnv, Model)) 66306c3fb27SDimitry Andric JoinedEnv.ReturnVal = MergedVal; 66406c3fb27SDimitry Andric } 665bdd1243dSDimitry Andric 66606c3fb27SDimitry Andric if (EnvA.ReturnLoc == EnvB.ReturnLoc) 66706c3fb27SDimitry Andric JoinedEnv.ReturnLoc = EnvA.ReturnLoc; 66806c3fb27SDimitry Andric else 66906c3fb27SDimitry Andric JoinedEnv.ReturnLoc = nullptr; 67004eeddc0SDimitry Andric 671*5f757f3fSDimitry Andric JoinedEnv.DeclToLoc = intersectDeclToLoc(EnvA.DeclToLoc, EnvB.DeclToLoc); 67281ad6265SDimitry Andric 673bdd1243dSDimitry Andric // FIXME: update join to detect backedges and simplify the flow condition 674bdd1243dSDimitry Andric // accordingly. 67506c3fb27SDimitry Andric JoinedEnv.FlowConditionToken = EnvA.DACtx->joinFlowConditions( 67606c3fb27SDimitry Andric EnvA.FlowConditionToken, EnvB.FlowConditionToken); 67781ad6265SDimitry Andric 678*5f757f3fSDimitry Andric JoinedEnv.LocToVal = 679*5f757f3fSDimitry Andric joinLocToVal(EnvA.LocToVal, EnvB.LocToVal, EnvA, EnvB, JoinedEnv, Model); 68004eeddc0SDimitry Andric 681*5f757f3fSDimitry Andric // We intentionally leave `JoinedEnv.ExprToLoc` and `JoinedEnv.ExprToVal` 682*5f757f3fSDimitry Andric // empty, as we never need to access entries in these maps outside of the 683*5f757f3fSDimitry Andric // basic block that sets them. 68404eeddc0SDimitry Andric 68506c3fb27SDimitry Andric return JoinedEnv; 68604eeddc0SDimitry Andric } 68704eeddc0SDimitry Andric 68804eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(QualType Type) { 689bdd1243dSDimitry Andric return DACtx->createStorageLocation(Type); 69004eeddc0SDimitry Andric } 69104eeddc0SDimitry Andric 692*5f757f3fSDimitry Andric StorageLocation &Environment::createStorageLocation(const ValueDecl &D) { 69304eeddc0SDimitry Andric // Evaluated declarations are always assigned the same storage locations to 69404eeddc0SDimitry Andric // ensure that the environment stabilizes across loop iterations. Storage 69504eeddc0SDimitry Andric // locations for evaluated declarations are stored in the analysis context. 69681ad6265SDimitry Andric return DACtx->getStableStorageLocation(D); 69704eeddc0SDimitry Andric } 69804eeddc0SDimitry Andric 69904eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const Expr &E) { 70004eeddc0SDimitry Andric // Evaluated expressions are always assigned the same storage locations to 70104eeddc0SDimitry Andric // ensure that the environment stabilizes across loop iterations. Storage 70204eeddc0SDimitry Andric // locations for evaluated expressions are stored in the analysis context. 70381ad6265SDimitry Andric return DACtx->getStableStorageLocation(E); 70404eeddc0SDimitry Andric } 70504eeddc0SDimitry Andric 70604eeddc0SDimitry Andric void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) { 70706c3fb27SDimitry Andric assert(!DeclToLoc.contains(&D)); 70804eeddc0SDimitry Andric DeclToLoc[&D] = &Loc; 70904eeddc0SDimitry Andric } 71004eeddc0SDimitry Andric 71106c3fb27SDimitry Andric StorageLocation *Environment::getStorageLocation(const ValueDecl &D) const { 71204eeddc0SDimitry Andric auto It = DeclToLoc.find(&D); 71306c3fb27SDimitry Andric if (It == DeclToLoc.end()) 71406c3fb27SDimitry Andric return nullptr; 71506c3fb27SDimitry Andric 71606c3fb27SDimitry Andric StorageLocation *Loc = It->second; 71706c3fb27SDimitry Andric 71806c3fb27SDimitry Andric return Loc; 71904eeddc0SDimitry Andric } 72004eeddc0SDimitry Andric 721*5f757f3fSDimitry Andric void Environment::removeDecl(const ValueDecl &D) { DeclToLoc.erase(&D); } 72204eeddc0SDimitry Andric 723*5f757f3fSDimitry Andric void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) { 72406c3fb27SDimitry Andric // `DeclRefExpr`s to builtin function types aren't glvalues, for some reason, 72506c3fb27SDimitry Andric // but we still want to be able to associate a `StorageLocation` with them, 72606c3fb27SDimitry Andric // so allow these as an exception. 72706c3fb27SDimitry Andric assert(E.isGLValue() || 72806c3fb27SDimitry Andric E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn)); 729*5f757f3fSDimitry Andric setStorageLocationInternal(E, Loc); 73006c3fb27SDimitry Andric } 73106c3fb27SDimitry Andric 732*5f757f3fSDimitry Andric StorageLocation *Environment::getStorageLocation(const Expr &E) const { 733*5f757f3fSDimitry Andric // See comment in `setStorageLocation()`. 73406c3fb27SDimitry Andric assert(E.isGLValue() || 73506c3fb27SDimitry Andric E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn)); 736*5f757f3fSDimitry Andric return getStorageLocationInternal(E); 73706c3fb27SDimitry Andric } 73806c3fb27SDimitry Andric 739*5f757f3fSDimitry Andric RecordStorageLocation & 74006c3fb27SDimitry Andric Environment::getResultObjectLocation(const Expr &RecordPRValue) { 74106c3fb27SDimitry Andric assert(RecordPRValue.getType()->isRecordType()); 74206c3fb27SDimitry Andric assert(RecordPRValue.isPRValue()); 74306c3fb27SDimitry Andric 744*5f757f3fSDimitry Andric if (StorageLocation *ExistingLoc = getStorageLocationInternal(RecordPRValue)) 745*5f757f3fSDimitry Andric return *cast<RecordStorageLocation>(ExistingLoc); 746*5f757f3fSDimitry Andric auto &Loc = cast<RecordStorageLocation>( 74706c3fb27SDimitry Andric DACtx->getStableStorageLocation(RecordPRValue)); 748*5f757f3fSDimitry Andric setStorageLocationInternal(RecordPRValue, Loc); 74906c3fb27SDimitry Andric return Loc; 75004eeddc0SDimitry Andric } 75104eeddc0SDimitry Andric 75281ad6265SDimitry Andric PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) { 75381ad6265SDimitry Andric return DACtx->getOrCreateNullPointerValue(PointeeType); 75481ad6265SDimitry Andric } 75581ad6265SDimitry Andric 75604eeddc0SDimitry Andric void Environment::setValue(const StorageLocation &Loc, Value &Val) { 757*5f757f3fSDimitry Andric assert(!isa<RecordValue>(&Val) || &cast<RecordValue>(&Val)->getLoc() == &Loc); 75806c3fb27SDimitry Andric 75904eeddc0SDimitry Andric LocToVal[&Loc] = &Val; 76006c3fb27SDimitry Andric } 76106c3fb27SDimitry Andric 762*5f757f3fSDimitry Andric void Environment::setValue(const Expr &E, Value &Val) { 76306c3fb27SDimitry Andric assert(E.isPRValue()); 764*5f757f3fSDimitry Andric ExprToVal[&E] = &Val; 76504eeddc0SDimitry Andric } 76604eeddc0SDimitry Andric 76704eeddc0SDimitry Andric Value *Environment::getValue(const StorageLocation &Loc) const { 76806c3fb27SDimitry Andric return LocToVal.lookup(&Loc); 76904eeddc0SDimitry Andric } 77004eeddc0SDimitry Andric 77106c3fb27SDimitry Andric Value *Environment::getValue(const ValueDecl &D) const { 77206c3fb27SDimitry Andric auto *Loc = getStorageLocation(D); 77304eeddc0SDimitry Andric if (Loc == nullptr) 77404eeddc0SDimitry Andric return nullptr; 77504eeddc0SDimitry Andric return getValue(*Loc); 77604eeddc0SDimitry Andric } 77704eeddc0SDimitry Andric 778*5f757f3fSDimitry Andric Value *Environment::getValue(const Expr &E) const { 779*5f757f3fSDimitry Andric if (E.isPRValue()) { 780*5f757f3fSDimitry Andric auto It = ExprToVal.find(&ignoreCFGOmittedNodes(E)); 781*5f757f3fSDimitry Andric return It == ExprToVal.end() ? nullptr : It->second; 78204eeddc0SDimitry Andric } 78304eeddc0SDimitry Andric 784*5f757f3fSDimitry Andric auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E)); 785*5f757f3fSDimitry Andric if (It == ExprToLoc.end()) 786*5f757f3fSDimitry Andric return nullptr; 787*5f757f3fSDimitry Andric return getValue(*It->second); 78806c3fb27SDimitry Andric } 78906c3fb27SDimitry Andric 79004eeddc0SDimitry Andric Value *Environment::createValue(QualType Type) { 79104eeddc0SDimitry Andric llvm::DenseSet<QualType> Visited; 79281ad6265SDimitry Andric int CreatedValuesCount = 0; 79381ad6265SDimitry Andric Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0, 79481ad6265SDimitry Andric CreatedValuesCount); 79581ad6265SDimitry Andric if (CreatedValuesCount > MaxCompositeValueSize) { 79681ad6265SDimitry Andric llvm::errs() << "Attempting to initialize a huge value of type: " << Type 79781ad6265SDimitry Andric << '\n'; 79881ad6265SDimitry Andric } 79981ad6265SDimitry Andric return Val; 80004eeddc0SDimitry Andric } 80104eeddc0SDimitry Andric 802*5f757f3fSDimitry Andric void Environment::setStorageLocationInternal(const Expr &E, 803*5f757f3fSDimitry Andric StorageLocation &Loc) { 804*5f757f3fSDimitry Andric const Expr &CanonE = ignoreCFGOmittedNodes(E); 805*5f757f3fSDimitry Andric assert(!ExprToLoc.contains(&CanonE)); 806*5f757f3fSDimitry Andric ExprToLoc[&CanonE] = &Loc; 807*5f757f3fSDimitry Andric } 808*5f757f3fSDimitry Andric 809*5f757f3fSDimitry Andric StorageLocation *Environment::getStorageLocationInternal(const Expr &E) const { 810*5f757f3fSDimitry Andric auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E)); 811*5f757f3fSDimitry Andric return It == ExprToLoc.end() ? nullptr : &*It->second; 812*5f757f3fSDimitry Andric } 813*5f757f3fSDimitry Andric 81404eeddc0SDimitry Andric Value *Environment::createValueUnlessSelfReferential( 81581ad6265SDimitry Andric QualType Type, llvm::DenseSet<QualType> &Visited, int Depth, 81681ad6265SDimitry Andric int &CreatedValuesCount) { 81704eeddc0SDimitry Andric assert(!Type.isNull()); 818*5f757f3fSDimitry Andric assert(!Type->isReferenceType()); 81904eeddc0SDimitry Andric 82081ad6265SDimitry Andric // Allow unlimited fields at depth 1; only cap at deeper nesting levels. 82181ad6265SDimitry Andric if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) || 82281ad6265SDimitry Andric Depth > MaxCompositeValueDepth) 82381ad6265SDimitry Andric return nullptr; 82481ad6265SDimitry Andric 82581ad6265SDimitry Andric if (Type->isBooleanType()) { 82681ad6265SDimitry Andric CreatedValuesCount++; 82781ad6265SDimitry Andric return &makeAtomicBoolValue(); 82881ad6265SDimitry Andric } 82981ad6265SDimitry Andric 83004eeddc0SDimitry Andric if (Type->isIntegerType()) { 831bdd1243dSDimitry Andric // FIXME: consider instead `return nullptr`, given that we do nothing useful 832bdd1243dSDimitry Andric // with integers, and so distinguishing them serves no purpose, but could 833bdd1243dSDimitry Andric // prevent convergence. 83481ad6265SDimitry Andric CreatedValuesCount++; 83506c3fb27SDimitry Andric return &arena().create<IntegerValue>(); 83604eeddc0SDimitry Andric } 83704eeddc0SDimitry Andric 838*5f757f3fSDimitry Andric if (Type->isPointerType()) { 83981ad6265SDimitry Andric CreatedValuesCount++; 84006c3fb27SDimitry Andric QualType PointeeType = Type->getPointeeType(); 84106c3fb27SDimitry Andric StorageLocation &PointeeLoc = 84206c3fb27SDimitry Andric createLocAndMaybeValue(PointeeType, Visited, Depth, CreatedValuesCount); 84304eeddc0SDimitry Andric 84406c3fb27SDimitry Andric return &arena().create<PointerValue>(PointeeLoc); 84504eeddc0SDimitry Andric } 84604eeddc0SDimitry Andric 84706c3fb27SDimitry Andric if (Type->isRecordType()) { 84881ad6265SDimitry Andric CreatedValuesCount++; 84906c3fb27SDimitry Andric llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs; 85006c3fb27SDimitry Andric for (const FieldDecl *Field : DACtx->getModeledFields(Type)) { 85104eeddc0SDimitry Andric assert(Field != nullptr); 85204eeddc0SDimitry Andric 85304eeddc0SDimitry Andric QualType FieldType = Field->getType(); 85404eeddc0SDimitry Andric 85506c3fb27SDimitry Andric FieldLocs.insert( 85606c3fb27SDimitry Andric {Field, &createLocAndMaybeValue(FieldType, Visited, Depth + 1, 85706c3fb27SDimitry Andric CreatedValuesCount)}); 85804eeddc0SDimitry Andric } 85904eeddc0SDimitry Andric 860*5f757f3fSDimitry Andric RecordStorageLocation::SyntheticFieldMap SyntheticFieldLocs; 861*5f757f3fSDimitry Andric for (const auto &Entry : DACtx->getSyntheticFields(Type)) { 862*5f757f3fSDimitry Andric SyntheticFieldLocs.insert( 863*5f757f3fSDimitry Andric {Entry.getKey(), 864*5f757f3fSDimitry Andric &createLocAndMaybeValue(Entry.getValue(), Visited, Depth + 1, 865*5f757f3fSDimitry Andric CreatedValuesCount)}); 866*5f757f3fSDimitry Andric } 86706c3fb27SDimitry Andric 868*5f757f3fSDimitry Andric RecordStorageLocation &Loc = DACtx->createRecordStorageLocation( 869*5f757f3fSDimitry Andric Type, std::move(FieldLocs), std::move(SyntheticFieldLocs)); 870*5f757f3fSDimitry Andric RecordValue &RecordVal = create<RecordValue>(Loc); 871*5f757f3fSDimitry Andric 872*5f757f3fSDimitry Andric // As we already have a storage location for the `RecordValue`, we can and 87306c3fb27SDimitry Andric // should associate them in the environment. 874*5f757f3fSDimitry Andric setValue(Loc, RecordVal); 87506c3fb27SDimitry Andric 876*5f757f3fSDimitry Andric return &RecordVal; 87704eeddc0SDimitry Andric } 87804eeddc0SDimitry Andric 87904eeddc0SDimitry Andric return nullptr; 88004eeddc0SDimitry Andric } 88104eeddc0SDimitry Andric 88206c3fb27SDimitry Andric StorageLocation & 88306c3fb27SDimitry Andric Environment::createLocAndMaybeValue(QualType Ty, 88406c3fb27SDimitry Andric llvm::DenseSet<QualType> &Visited, 88506c3fb27SDimitry Andric int Depth, int &CreatedValuesCount) { 88606c3fb27SDimitry Andric if (!Visited.insert(Ty.getCanonicalType()).second) 88706c3fb27SDimitry Andric return createStorageLocation(Ty.getNonReferenceType()); 88806c3fb27SDimitry Andric Value *Val = createValueUnlessSelfReferential( 88906c3fb27SDimitry Andric Ty.getNonReferenceType(), Visited, Depth, CreatedValuesCount); 89006c3fb27SDimitry Andric Visited.erase(Ty.getCanonicalType()); 89106c3fb27SDimitry Andric 89206c3fb27SDimitry Andric Ty = Ty.getNonReferenceType(); 89306c3fb27SDimitry Andric 89406c3fb27SDimitry Andric if (Val == nullptr) 89506c3fb27SDimitry Andric return createStorageLocation(Ty); 89606c3fb27SDimitry Andric 89706c3fb27SDimitry Andric if (Ty->isRecordType()) 898*5f757f3fSDimitry Andric return cast<RecordValue>(Val)->getLoc(); 89906c3fb27SDimitry Andric 90006c3fb27SDimitry Andric StorageLocation &Loc = createStorageLocation(Ty); 90106c3fb27SDimitry Andric setValue(Loc, *Val); 90206c3fb27SDimitry Andric return Loc; 90306c3fb27SDimitry Andric } 90406c3fb27SDimitry Andric 905*5f757f3fSDimitry Andric StorageLocation &Environment::createObjectInternal(const ValueDecl *D, 90606c3fb27SDimitry Andric QualType Ty, 90706c3fb27SDimitry Andric const Expr *InitExpr) { 90806c3fb27SDimitry Andric if (Ty->isReferenceType()) { 90906c3fb27SDimitry Andric // Although variables of reference type always need to be initialized, it 91006c3fb27SDimitry Andric // can happen that we can't see the initializer, so `InitExpr` may still 91106c3fb27SDimitry Andric // be null. 91206c3fb27SDimitry Andric if (InitExpr) { 913*5f757f3fSDimitry Andric if (auto *InitExprLoc = getStorageLocation(*InitExpr)) 91406c3fb27SDimitry Andric return *InitExprLoc; 91506c3fb27SDimitry Andric } 91606c3fb27SDimitry Andric 91706c3fb27SDimitry Andric // Even though we have an initializer, we might not get an 91806c3fb27SDimitry Andric // InitExprLoc, for example if the InitExpr is a CallExpr for which we 91906c3fb27SDimitry Andric // don't have a function body. In this case, we just invent a storage 92006c3fb27SDimitry Andric // location and value -- it's the best we can do. 92106c3fb27SDimitry Andric return createObjectInternal(D, Ty.getNonReferenceType(), nullptr); 92206c3fb27SDimitry Andric } 92306c3fb27SDimitry Andric 92406c3fb27SDimitry Andric Value *Val = nullptr; 92506c3fb27SDimitry Andric if (InitExpr) 92606c3fb27SDimitry Andric // In the (few) cases where an expression is intentionally 92706c3fb27SDimitry Andric // "uninterpreted", `InitExpr` is not associated with a value. There are 92806c3fb27SDimitry Andric // two ways to handle this situation: propagate the status, so that 92906c3fb27SDimitry Andric // uninterpreted initializers result in uninterpreted variables, or 93006c3fb27SDimitry Andric // provide a default value. We choose the latter so that later refinements 93106c3fb27SDimitry Andric // of the variable can be used for reasoning about the surrounding code. 93206c3fb27SDimitry Andric // For this reason, we let this case be handled by the `createValue()` 93306c3fb27SDimitry Andric // call below. 93406c3fb27SDimitry Andric // 93506c3fb27SDimitry Andric // FIXME. If and when we interpret all language cases, change this to 93606c3fb27SDimitry Andric // assert that `InitExpr` is interpreted, rather than supplying a 93706c3fb27SDimitry Andric // default value (assuming we don't update the environment API to return 93806c3fb27SDimitry Andric // references). 939*5f757f3fSDimitry Andric Val = getValue(*InitExpr); 94006c3fb27SDimitry Andric if (!Val) 94106c3fb27SDimitry Andric Val = createValue(Ty); 94206c3fb27SDimitry Andric 94306c3fb27SDimitry Andric if (Ty->isRecordType()) 944*5f757f3fSDimitry Andric return cast<RecordValue>(Val)->getLoc(); 94506c3fb27SDimitry Andric 94606c3fb27SDimitry Andric StorageLocation &Loc = 94706c3fb27SDimitry Andric D ? createStorageLocation(*D) : createStorageLocation(Ty); 94806c3fb27SDimitry Andric 94906c3fb27SDimitry Andric if (Val) 95006c3fb27SDimitry Andric setValue(Loc, *Val); 95106c3fb27SDimitry Andric 95206c3fb27SDimitry Andric return Loc; 95306c3fb27SDimitry Andric } 95406c3fb27SDimitry Andric 955*5f757f3fSDimitry Andric void Environment::assume(const Formula &F) { 956*5f757f3fSDimitry Andric DACtx->addFlowConditionConstraint(FlowConditionToken, F); 95704eeddc0SDimitry Andric } 95804eeddc0SDimitry Andric 959*5f757f3fSDimitry Andric bool Environment::proves(const Formula &F) const { 960*5f757f3fSDimitry Andric return DACtx->flowConditionImplies(FlowConditionToken, F); 96104eeddc0SDimitry Andric } 96204eeddc0SDimitry Andric 963*5f757f3fSDimitry Andric bool Environment::allows(const Formula &F) const { 964*5f757f3fSDimitry Andric return DACtx->flowConditionAllows(FlowConditionToken, F); 96581ad6265SDimitry Andric } 96681ad6265SDimitry Andric 967bdd1243dSDimitry Andric void Environment::dump(raw_ostream &OS) const { 968bdd1243dSDimitry Andric // FIXME: add printing for remaining fields and allow caller to decide what 969bdd1243dSDimitry Andric // fields are printed. 970bdd1243dSDimitry Andric OS << "DeclToLoc:\n"; 971bdd1243dSDimitry Andric for (auto [D, L] : DeclToLoc) 97206c3fb27SDimitry Andric OS << " [" << D->getNameAsString() << ", " << L << "]\n"; 973bdd1243dSDimitry Andric 974bdd1243dSDimitry Andric OS << "ExprToLoc:\n"; 975bdd1243dSDimitry Andric for (auto [E, L] : ExprToLoc) 976bdd1243dSDimitry Andric OS << " [" << E << ", " << L << "]\n"; 977bdd1243dSDimitry Andric 978*5f757f3fSDimitry Andric OS << "ExprToVal:\n"; 979*5f757f3fSDimitry Andric for (auto [E, V] : ExprToVal) 980*5f757f3fSDimitry Andric OS << " [" << E << ", " << V << ": " << *V << "]\n"; 981*5f757f3fSDimitry Andric 982bdd1243dSDimitry Andric OS << "LocToVal:\n"; 983bdd1243dSDimitry Andric for (auto [L, V] : LocToVal) { 984bdd1243dSDimitry Andric OS << " [" << L << ", " << V << ": " << *V << "]\n"; 985bdd1243dSDimitry Andric } 986bdd1243dSDimitry Andric 987*5f757f3fSDimitry Andric OS << "\n"; 98806c3fb27SDimitry Andric DACtx->dumpFlowCondition(FlowConditionToken, OS); 989fcaf7f86SDimitry Andric } 990fcaf7f86SDimitry Andric 991bdd1243dSDimitry Andric void Environment::dump() const { 992bdd1243dSDimitry Andric dump(llvm::dbgs()); 993bdd1243dSDimitry Andric } 994bdd1243dSDimitry Andric 995*5f757f3fSDimitry Andric RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE, 99606c3fb27SDimitry Andric const Environment &Env) { 99706c3fb27SDimitry Andric Expr *ImplicitObject = MCE.getImplicitObjectArgument(); 99806c3fb27SDimitry Andric if (ImplicitObject == nullptr) 99906c3fb27SDimitry Andric return nullptr; 100006c3fb27SDimitry Andric if (ImplicitObject->getType()->isPointerType()) { 1001*5f757f3fSDimitry Andric if (auto *Val = cast_or_null<PointerValue>(Env.getValue(*ImplicitObject))) 1002*5f757f3fSDimitry Andric return &cast<RecordStorageLocation>(Val->getPointeeLoc()); 100306c3fb27SDimitry Andric return nullptr; 100406c3fb27SDimitry Andric } 1005*5f757f3fSDimitry Andric return cast_or_null<RecordStorageLocation>( 1006*5f757f3fSDimitry Andric Env.getStorageLocation(*ImplicitObject)); 100706c3fb27SDimitry Andric } 100806c3fb27SDimitry Andric 1009*5f757f3fSDimitry Andric RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME, 101006c3fb27SDimitry Andric const Environment &Env) { 101106c3fb27SDimitry Andric Expr *Base = ME.getBase(); 101206c3fb27SDimitry Andric if (Base == nullptr) 101306c3fb27SDimitry Andric return nullptr; 101406c3fb27SDimitry Andric if (ME.isArrow()) { 1015*5f757f3fSDimitry Andric if (auto *Val = cast_or_null<PointerValue>(Env.getValue(*Base))) 1016*5f757f3fSDimitry Andric return &cast<RecordStorageLocation>(Val->getPointeeLoc()); 101706c3fb27SDimitry Andric return nullptr; 101806c3fb27SDimitry Andric } 1019*5f757f3fSDimitry Andric return cast_or_null<RecordStorageLocation>(Env.getStorageLocation(*Base)); 102006c3fb27SDimitry Andric } 102106c3fb27SDimitry Andric 102206c3fb27SDimitry Andric std::vector<FieldDecl *> getFieldsForInitListExpr(const RecordDecl *RD) { 102306c3fb27SDimitry Andric // Unnamed bitfields are only used for padding and do not appear in 102406c3fb27SDimitry Andric // `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s 102506c3fb27SDimitry Andric // field list, and we thus need to remove them before mapping inits to 102606c3fb27SDimitry Andric // fields to avoid mapping inits to the wrongs fields. 102706c3fb27SDimitry Andric std::vector<FieldDecl *> Fields; 102806c3fb27SDimitry Andric llvm::copy_if( 102906c3fb27SDimitry Andric RD->fields(), std::back_inserter(Fields), 103006c3fb27SDimitry Andric [](const FieldDecl *Field) { return !Field->isUnnamedBitfield(); }); 103106c3fb27SDimitry Andric return Fields; 103206c3fb27SDimitry Andric } 103306c3fb27SDimitry Andric 1034*5f757f3fSDimitry Andric RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env) { 1035*5f757f3fSDimitry Andric auto &NewVal = Env.create<RecordValue>(Loc); 103606c3fb27SDimitry Andric Env.setValue(Loc, NewVal); 103706c3fb27SDimitry Andric return NewVal; 103806c3fb27SDimitry Andric } 103906c3fb27SDimitry Andric 1040*5f757f3fSDimitry Andric RecordValue &refreshRecordValue(const Expr &Expr, Environment &Env) { 104106c3fb27SDimitry Andric assert(Expr.getType()->isRecordType()); 104206c3fb27SDimitry Andric 104306c3fb27SDimitry Andric if (Expr.isPRValue()) { 1044*5f757f3fSDimitry Andric if (auto *ExistingVal = cast_or_null<RecordValue>(Env.getValue(Expr))) { 1045*5f757f3fSDimitry Andric auto &NewVal = Env.create<RecordValue>(ExistingVal->getLoc()); 1046*5f757f3fSDimitry Andric Env.setValue(Expr, NewVal); 104706c3fb27SDimitry Andric return NewVal; 104806c3fb27SDimitry Andric } 104906c3fb27SDimitry Andric 1050*5f757f3fSDimitry Andric auto &NewVal = *cast<RecordValue>(Env.createValue(Expr.getType())); 1051*5f757f3fSDimitry Andric Env.setValue(Expr, NewVal); 105206c3fb27SDimitry Andric return NewVal; 105306c3fb27SDimitry Andric } 105406c3fb27SDimitry Andric 1055*5f757f3fSDimitry Andric if (auto *Loc = 1056*5f757f3fSDimitry Andric cast_or_null<RecordStorageLocation>(Env.getStorageLocation(Expr))) { 1057*5f757f3fSDimitry Andric auto &NewVal = Env.create<RecordValue>(*Loc); 105806c3fb27SDimitry Andric Env.setValue(*Loc, NewVal); 105906c3fb27SDimitry Andric return NewVal; 106006c3fb27SDimitry Andric } 106106c3fb27SDimitry Andric 1062*5f757f3fSDimitry Andric auto &NewVal = *cast<RecordValue>(Env.createValue(Expr.getType())); 1063*5f757f3fSDimitry Andric Env.setStorageLocation(Expr, NewVal.getLoc()); 106406c3fb27SDimitry Andric return NewVal; 106506c3fb27SDimitry Andric } 106606c3fb27SDimitry Andric 106704eeddc0SDimitry Andric } // namespace dataflow 106804eeddc0SDimitry Andric } // namespace clang 1069