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"
18*0fca6ea1SDimitry Andric #include "clang/AST/ExprCXX.h"
19*0fca6ea1SDimitry Andric #include "clang/AST/RecursiveASTVisitor.h"
20*0fca6ea1SDimitry Andric #include "clang/AST/Stmt.h"
2104eeddc0SDimitry Andric #include "clang/AST/Type.h"
22*0fca6ea1SDimitry Andric #include "clang/Analysis/FlowSensitive/ASTOps.h"
23*0fca6ea1SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
2404eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
2504eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h"
2604eeddc0SDimitry Andric #include "llvm/ADT/DenseMap.h"
2704eeddc0SDimitry Andric #include "llvm/ADT/DenseSet.h"
2806c3fb27SDimitry Andric #include "llvm/ADT/MapVector.h"
29*0fca6ea1SDimitry Andric #include "llvm/ADT/PointerUnion.h"
30bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h"
31*0fca6ea1SDimitry Andric #include "llvm/ADT/ScopeExit.h"
3204eeddc0SDimitry Andric #include "llvm/Support/ErrorHandling.h"
33*0fca6ea1SDimitry Andric #include <algorithm>
3481ad6265SDimitry Andric #include <cassert>
35*0fca6ea1SDimitry Andric #include <memory>
3604eeddc0SDimitry Andric #include <utility>
3704eeddc0SDimitry Andric
38*0fca6ea1SDimitry Andric #define DEBUG_TYPE "dataflow"
39*0fca6ea1SDimitry Andric
4004eeddc0SDimitry Andric namespace clang {
4104eeddc0SDimitry Andric namespace dataflow {
4204eeddc0SDimitry Andric
4381ad6265SDimitry Andric // FIXME: convert these to parameters of the analysis or environment. Current
4481ad6265SDimitry Andric // settings have been experimentaly validated, but only for a particular
4581ad6265SDimitry Andric // analysis.
4681ad6265SDimitry Andric static constexpr int MaxCompositeValueDepth = 3;
4781ad6265SDimitry Andric static constexpr int MaxCompositeValueSize = 1000;
4881ad6265SDimitry Andric
4904eeddc0SDimitry Andric /// Returns a map consisting of key-value entries that are present in both maps.
intersectDeclToLoc(const llvm::DenseMap<const ValueDecl *,StorageLocation * > & DeclToLoc1,const llvm::DenseMap<const ValueDecl *,StorageLocation * > & DeclToLoc2)505f757f3fSDimitry Andric static llvm::DenseMap<const ValueDecl *, StorageLocation *> intersectDeclToLoc(
515f757f3fSDimitry Andric const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc1,
525f757f3fSDimitry Andric const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc2) {
535f757f3fSDimitry Andric llvm::DenseMap<const ValueDecl *, StorageLocation *> Result;
545f757f3fSDimitry Andric for (auto &Entry : DeclToLoc1) {
555f757f3fSDimitry Andric auto It = DeclToLoc2.find(Entry.first);
565f757f3fSDimitry Andric if (It != DeclToLoc2.end() && Entry.second == It->second)
5704eeddc0SDimitry Andric Result.insert({Entry.first, Entry.second});
5804eeddc0SDimitry Andric }
5904eeddc0SDimitry Andric return Result;
6004eeddc0SDimitry Andric }
6104eeddc0SDimitry Andric
62*0fca6ea1SDimitry Andric // Performs a join on either `ExprToLoc` or `ExprToVal`.
63*0fca6ea1SDimitry Andric // The maps must be consistent in the sense that any entries for the same
64*0fca6ea1SDimitry Andric // expression must map to the same location / value. This is the case if we are
65*0fca6ea1SDimitry Andric // performing a join for control flow within a full-expression (which is the
66*0fca6ea1SDimitry Andric // only case when this function should be used).
joinExprMaps(const MapT & Map1,const MapT & Map2)67*0fca6ea1SDimitry Andric template <typename MapT> MapT joinExprMaps(const MapT &Map1, const MapT &Map2) {
68*0fca6ea1SDimitry Andric MapT Result = Map1;
69*0fca6ea1SDimitry Andric
70*0fca6ea1SDimitry Andric for (const auto &Entry : Map2) {
71*0fca6ea1SDimitry Andric [[maybe_unused]] auto [It, Inserted] = Result.insert(Entry);
72*0fca6ea1SDimitry Andric // If there was an existing entry, its value should be the same as for the
73*0fca6ea1SDimitry Andric // entry we were trying to insert.
74*0fca6ea1SDimitry Andric assert(It->second == Entry.second);
75*0fca6ea1SDimitry Andric }
76*0fca6ea1SDimitry Andric
77*0fca6ea1SDimitry Andric return Result;
78*0fca6ea1SDimitry Andric }
79*0fca6ea1SDimitry Andric
805f757f3fSDimitry Andric // Whether to consider equivalent two values with an unknown relation.
815f757f3fSDimitry Andric //
825f757f3fSDimitry Andric // FIXME: this function is a hack enabling unsoundness to support
835f757f3fSDimitry Andric // convergence. Once we have widening support for the reference/pointer and
845f757f3fSDimitry Andric // struct built-in models, this should be unconditionally `false` (and inlined
855f757f3fSDimitry Andric // as such at its call sites).
equateUnknownValues(Value::Kind K)865f757f3fSDimitry Andric static bool equateUnknownValues(Value::Kind K) {
875f757f3fSDimitry Andric switch (K) {
885f757f3fSDimitry Andric case Value::Kind::Integer:
895f757f3fSDimitry Andric case Value::Kind::Pointer:
905f757f3fSDimitry Andric return true;
915f757f3fSDimitry Andric default:
925f757f3fSDimitry Andric return false;
935f757f3fSDimitry Andric }
945f757f3fSDimitry Andric }
955f757f3fSDimitry Andric
compareDistinctValues(QualType Type,Value & Val1,const Environment & Env1,Value & Val2,const Environment & Env2,Environment::ValueModel & Model)96bdd1243dSDimitry Andric static bool compareDistinctValues(QualType Type, Value &Val1,
97bdd1243dSDimitry Andric const Environment &Env1, Value &Val2,
9881ad6265SDimitry Andric const Environment &Env2,
9981ad6265SDimitry Andric Environment::ValueModel &Model) {
100bdd1243dSDimitry Andric // Note: Potentially costly, but, for booleans, we could check whether both
101bdd1243dSDimitry Andric // can be proven equivalent in their respective environments.
102bdd1243dSDimitry Andric
103bdd1243dSDimitry Andric // FIXME: move the reference/pointers logic from `areEquivalentValues` to here
104bdd1243dSDimitry Andric // and implement separate, join/widen specific handling for
105bdd1243dSDimitry Andric // reference/pointers.
106bdd1243dSDimitry Andric switch (Model.compare(Type, Val1, Env1, Val2, Env2)) {
107bdd1243dSDimitry Andric case ComparisonResult::Same:
108bdd1243dSDimitry Andric return true;
109bdd1243dSDimitry Andric case ComparisonResult::Different:
110bdd1243dSDimitry Andric return false;
111bdd1243dSDimitry Andric case ComparisonResult::Unknown:
1125f757f3fSDimitry Andric return equateUnknownValues(Val1.getKind());
113bdd1243dSDimitry Andric }
114bdd1243dSDimitry Andric llvm_unreachable("All cases covered in switch");
11581ad6265SDimitry Andric }
11681ad6265SDimitry Andric
117*0fca6ea1SDimitry Andric /// Attempts to join distinct values `Val1` and `Val2` in `Env1` and `Env2`,
118*0fca6ea1SDimitry Andric /// respectively, of the same type `Type`. Joining generally produces a single
11981ad6265SDimitry Andric /// value that (soundly) approximates the two inputs, although the actual
12081ad6265SDimitry Andric /// meaning depends on `Model`.
joinDistinctValues(QualType Type,Value & Val1,const Environment & Env1,Value & Val2,const Environment & Env2,Environment & JoinedEnv,Environment::ValueModel & Model)121*0fca6ea1SDimitry Andric static Value *joinDistinctValues(QualType Type, Value &Val1,
122bdd1243dSDimitry Andric const Environment &Env1, Value &Val2,
12381ad6265SDimitry Andric const Environment &Env2,
124*0fca6ea1SDimitry Andric Environment &JoinedEnv,
12581ad6265SDimitry Andric Environment::ValueModel &Model) {
12681ad6265SDimitry Andric // Join distinct boolean values preserving information about the constraints
12781ad6265SDimitry Andric // in the respective path conditions.
128bdd1243dSDimitry Andric if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) {
129bdd1243dSDimitry Andric // FIXME: Checking both values should be unnecessary, since they should have
130bdd1243dSDimitry Andric // a consistent shape. However, right now we can end up with BoolValue's in
131bdd1243dSDimitry Andric // integer-typed variables due to our incorrect handling of
132bdd1243dSDimitry Andric // boolean-to-integer casts (we just propagate the BoolValue to the result
133bdd1243dSDimitry Andric // of the cast). So, a join can encounter an integer in one branch but a
134bdd1243dSDimitry Andric // bool in the other.
135bdd1243dSDimitry Andric // For example:
136bdd1243dSDimitry Andric // ```
137bdd1243dSDimitry Andric // std::optional<bool> o;
138bdd1243dSDimitry Andric // int x;
139bdd1243dSDimitry Andric // if (o.has_value())
140bdd1243dSDimitry Andric // x = o.value();
141bdd1243dSDimitry Andric // ```
14206c3fb27SDimitry Andric auto &Expr1 = cast<BoolValue>(Val1).formula();
14306c3fb27SDimitry Andric auto &Expr2 = cast<BoolValue>(Val2).formula();
144*0fca6ea1SDimitry Andric auto &A = JoinedEnv.arena();
145*0fca6ea1SDimitry Andric auto &JoinedVal = A.makeAtomRef(A.makeAtom());
146*0fca6ea1SDimitry Andric JoinedEnv.assume(
14706c3fb27SDimitry Andric A.makeOr(A.makeAnd(A.makeAtomRef(Env1.getFlowConditionToken()),
148*0fca6ea1SDimitry Andric A.makeEquals(JoinedVal, Expr1)),
14906c3fb27SDimitry Andric A.makeAnd(A.makeAtomRef(Env2.getFlowConditionToken()),
150*0fca6ea1SDimitry Andric A.makeEquals(JoinedVal, Expr2))));
151*0fca6ea1SDimitry Andric return &A.makeBoolValue(JoinedVal);
15206c3fb27SDimitry Andric }
15306c3fb27SDimitry Andric
154*0fca6ea1SDimitry Andric Value *JoinedVal = JoinedEnv.createValue(Type);
155*0fca6ea1SDimitry Andric if (JoinedVal)
156*0fca6ea1SDimitry Andric Model.join(Type, Val1, Env1, Val2, Env2, *JoinedVal, JoinedEnv);
15706c3fb27SDimitry Andric
158*0fca6ea1SDimitry Andric return JoinedVal;
15981ad6265SDimitry Andric }
16081ad6265SDimitry Andric
widenDistinctValues(QualType Type,Value & Prev,const Environment & PrevEnv,Value & Current,Environment & CurrentEnv,Environment::ValueModel & Model)161*0fca6ea1SDimitry Andric static WidenResult widenDistinctValues(QualType Type, Value &Prev,
162*0fca6ea1SDimitry Andric const Environment &PrevEnv,
163*0fca6ea1SDimitry Andric Value &Current, Environment &CurrentEnv,
164bdd1243dSDimitry Andric Environment::ValueModel &Model) {
165bdd1243dSDimitry Andric // Boolean-model widening.
166*0fca6ea1SDimitry Andric if (isa<BoolValue>(Prev) && isa<BoolValue>(Current)) {
167*0fca6ea1SDimitry Andric // FIXME: Checking both values should be unnecessary, but we can currently
168*0fca6ea1SDimitry Andric // end up with `BoolValue`s in integer-typed variables. See comment in
169*0fca6ea1SDimitry Andric // `joinDistinctValues()` for details.
170*0fca6ea1SDimitry Andric auto &PrevBool = cast<BoolValue>(Prev);
171*0fca6ea1SDimitry Andric auto &CurBool = cast<BoolValue>(Current);
172*0fca6ea1SDimitry Andric
173bdd1243dSDimitry Andric if (isa<TopBoolValue>(Prev))
174*0fca6ea1SDimitry Andric // Safe to return `Prev` here, because Top is never dependent on the
175*0fca6ea1SDimitry Andric // environment.
176*0fca6ea1SDimitry Andric return {&Prev, LatticeEffect::Unchanged};
1775f757f3fSDimitry Andric
1785f757f3fSDimitry Andric // We may need to widen to Top, but before we do so, check whether both
1795f757f3fSDimitry Andric // values are implied to be either true or false in the current environment.
1805f757f3fSDimitry Andric // In that case, we can simply return a literal instead.
181*0fca6ea1SDimitry Andric bool TruePrev = PrevEnv.proves(PrevBool.formula());
1825f757f3fSDimitry Andric bool TrueCur = CurrentEnv.proves(CurBool.formula());
1835f757f3fSDimitry Andric if (TruePrev && TrueCur)
184*0fca6ea1SDimitry Andric return {&CurrentEnv.getBoolLiteralValue(true), LatticeEffect::Unchanged};
1855f757f3fSDimitry Andric if (!TruePrev && !TrueCur &&
186*0fca6ea1SDimitry Andric PrevEnv.proves(PrevEnv.arena().makeNot(PrevBool.formula())) &&
1875f757f3fSDimitry Andric CurrentEnv.proves(CurrentEnv.arena().makeNot(CurBool.formula())))
188*0fca6ea1SDimitry Andric return {&CurrentEnv.getBoolLiteralValue(false), LatticeEffect::Unchanged};
1895f757f3fSDimitry Andric
190*0fca6ea1SDimitry Andric return {&CurrentEnv.makeTopBoolValue(), LatticeEffect::Changed};
191bdd1243dSDimitry Andric }
19281ad6265SDimitry Andric
193bdd1243dSDimitry Andric // FIXME: Add other built-in model widening.
194bdd1243dSDimitry Andric
195bdd1243dSDimitry Andric // Custom-model widening.
196*0fca6ea1SDimitry Andric if (auto Result = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv))
197*0fca6ea1SDimitry Andric return *Result;
198bdd1243dSDimitry Andric
199*0fca6ea1SDimitry Andric return {&Current, equateUnknownValues(Prev.getKind())
200*0fca6ea1SDimitry Andric ? LatticeEffect::Unchanged
201*0fca6ea1SDimitry Andric : LatticeEffect::Changed};
2025f757f3fSDimitry Andric }
2035f757f3fSDimitry Andric
2045f757f3fSDimitry Andric // Returns whether the values in `Map1` and `Map2` compare equal for those
2055f757f3fSDimitry Andric // keys that `Map1` and `Map2` have in common.
2065f757f3fSDimitry Andric template <typename Key>
compareKeyToValueMaps(const llvm::MapVector<Key,Value * > & Map1,const llvm::MapVector<Key,Value * > & Map2,const Environment & Env1,const Environment & Env2,Environment::ValueModel & Model)2075f757f3fSDimitry Andric bool compareKeyToValueMaps(const llvm::MapVector<Key, Value *> &Map1,
2085f757f3fSDimitry Andric const llvm::MapVector<Key, Value *> &Map2,
2095f757f3fSDimitry Andric const Environment &Env1, const Environment &Env2,
2105f757f3fSDimitry Andric Environment::ValueModel &Model) {
2115f757f3fSDimitry Andric for (auto &Entry : Map1) {
2125f757f3fSDimitry Andric Key K = Entry.first;
2135f757f3fSDimitry Andric assert(K != nullptr);
2145f757f3fSDimitry Andric
2155f757f3fSDimitry Andric Value *Val = Entry.second;
2165f757f3fSDimitry Andric assert(Val != nullptr);
2175f757f3fSDimitry Andric
2185f757f3fSDimitry Andric auto It = Map2.find(K);
2195f757f3fSDimitry Andric if (It == Map2.end())
2205f757f3fSDimitry Andric continue;
2215f757f3fSDimitry Andric assert(It->second != nullptr);
2225f757f3fSDimitry Andric
2235f757f3fSDimitry Andric if (!areEquivalentValues(*Val, *It->second) &&
2245f757f3fSDimitry Andric !compareDistinctValues(K->getType(), *Val, Env1, *It->second, Env2,
2255f757f3fSDimitry Andric Model))
2265f757f3fSDimitry Andric return false;
2275f757f3fSDimitry Andric }
2285f757f3fSDimitry Andric
2295f757f3fSDimitry Andric return true;
2305f757f3fSDimitry Andric }
2315f757f3fSDimitry Andric
2325f757f3fSDimitry Andric // Perform a join on two `LocToVal` maps.
2335f757f3fSDimitry Andric static llvm::MapVector<const StorageLocation *, Value *>
joinLocToVal(const llvm::MapVector<const StorageLocation *,Value * > & LocToVal,const llvm::MapVector<const StorageLocation *,Value * > & LocToVal2,const Environment & Env1,const Environment & Env2,Environment & JoinedEnv,Environment::ValueModel & Model)2345f757f3fSDimitry Andric joinLocToVal(const llvm::MapVector<const StorageLocation *, Value *> &LocToVal,
2355f757f3fSDimitry Andric const llvm::MapVector<const StorageLocation *, Value *> &LocToVal2,
2365f757f3fSDimitry Andric const Environment &Env1, const Environment &Env2,
2375f757f3fSDimitry Andric Environment &JoinedEnv, Environment::ValueModel &Model) {
2385f757f3fSDimitry Andric llvm::MapVector<const StorageLocation *, Value *> Result;
2395f757f3fSDimitry Andric for (auto &Entry : LocToVal) {
2405f757f3fSDimitry Andric const StorageLocation *Loc = Entry.first;
2415f757f3fSDimitry Andric assert(Loc != nullptr);
2425f757f3fSDimitry Andric
2435f757f3fSDimitry Andric Value *Val = Entry.second;
2445f757f3fSDimitry Andric assert(Val != nullptr);
2455f757f3fSDimitry Andric
2465f757f3fSDimitry Andric auto It = LocToVal2.find(Loc);
2475f757f3fSDimitry Andric if (It == LocToVal2.end())
2485f757f3fSDimitry Andric continue;
2495f757f3fSDimitry Andric assert(It->second != nullptr);
2505f757f3fSDimitry Andric
251*0fca6ea1SDimitry Andric if (Value *JoinedVal = Environment::joinValues(
252*0fca6ea1SDimitry Andric Loc->getType(), Val, Env1, It->second, Env2, JoinedEnv, Model)) {
253*0fca6ea1SDimitry Andric Result.insert({Loc, JoinedVal});
2545f757f3fSDimitry Andric }
2555f757f3fSDimitry Andric }
2565f757f3fSDimitry Andric
2575f757f3fSDimitry Andric return Result;
2585f757f3fSDimitry Andric }
2595f757f3fSDimitry Andric
2605f757f3fSDimitry Andric // Perform widening on either `LocToVal` or `ExprToVal`. `Key` must be either
2615f757f3fSDimitry Andric // `const StorageLocation *` or `const Expr *`.
2625f757f3fSDimitry Andric template <typename Key>
2635f757f3fSDimitry Andric llvm::MapVector<Key, Value *>
widenKeyToValueMap(const llvm::MapVector<Key,Value * > & CurMap,const llvm::MapVector<Key,Value * > & PrevMap,Environment & CurEnv,const Environment & PrevEnv,Environment::ValueModel & Model,LatticeEffect & Effect)2645f757f3fSDimitry Andric widenKeyToValueMap(const llvm::MapVector<Key, Value *> &CurMap,
2655f757f3fSDimitry Andric const llvm::MapVector<Key, Value *> &PrevMap,
2665f757f3fSDimitry Andric Environment &CurEnv, const Environment &PrevEnv,
267*0fca6ea1SDimitry Andric Environment::ValueModel &Model, LatticeEffect &Effect) {
2685f757f3fSDimitry Andric llvm::MapVector<Key, Value *> WidenedMap;
2695f757f3fSDimitry Andric for (auto &Entry : CurMap) {
2705f757f3fSDimitry Andric Key K = Entry.first;
2715f757f3fSDimitry Andric assert(K != nullptr);
2725f757f3fSDimitry Andric
2735f757f3fSDimitry Andric Value *Val = Entry.second;
2745f757f3fSDimitry Andric assert(Val != nullptr);
2755f757f3fSDimitry Andric
2765f757f3fSDimitry Andric auto PrevIt = PrevMap.find(K);
2775f757f3fSDimitry Andric if (PrevIt == PrevMap.end())
2785f757f3fSDimitry Andric continue;
2795f757f3fSDimitry Andric assert(PrevIt->second != nullptr);
2805f757f3fSDimitry Andric
2815f757f3fSDimitry Andric if (areEquivalentValues(*Val, *PrevIt->second)) {
2825f757f3fSDimitry Andric WidenedMap.insert({K, Val});
2835f757f3fSDimitry Andric continue;
2845f757f3fSDimitry Andric }
2855f757f3fSDimitry Andric
286*0fca6ea1SDimitry Andric auto [WidenedVal, ValEffect] = widenDistinctValues(
287*0fca6ea1SDimitry Andric K->getType(), *PrevIt->second, PrevEnv, *Val, CurEnv, Model);
288*0fca6ea1SDimitry Andric WidenedMap.insert({K, WidenedVal});
289*0fca6ea1SDimitry Andric if (ValEffect == LatticeEffect::Changed)
290*0fca6ea1SDimitry Andric Effect = LatticeEffect::Changed;
2915f757f3fSDimitry Andric }
2925f757f3fSDimitry Andric
2935f757f3fSDimitry Andric return WidenedMap;
29481ad6265SDimitry Andric }
29581ad6265SDimitry Andric
296*0fca6ea1SDimitry Andric namespace {
297*0fca6ea1SDimitry Andric
298*0fca6ea1SDimitry Andric // Visitor that builds a map from record prvalues to result objects.
299*0fca6ea1SDimitry Andric // For each result object that it encounters, it propagates the storage location
300*0fca6ea1SDimitry Andric // of the result object to all record prvalues that can initialize it.
301*0fca6ea1SDimitry Andric class ResultObjectVisitor : public AnalysisASTVisitor<ResultObjectVisitor> {
302*0fca6ea1SDimitry Andric public:
303*0fca6ea1SDimitry Andric // `ResultObjectMap` will be filled with a map from record prvalues to result
304*0fca6ea1SDimitry Andric // object. If this visitor will traverse a function that returns a record by
305*0fca6ea1SDimitry Andric // value, `LocForRecordReturnVal` is the location to which this record should
306*0fca6ea1SDimitry Andric // be written; otherwise, it is null.
ResultObjectVisitor(llvm::DenseMap<const Expr *,RecordStorageLocation * > & ResultObjectMap,RecordStorageLocation * LocForRecordReturnVal,DataflowAnalysisContext & DACtx)307*0fca6ea1SDimitry Andric explicit ResultObjectVisitor(
308*0fca6ea1SDimitry Andric llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap,
309*0fca6ea1SDimitry Andric RecordStorageLocation *LocForRecordReturnVal,
310*0fca6ea1SDimitry Andric DataflowAnalysisContext &DACtx)
311*0fca6ea1SDimitry Andric : ResultObjectMap(ResultObjectMap),
312*0fca6ea1SDimitry Andric LocForRecordReturnVal(LocForRecordReturnVal), DACtx(DACtx) {}
313*0fca6ea1SDimitry Andric
314*0fca6ea1SDimitry Andric // Traverse all member and base initializers of `Ctor`. This function is not
315*0fca6ea1SDimitry Andric // called by `RecursiveASTVisitor`; it should be called manually if we are
316*0fca6ea1SDimitry Andric // analyzing a constructor. `ThisPointeeLoc` is the storage location that
317*0fca6ea1SDimitry Andric // `this` points to.
TraverseConstructorInits(const CXXConstructorDecl * Ctor,RecordStorageLocation * ThisPointeeLoc)318*0fca6ea1SDimitry Andric void TraverseConstructorInits(const CXXConstructorDecl *Ctor,
319*0fca6ea1SDimitry Andric RecordStorageLocation *ThisPointeeLoc) {
320*0fca6ea1SDimitry Andric assert(ThisPointeeLoc != nullptr);
321*0fca6ea1SDimitry Andric for (const CXXCtorInitializer *Init : Ctor->inits()) {
322*0fca6ea1SDimitry Andric Expr *InitExpr = Init->getInit();
323*0fca6ea1SDimitry Andric if (FieldDecl *Field = Init->getMember();
324*0fca6ea1SDimitry Andric Field != nullptr && Field->getType()->isRecordType()) {
325*0fca6ea1SDimitry Andric PropagateResultObject(InitExpr, cast<RecordStorageLocation>(
326*0fca6ea1SDimitry Andric ThisPointeeLoc->getChild(*Field)));
327*0fca6ea1SDimitry Andric } else if (Init->getBaseClass()) {
328*0fca6ea1SDimitry Andric PropagateResultObject(InitExpr, ThisPointeeLoc);
32981ad6265SDimitry Andric }
33081ad6265SDimitry Andric
331*0fca6ea1SDimitry Andric // Ensure that any result objects within `InitExpr` (e.g. temporaries)
332*0fca6ea1SDimitry Andric // are also propagated to the prvalues that initialize them.
333*0fca6ea1SDimitry Andric TraverseStmt(InitExpr);
33406c3fb27SDimitry Andric
335*0fca6ea1SDimitry Andric // If this is a `CXXDefaultInitExpr`, also propagate any result objects
336*0fca6ea1SDimitry Andric // within the default expression.
337*0fca6ea1SDimitry Andric if (auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(InitExpr))
338*0fca6ea1SDimitry Andric TraverseStmt(DefaultInit->getExpr());
339bdd1243dSDimitry Andric }
340bdd1243dSDimitry Andric }
341bdd1243dSDimitry Andric
VisitVarDecl(VarDecl * VD)342*0fca6ea1SDimitry Andric bool VisitVarDecl(VarDecl *VD) {
343*0fca6ea1SDimitry Andric if (VD->getType()->isRecordType() && VD->hasInit())
344*0fca6ea1SDimitry Andric PropagateResultObject(
345*0fca6ea1SDimitry Andric VD->getInit(),
346*0fca6ea1SDimitry Andric &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*VD)));
347*0fca6ea1SDimitry Andric return true;
3485f757f3fSDimitry Andric }
3495f757f3fSDimitry Andric
VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr * MTE)350*0fca6ea1SDimitry Andric bool VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE) {
351*0fca6ea1SDimitry Andric if (MTE->getType()->isRecordType())
352*0fca6ea1SDimitry Andric PropagateResultObject(
353*0fca6ea1SDimitry Andric MTE->getSubExpr(),
354*0fca6ea1SDimitry Andric &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*MTE)));
355*0fca6ea1SDimitry Andric return true;
356*0fca6ea1SDimitry Andric }
357*0fca6ea1SDimitry Andric
VisitReturnStmt(ReturnStmt * Return)358*0fca6ea1SDimitry Andric bool VisitReturnStmt(ReturnStmt *Return) {
359*0fca6ea1SDimitry Andric Expr *RetValue = Return->getRetValue();
360*0fca6ea1SDimitry Andric if (RetValue != nullptr && RetValue->getType()->isRecordType() &&
361*0fca6ea1SDimitry Andric RetValue->isPRValue())
362*0fca6ea1SDimitry Andric PropagateResultObject(RetValue, LocForRecordReturnVal);
363*0fca6ea1SDimitry Andric return true;
364*0fca6ea1SDimitry Andric }
365*0fca6ea1SDimitry Andric
VisitExpr(Expr * E)366*0fca6ea1SDimitry Andric bool VisitExpr(Expr *E) {
367*0fca6ea1SDimitry Andric // Clang's AST can have record-type prvalues without a result object -- for
368*0fca6ea1SDimitry Andric // example as full-expressions contained in a compound statement or as
369*0fca6ea1SDimitry Andric // arguments of call expressions. We notice this if we get here and a
370*0fca6ea1SDimitry Andric // storage location has not yet been associated with `E`. In this case,
371*0fca6ea1SDimitry Andric // treat this as if it was a `MaterializeTemporaryExpr`.
372*0fca6ea1SDimitry Andric if (E->isPRValue() && E->getType()->isRecordType() &&
373*0fca6ea1SDimitry Andric !ResultObjectMap.contains(E))
374*0fca6ea1SDimitry Andric PropagateResultObject(
375*0fca6ea1SDimitry Andric E, &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*E)));
376*0fca6ea1SDimitry Andric return true;
377*0fca6ea1SDimitry Andric }
378*0fca6ea1SDimitry Andric
379*0fca6ea1SDimitry Andric void
PropagateResultObjectToRecordInitList(const RecordInitListHelper & InitList,RecordStorageLocation * Loc)380*0fca6ea1SDimitry Andric PropagateResultObjectToRecordInitList(const RecordInitListHelper &InitList,
381*0fca6ea1SDimitry Andric RecordStorageLocation *Loc) {
382*0fca6ea1SDimitry Andric for (auto [Base, Init] : InitList.base_inits()) {
383*0fca6ea1SDimitry Andric assert(Base->getType().getCanonicalType() ==
384*0fca6ea1SDimitry Andric Init->getType().getCanonicalType());
385*0fca6ea1SDimitry Andric
386*0fca6ea1SDimitry Andric // Storage location for the base class is the same as that of the
387*0fca6ea1SDimitry Andric // derived class because we "flatten" the object hierarchy and put all
388*0fca6ea1SDimitry Andric // fields in `RecordStorageLocation` of the derived class.
389*0fca6ea1SDimitry Andric PropagateResultObject(Init, Loc);
390*0fca6ea1SDimitry Andric }
391*0fca6ea1SDimitry Andric
392*0fca6ea1SDimitry Andric for (auto [Field, Init] : InitList.field_inits()) {
393*0fca6ea1SDimitry Andric // Fields of non-record type are handled in
394*0fca6ea1SDimitry Andric // `TransferVisitor::VisitInitListExpr()`.
395*0fca6ea1SDimitry Andric if (Field->getType()->isRecordType())
396*0fca6ea1SDimitry Andric PropagateResultObject(
397*0fca6ea1SDimitry Andric Init, cast<RecordStorageLocation>(Loc->getChild(*Field)));
398*0fca6ea1SDimitry Andric }
399*0fca6ea1SDimitry Andric }
400*0fca6ea1SDimitry Andric
401*0fca6ea1SDimitry Andric // Assigns `Loc` as the result object location of `E`, then propagates the
402*0fca6ea1SDimitry Andric // location to all lower-level prvalues that initialize the same object as
403*0fca6ea1SDimitry Andric // `E` (or one of its base classes or member variables).
PropagateResultObject(Expr * E,RecordStorageLocation * Loc)404*0fca6ea1SDimitry Andric void PropagateResultObject(Expr *E, RecordStorageLocation *Loc) {
405*0fca6ea1SDimitry Andric if (!E->isPRValue() || !E->getType()->isRecordType()) {
406*0fca6ea1SDimitry Andric assert(false);
407*0fca6ea1SDimitry Andric // Ensure we don't propagate the result object if we hit this in a
408*0fca6ea1SDimitry Andric // release build.
409*0fca6ea1SDimitry Andric return;
410*0fca6ea1SDimitry Andric }
411*0fca6ea1SDimitry Andric
412*0fca6ea1SDimitry Andric ResultObjectMap[E] = Loc;
413*0fca6ea1SDimitry Andric
414*0fca6ea1SDimitry Andric // The following AST node kinds are "original initializers": They are the
415*0fca6ea1SDimitry Andric // lowest-level AST node that initializes a given object, and nothing
416*0fca6ea1SDimitry Andric // below them can initialize the same object (or part of it).
417*0fca6ea1SDimitry Andric if (isa<CXXConstructExpr>(E) || isa<CallExpr>(E) || isa<LambdaExpr>(E) ||
418*0fca6ea1SDimitry Andric isa<CXXDefaultArgExpr>(E) || isa<CXXStdInitializerListExpr>(E) ||
419*0fca6ea1SDimitry Andric isa<AtomicExpr>(E) ||
420*0fca6ea1SDimitry Andric // We treat `BuiltinBitCastExpr` as an "original initializer" too as
421*0fca6ea1SDimitry Andric // it may not even be casting from a record type -- and even if it is,
422*0fca6ea1SDimitry Andric // the two objects are in general of unrelated type.
423*0fca6ea1SDimitry Andric isa<BuiltinBitCastExpr>(E)) {
424*0fca6ea1SDimitry Andric return;
425*0fca6ea1SDimitry Andric }
426*0fca6ea1SDimitry Andric if (auto *Op = dyn_cast<BinaryOperator>(E);
427*0fca6ea1SDimitry Andric Op && Op->getOpcode() == BO_Cmp) {
428*0fca6ea1SDimitry Andric // Builtin `<=>` returns a `std::strong_ordering` object.
429*0fca6ea1SDimitry Andric return;
430*0fca6ea1SDimitry Andric }
431*0fca6ea1SDimitry Andric
432*0fca6ea1SDimitry Andric if (auto *InitList = dyn_cast<InitListExpr>(E)) {
433*0fca6ea1SDimitry Andric if (!InitList->isSemanticForm())
434*0fca6ea1SDimitry Andric return;
435*0fca6ea1SDimitry Andric if (InitList->isTransparent()) {
436*0fca6ea1SDimitry Andric PropagateResultObject(InitList->getInit(0), Loc);
437*0fca6ea1SDimitry Andric return;
438*0fca6ea1SDimitry Andric }
439*0fca6ea1SDimitry Andric
440*0fca6ea1SDimitry Andric PropagateResultObjectToRecordInitList(RecordInitListHelper(InitList),
441*0fca6ea1SDimitry Andric Loc);
442*0fca6ea1SDimitry Andric return;
443*0fca6ea1SDimitry Andric }
444*0fca6ea1SDimitry Andric
445*0fca6ea1SDimitry Andric if (auto *ParenInitList = dyn_cast<CXXParenListInitExpr>(E)) {
446*0fca6ea1SDimitry Andric PropagateResultObjectToRecordInitList(RecordInitListHelper(ParenInitList),
447*0fca6ea1SDimitry Andric Loc);
448*0fca6ea1SDimitry Andric return;
449*0fca6ea1SDimitry Andric }
450*0fca6ea1SDimitry Andric
451*0fca6ea1SDimitry Andric if (auto *Op = dyn_cast<BinaryOperator>(E); Op && Op->isCommaOp()) {
452*0fca6ea1SDimitry Andric PropagateResultObject(Op->getRHS(), Loc);
453*0fca6ea1SDimitry Andric return;
454*0fca6ea1SDimitry Andric }
455*0fca6ea1SDimitry Andric
456*0fca6ea1SDimitry Andric if (auto *Cond = dyn_cast<AbstractConditionalOperator>(E)) {
457*0fca6ea1SDimitry Andric PropagateResultObject(Cond->getTrueExpr(), Loc);
458*0fca6ea1SDimitry Andric PropagateResultObject(Cond->getFalseExpr(), Loc);
459*0fca6ea1SDimitry Andric return;
460*0fca6ea1SDimitry Andric }
461*0fca6ea1SDimitry Andric
462*0fca6ea1SDimitry Andric if (auto *SE = dyn_cast<StmtExpr>(E)) {
463*0fca6ea1SDimitry Andric PropagateResultObject(cast<Expr>(SE->getSubStmt()->body_back()), Loc);
464*0fca6ea1SDimitry Andric return;
465*0fca6ea1SDimitry Andric }
466*0fca6ea1SDimitry Andric
467*0fca6ea1SDimitry Andric if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(E)) {
468*0fca6ea1SDimitry Andric PropagateResultObject(DIE->getExpr(), Loc);
469*0fca6ea1SDimitry Andric return;
470*0fca6ea1SDimitry Andric }
471*0fca6ea1SDimitry Andric
472*0fca6ea1SDimitry Andric // All other expression nodes that propagate a record prvalue should have
473*0fca6ea1SDimitry Andric // exactly one child.
474*0fca6ea1SDimitry Andric SmallVector<Stmt *, 1> Children(E->child_begin(), E->child_end());
475*0fca6ea1SDimitry Andric LLVM_DEBUG({
476*0fca6ea1SDimitry Andric if (Children.size() != 1)
477*0fca6ea1SDimitry Andric E->dump();
478*0fca6ea1SDimitry Andric });
479*0fca6ea1SDimitry Andric assert(Children.size() == 1);
480*0fca6ea1SDimitry Andric for (Stmt *S : Children)
481*0fca6ea1SDimitry Andric PropagateResultObject(cast<Expr>(S), Loc);
482*0fca6ea1SDimitry Andric }
483*0fca6ea1SDimitry Andric
484*0fca6ea1SDimitry Andric private:
485*0fca6ea1SDimitry Andric llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap;
486*0fca6ea1SDimitry Andric RecordStorageLocation *LocForRecordReturnVal;
487*0fca6ea1SDimitry Andric DataflowAnalysisContext &DACtx;
488*0fca6ea1SDimitry Andric };
489*0fca6ea1SDimitry Andric
490*0fca6ea1SDimitry Andric } // namespace
491*0fca6ea1SDimitry Andric
initialize()4925f757f3fSDimitry Andric void Environment::initialize() {
493*0fca6ea1SDimitry Andric if (InitialTargetStmt == nullptr)
4945f757f3fSDimitry Andric return;
4955f757f3fSDimitry Andric
496*0fca6ea1SDimitry Andric if (InitialTargetFunc == nullptr) {
497*0fca6ea1SDimitry Andric initFieldsGlobalsAndFuncs(getReferencedDecls(*InitialTargetStmt));
498*0fca6ea1SDimitry Andric ResultObjectMap =
499*0fca6ea1SDimitry Andric std::make_shared<PrValueToResultObject>(buildResultObjectMap(
500*0fca6ea1SDimitry Andric DACtx, InitialTargetStmt, getThisPointeeStorageLocation(),
501*0fca6ea1SDimitry Andric /*LocForRecordReturnValue=*/nullptr));
502*0fca6ea1SDimitry Andric return;
503*0fca6ea1SDimitry Andric }
5045f757f3fSDimitry Andric
505*0fca6ea1SDimitry Andric initFieldsGlobalsAndFuncs(getReferencedDecls(*InitialTargetFunc));
5065f757f3fSDimitry Andric
507*0fca6ea1SDimitry Andric for (const auto *ParamDecl : InitialTargetFunc->parameters()) {
5085f757f3fSDimitry Andric assert(ParamDecl != nullptr);
5095f757f3fSDimitry Andric setStorageLocation(*ParamDecl, createObject(*ParamDecl, nullptr));
5105f757f3fSDimitry Andric }
5115f757f3fSDimitry Andric
512*0fca6ea1SDimitry Andric if (InitialTargetFunc->getReturnType()->isRecordType())
513*0fca6ea1SDimitry Andric LocForRecordReturnVal = &cast<RecordStorageLocation>(
514*0fca6ea1SDimitry Andric createStorageLocation(InitialTargetFunc->getReturnType()));
515*0fca6ea1SDimitry Andric
516*0fca6ea1SDimitry Andric if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(InitialTargetFunc)) {
5175f757f3fSDimitry Andric auto *Parent = MethodDecl->getParent();
5185f757f3fSDimitry Andric assert(Parent != nullptr);
5195f757f3fSDimitry Andric
5205f757f3fSDimitry Andric if (Parent->isLambda()) {
521*0fca6ea1SDimitry Andric for (const auto &Capture : Parent->captures()) {
5225f757f3fSDimitry Andric if (Capture.capturesVariable()) {
5235f757f3fSDimitry Andric const auto *VarDecl = Capture.getCapturedVar();
5245f757f3fSDimitry Andric assert(VarDecl != nullptr);
5255f757f3fSDimitry Andric setStorageLocation(*VarDecl, createObject(*VarDecl, nullptr));
5265f757f3fSDimitry Andric } else if (Capture.capturesThis()) {
527*0fca6ea1SDimitry Andric if (auto *Ancestor = InitialTargetFunc->getNonClosureAncestor()) {
528*0fca6ea1SDimitry Andric const auto *SurroundingMethodDecl = cast<CXXMethodDecl>(Ancestor);
5295f757f3fSDimitry Andric QualType ThisPointeeType =
5305f757f3fSDimitry Andric SurroundingMethodDecl->getFunctionObjectParameterType();
5315f757f3fSDimitry Andric setThisPointeeStorageLocation(
532*0fca6ea1SDimitry Andric cast<RecordStorageLocation>(createObject(ThisPointeeType)));
533*0fca6ea1SDimitry Andric } else if (auto *FieldBeingInitialized =
534*0fca6ea1SDimitry Andric dyn_cast<FieldDecl>(Parent->getLambdaContextDecl())) {
535*0fca6ea1SDimitry Andric // This is in a field initializer, rather than a method.
536*0fca6ea1SDimitry Andric setThisPointeeStorageLocation(
537*0fca6ea1SDimitry Andric cast<RecordStorageLocation>(createObject(QualType(
538*0fca6ea1SDimitry Andric FieldBeingInitialized->getParent()->getTypeForDecl(), 0))));
539*0fca6ea1SDimitry Andric } else {
540*0fca6ea1SDimitry Andric assert(false && "Unexpected this-capturing lambda context.");
541*0fca6ea1SDimitry Andric }
5425f757f3fSDimitry Andric }
5435f757f3fSDimitry Andric }
5445f757f3fSDimitry Andric } else if (MethodDecl->isImplicitObjectMemberFunction()) {
5455f757f3fSDimitry Andric QualType ThisPointeeType = MethodDecl->getFunctionObjectParameterType();
546*0fca6ea1SDimitry Andric auto &ThisLoc =
547*0fca6ea1SDimitry Andric cast<RecordStorageLocation>(createStorageLocation(ThisPointeeType));
548*0fca6ea1SDimitry Andric setThisPointeeStorageLocation(ThisLoc);
549*0fca6ea1SDimitry Andric // Initialize fields of `*this` with values, but only if we're not
550*0fca6ea1SDimitry Andric // analyzing a constructor; after all, it's the constructor's job to do
551*0fca6ea1SDimitry Andric // this (and we want to be able to test that).
552*0fca6ea1SDimitry Andric if (!isa<CXXConstructorDecl>(MethodDecl))
553*0fca6ea1SDimitry Andric initializeFieldsWithValues(ThisLoc);
5545f757f3fSDimitry Andric }
5555f757f3fSDimitry Andric }
5565f757f3fSDimitry Andric
557*0fca6ea1SDimitry Andric // We do this below the handling of `CXXMethodDecl` above so that we can
558*0fca6ea1SDimitry Andric // be sure that the storage location for `this` has been set.
559*0fca6ea1SDimitry Andric ResultObjectMap =
560*0fca6ea1SDimitry Andric std::make_shared<PrValueToResultObject>(buildResultObjectMap(
561*0fca6ea1SDimitry Andric DACtx, InitialTargetFunc, getThisPointeeStorageLocation(),
562*0fca6ea1SDimitry Andric LocForRecordReturnVal));
56306c3fb27SDimitry Andric }
56406c3fb27SDimitry Andric
565*0fca6ea1SDimitry Andric // FIXME: Add support for resetting globals after function calls to enable the
566*0fca6ea1SDimitry Andric // implementation of sound analyses.
567*0fca6ea1SDimitry Andric
initFieldsGlobalsAndFuncs(const ReferencedDecls & Referenced)568*0fca6ea1SDimitry Andric void Environment::initFieldsGlobalsAndFuncs(const ReferencedDecls &Referenced) {
56906c3fb27SDimitry Andric // These have to be added before the lines that follow to ensure that
57006c3fb27SDimitry Andric // `create*` work correctly for structs.
571*0fca6ea1SDimitry Andric DACtx->addModeledFields(Referenced.Fields);
57206c3fb27SDimitry Andric
573*0fca6ea1SDimitry Andric for (const VarDecl *D : Referenced.Globals) {
57406c3fb27SDimitry Andric if (getStorageLocation(*D) != nullptr)
575bdd1243dSDimitry Andric continue;
57606c3fb27SDimitry Andric
577*0fca6ea1SDimitry Andric // We don't run transfer functions on the initializers of global variables,
578*0fca6ea1SDimitry Andric // so they won't be associated with a value or storage location. We
579*0fca6ea1SDimitry Andric // therefore intentionally don't pass an initializer to `createObject()`; in
580*0fca6ea1SDimitry Andric // particular, this ensures that `createObject()` will initialize the fields
581*0fca6ea1SDimitry Andric // of record-type variables with values.
582*0fca6ea1SDimitry Andric setStorageLocation(*D, createObject(*D, nullptr));
58306c3fb27SDimitry Andric }
58406c3fb27SDimitry Andric
585*0fca6ea1SDimitry Andric for (const FunctionDecl *FD : Referenced.Functions) {
58606c3fb27SDimitry Andric if (getStorageLocation(*FD) != nullptr)
58706c3fb27SDimitry Andric continue;
588*0fca6ea1SDimitry Andric auto &Loc = createStorageLocation(*FD);
58906c3fb27SDimitry Andric setStorageLocation(*FD, Loc);
59081ad6265SDimitry Andric }
59181ad6265SDimitry Andric }
59281ad6265SDimitry Andric
fork() const59306c3fb27SDimitry Andric Environment Environment::fork() const {
59406c3fb27SDimitry Andric Environment Copy(*this);
59506c3fb27SDimitry Andric Copy.FlowConditionToken = DACtx->forkFlowCondition(FlowConditionToken);
59606c3fb27SDimitry Andric return Copy;
5971fd87a68SDimitry Andric }
5981fd87a68SDimitry Andric
canDescend(unsigned MaxDepth,const FunctionDecl * Callee) const599bdd1243dSDimitry Andric bool Environment::canDescend(unsigned MaxDepth,
600*0fca6ea1SDimitry Andric const FunctionDecl *Callee) const {
601*0fca6ea1SDimitry Andric return CallStack.size() < MaxDepth && !llvm::is_contained(CallStack, Callee);
60204eeddc0SDimitry Andric }
60304eeddc0SDimitry Andric
pushCall(const CallExpr * Call) const604972a253aSDimitry Andric Environment Environment::pushCall(const CallExpr *Call) const {
605972a253aSDimitry Andric Environment Env(*this);
606972a253aSDimitry Andric
607bdd1243dSDimitry Andric if (const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(Call)) {
608bdd1243dSDimitry Andric if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
609bdd1243dSDimitry Andric if (!isa<CXXThisExpr>(Arg))
6105f757f3fSDimitry Andric Env.ThisPointeeLoc =
6115f757f3fSDimitry Andric cast<RecordStorageLocation>(getStorageLocation(*Arg));
612bdd1243dSDimitry Andric // Otherwise (when the argument is `this`), retain the current
613bdd1243dSDimitry Andric // environment's `ThisPointeeLoc`.
614bdd1243dSDimitry Andric }
615bdd1243dSDimitry Andric }
616972a253aSDimitry Andric
617*0fca6ea1SDimitry Andric if (Call->getType()->isRecordType() && Call->isPRValue())
618*0fca6ea1SDimitry Andric Env.LocForRecordReturnVal = &Env.getResultObjectLocation(*Call);
619*0fca6ea1SDimitry Andric
620bdd1243dSDimitry Andric Env.pushCallInternal(Call->getDirectCallee(),
621bdd1243dSDimitry Andric llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));
622bdd1243dSDimitry Andric
623bdd1243dSDimitry Andric return Env;
624bdd1243dSDimitry Andric }
625bdd1243dSDimitry Andric
pushCall(const CXXConstructExpr * Call) const626bdd1243dSDimitry Andric Environment Environment::pushCall(const CXXConstructExpr *Call) const {
627bdd1243dSDimitry Andric Environment Env(*this);
628bdd1243dSDimitry Andric
62906c3fb27SDimitry Andric Env.ThisPointeeLoc = &Env.getResultObjectLocation(*Call);
630*0fca6ea1SDimitry Andric Env.LocForRecordReturnVal = &Env.getResultObjectLocation(*Call);
631bdd1243dSDimitry Andric
632bdd1243dSDimitry Andric Env.pushCallInternal(Call->getConstructor(),
633bdd1243dSDimitry Andric llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));
634bdd1243dSDimitry Andric
635bdd1243dSDimitry Andric return Env;
636bdd1243dSDimitry Andric }
637bdd1243dSDimitry Andric
pushCallInternal(const FunctionDecl * FuncDecl,ArrayRef<const Expr * > Args)638bdd1243dSDimitry Andric void Environment::pushCallInternal(const FunctionDecl *FuncDecl,
639bdd1243dSDimitry Andric ArrayRef<const Expr *> Args) {
64006c3fb27SDimitry Andric // Canonicalize to the definition of the function. This ensures that we're
64106c3fb27SDimitry Andric // putting arguments into the same `ParamVarDecl`s` that the callee will later
64206c3fb27SDimitry Andric // be retrieving them from.
64306c3fb27SDimitry Andric assert(FuncDecl->getDefinition() != nullptr);
64406c3fb27SDimitry Andric FuncDecl = FuncDecl->getDefinition();
64506c3fb27SDimitry Andric
646bdd1243dSDimitry Andric CallStack.push_back(FuncDecl);
647bdd1243dSDimitry Andric
648*0fca6ea1SDimitry Andric initFieldsGlobalsAndFuncs(getReferencedDecls(*FuncDecl));
649bdd1243dSDimitry Andric
650bdd1243dSDimitry Andric const auto *ParamIt = FuncDecl->param_begin();
651972a253aSDimitry Andric
652972a253aSDimitry Andric // FIXME: Parameters don't always map to arguments 1:1; examples include
653972a253aSDimitry Andric // overloaded operators implemented as member functions, and parameter packs.
654bdd1243dSDimitry Andric for (unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) {
655972a253aSDimitry Andric assert(ParamIt != FuncDecl->param_end());
656972a253aSDimitry Andric const VarDecl *Param = *ParamIt;
65706c3fb27SDimitry Andric setStorageLocation(*Param, createObject(*Param, Args[ArgIndex]));
658bdd1243dSDimitry Andric }
659*0fca6ea1SDimitry Andric
660*0fca6ea1SDimitry Andric ResultObjectMap = std::make_shared<PrValueToResultObject>(
661*0fca6ea1SDimitry Andric buildResultObjectMap(DACtx, FuncDecl, getThisPointeeStorageLocation(),
662*0fca6ea1SDimitry Andric LocForRecordReturnVal));
663972a253aSDimitry Andric }
664972a253aSDimitry Andric
popCall(const CallExpr * Call,const Environment & CalleeEnv)66506c3fb27SDimitry Andric void Environment::popCall(const CallExpr *Call, const Environment &CalleeEnv) {
6665f757f3fSDimitry Andric // We ignore some entries of `CalleeEnv`:
6675f757f3fSDimitry Andric // - `DACtx` because is already the same in both
6685f757f3fSDimitry Andric // - We don't want the callee's `DeclCtx`, `ReturnVal`, `ReturnLoc` or
6695f757f3fSDimitry Andric // `ThisPointeeLoc` because they don't apply to us.
6705f757f3fSDimitry Andric // - `DeclToLoc`, `ExprToLoc`, and `ExprToVal` capture information from the
6715f757f3fSDimitry Andric // callee's local scope, so when popping that scope, we do not propagate
6725f757f3fSDimitry Andric // the maps.
673bdd1243dSDimitry Andric this->LocToVal = std::move(CalleeEnv.LocToVal);
674bdd1243dSDimitry Andric this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
67506c3fb27SDimitry Andric
67606c3fb27SDimitry Andric if (Call->isGLValue()) {
67706c3fb27SDimitry Andric if (CalleeEnv.ReturnLoc != nullptr)
6785f757f3fSDimitry Andric setStorageLocation(*Call, *CalleeEnv.ReturnLoc);
67906c3fb27SDimitry Andric } else if (!Call->getType()->isVoidType()) {
68006c3fb27SDimitry Andric if (CalleeEnv.ReturnVal != nullptr)
6815f757f3fSDimitry Andric setValue(*Call, *CalleeEnv.ReturnVal);
68206c3fb27SDimitry Andric }
68306c3fb27SDimitry Andric }
68406c3fb27SDimitry Andric
popCall(const CXXConstructExpr * Call,const Environment & CalleeEnv)68506c3fb27SDimitry Andric void Environment::popCall(const CXXConstructExpr *Call,
68606c3fb27SDimitry Andric const Environment &CalleeEnv) {
68706c3fb27SDimitry Andric // See also comment in `popCall(const CallExpr *, const Environment &)` above.
68806c3fb27SDimitry Andric this->LocToVal = std::move(CalleeEnv.LocToVal);
68906c3fb27SDimitry Andric this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
690972a253aSDimitry Andric }
691972a253aSDimitry Andric
equivalentTo(const Environment & Other,Environment::ValueModel & Model) const6921fd87a68SDimitry Andric bool Environment::equivalentTo(const Environment &Other,
6931fd87a68SDimitry Andric Environment::ValueModel &Model) const {
69404eeddc0SDimitry Andric assert(DACtx == Other.DACtx);
6951fd87a68SDimitry Andric
69606c3fb27SDimitry Andric if (ReturnVal != Other.ReturnVal)
69706c3fb27SDimitry Andric return false;
69806c3fb27SDimitry Andric
699bdd1243dSDimitry Andric if (ReturnLoc != Other.ReturnLoc)
700bdd1243dSDimitry Andric return false;
701bdd1243dSDimitry Andric
702*0fca6ea1SDimitry Andric if (LocForRecordReturnVal != Other.LocForRecordReturnVal)
703*0fca6ea1SDimitry Andric return false;
704*0fca6ea1SDimitry Andric
705bdd1243dSDimitry Andric if (ThisPointeeLoc != Other.ThisPointeeLoc)
706bdd1243dSDimitry Andric return false;
707bdd1243dSDimitry Andric
7081fd87a68SDimitry Andric if (DeclToLoc != Other.DeclToLoc)
7091fd87a68SDimitry Andric return false;
7101fd87a68SDimitry Andric
7111fd87a68SDimitry Andric if (ExprToLoc != Other.ExprToLoc)
7121fd87a68SDimitry Andric return false;
7131fd87a68SDimitry Andric
7145f757f3fSDimitry Andric if (!compareKeyToValueMaps(ExprToVal, Other.ExprToVal, *this, Other, Model))
7151fd87a68SDimitry Andric return false;
7165f757f3fSDimitry Andric
7175f757f3fSDimitry Andric if (!compareKeyToValueMaps(LocToVal, Other.LocToVal, *this, Other, Model))
7185f757f3fSDimitry Andric return false;
7191fd87a68SDimitry Andric
7201fd87a68SDimitry Andric return true;
72104eeddc0SDimitry Andric }
72204eeddc0SDimitry Andric
widen(const Environment & PrevEnv,Environment::ValueModel & Model)723*0fca6ea1SDimitry Andric LatticeEffect Environment::widen(const Environment &PrevEnv,
724bdd1243dSDimitry Andric Environment::ValueModel &Model) {
725bdd1243dSDimitry Andric assert(DACtx == PrevEnv.DACtx);
72606c3fb27SDimitry Andric assert(ReturnVal == PrevEnv.ReturnVal);
727bdd1243dSDimitry Andric assert(ReturnLoc == PrevEnv.ReturnLoc);
728*0fca6ea1SDimitry Andric assert(LocForRecordReturnVal == PrevEnv.LocForRecordReturnVal);
729bdd1243dSDimitry Andric assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc);
730bdd1243dSDimitry Andric assert(CallStack == PrevEnv.CallStack);
731*0fca6ea1SDimitry Andric assert(ResultObjectMap == PrevEnv.ResultObjectMap);
732*0fca6ea1SDimitry Andric assert(InitialTargetFunc == PrevEnv.InitialTargetFunc);
733*0fca6ea1SDimitry Andric assert(InitialTargetStmt == PrevEnv.InitialTargetStmt);
734bdd1243dSDimitry Andric
735*0fca6ea1SDimitry Andric auto Effect = LatticeEffect::Unchanged;
736bdd1243dSDimitry Andric
737bdd1243dSDimitry Andric // By the API, `PrevEnv` is a previous version of the environment for the same
738bdd1243dSDimitry Andric // block, so we have some guarantees about its shape. In particular, it will
739bdd1243dSDimitry Andric // be the result of a join or widen operation on previous values for this
7405f757f3fSDimitry Andric // block. For `DeclToLoc`, `ExprToVal`, and `ExprToLoc`, join guarantees that
7415f757f3fSDimitry Andric // these maps are subsets of the maps in `PrevEnv`. So, as long as we maintain
7425f757f3fSDimitry Andric // this property here, we don't need change their current values to widen.
743bdd1243dSDimitry Andric assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size());
7445f757f3fSDimitry Andric assert(ExprToVal.size() <= PrevEnv.ExprToVal.size());
745bdd1243dSDimitry Andric assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size());
746bdd1243dSDimitry Andric
7475f757f3fSDimitry Andric ExprToVal = widenKeyToValueMap(ExprToVal, PrevEnv.ExprToVal, *this, PrevEnv,
7485f757f3fSDimitry Andric Model, Effect);
749bdd1243dSDimitry Andric
7505f757f3fSDimitry Andric LocToVal = widenKeyToValueMap(LocToVal, PrevEnv.LocToVal, *this, PrevEnv,
7515f757f3fSDimitry Andric Model, Effect);
752bdd1243dSDimitry Andric if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() ||
753bdd1243dSDimitry Andric ExprToLoc.size() != PrevEnv.ExprToLoc.size() ||
7545f757f3fSDimitry Andric ExprToVal.size() != PrevEnv.ExprToVal.size() ||
75506c3fb27SDimitry Andric LocToVal.size() != PrevEnv.LocToVal.size())
756*0fca6ea1SDimitry Andric Effect = LatticeEffect::Changed;
757bdd1243dSDimitry Andric
758bdd1243dSDimitry Andric return Effect;
759bdd1243dSDimitry Andric }
760bdd1243dSDimitry Andric
join(const Environment & EnvA,const Environment & EnvB,Environment::ValueModel & Model,ExprJoinBehavior ExprBehavior)76106c3fb27SDimitry Andric Environment Environment::join(const Environment &EnvA, const Environment &EnvB,
762*0fca6ea1SDimitry Andric Environment::ValueModel &Model,
763*0fca6ea1SDimitry Andric ExprJoinBehavior ExprBehavior) {
76406c3fb27SDimitry Andric assert(EnvA.DACtx == EnvB.DACtx);
765*0fca6ea1SDimitry Andric assert(EnvA.LocForRecordReturnVal == EnvB.LocForRecordReturnVal);
76606c3fb27SDimitry Andric assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc);
76706c3fb27SDimitry Andric assert(EnvA.CallStack == EnvB.CallStack);
768*0fca6ea1SDimitry Andric assert(EnvA.ResultObjectMap == EnvB.ResultObjectMap);
769*0fca6ea1SDimitry Andric assert(EnvA.InitialTargetFunc == EnvB.InitialTargetFunc);
770*0fca6ea1SDimitry Andric assert(EnvA.InitialTargetStmt == EnvB.InitialTargetStmt);
77104eeddc0SDimitry Andric
77206c3fb27SDimitry Andric Environment JoinedEnv(*EnvA.DACtx);
77304eeddc0SDimitry Andric
77406c3fb27SDimitry Andric JoinedEnv.CallStack = EnvA.CallStack;
775*0fca6ea1SDimitry Andric JoinedEnv.ResultObjectMap = EnvA.ResultObjectMap;
776*0fca6ea1SDimitry Andric JoinedEnv.LocForRecordReturnVal = EnvA.LocForRecordReturnVal;
77706c3fb27SDimitry Andric JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc;
778*0fca6ea1SDimitry Andric JoinedEnv.InitialTargetFunc = EnvA.InitialTargetFunc;
779*0fca6ea1SDimitry Andric JoinedEnv.InitialTargetStmt = EnvA.InitialTargetStmt;
78081ad6265SDimitry Andric
781*0fca6ea1SDimitry Andric const FunctionDecl *Func = EnvA.getCurrentFunc();
782*0fca6ea1SDimitry Andric if (!Func) {
78306c3fb27SDimitry Andric JoinedEnv.ReturnVal = nullptr;
78406c3fb27SDimitry Andric } else {
785*0fca6ea1SDimitry Andric JoinedEnv.ReturnVal =
786*0fca6ea1SDimitry Andric joinValues(Func->getReturnType(), EnvA.ReturnVal, EnvA, EnvB.ReturnVal,
787*0fca6ea1SDimitry Andric EnvB, JoinedEnv, Model);
78806c3fb27SDimitry Andric }
789bdd1243dSDimitry Andric
79006c3fb27SDimitry Andric if (EnvA.ReturnLoc == EnvB.ReturnLoc)
79106c3fb27SDimitry Andric JoinedEnv.ReturnLoc = EnvA.ReturnLoc;
79206c3fb27SDimitry Andric else
79306c3fb27SDimitry Andric JoinedEnv.ReturnLoc = nullptr;
79404eeddc0SDimitry Andric
7955f757f3fSDimitry Andric JoinedEnv.DeclToLoc = intersectDeclToLoc(EnvA.DeclToLoc, EnvB.DeclToLoc);
79681ad6265SDimitry Andric
797bdd1243dSDimitry Andric // FIXME: update join to detect backedges and simplify the flow condition
798bdd1243dSDimitry Andric // accordingly.
79906c3fb27SDimitry Andric JoinedEnv.FlowConditionToken = EnvA.DACtx->joinFlowConditions(
80006c3fb27SDimitry Andric EnvA.FlowConditionToken, EnvB.FlowConditionToken);
80181ad6265SDimitry Andric
8025f757f3fSDimitry Andric JoinedEnv.LocToVal =
8035f757f3fSDimitry Andric joinLocToVal(EnvA.LocToVal, EnvB.LocToVal, EnvA, EnvB, JoinedEnv, Model);
80404eeddc0SDimitry Andric
805*0fca6ea1SDimitry Andric if (ExprBehavior == KeepExprState) {
806*0fca6ea1SDimitry Andric JoinedEnv.ExprToVal = joinExprMaps(EnvA.ExprToVal, EnvB.ExprToVal);
807*0fca6ea1SDimitry Andric JoinedEnv.ExprToLoc = joinExprMaps(EnvA.ExprToLoc, EnvB.ExprToLoc);
808*0fca6ea1SDimitry Andric }
80904eeddc0SDimitry Andric
81006c3fb27SDimitry Andric return JoinedEnv;
81104eeddc0SDimitry Andric }
81204eeddc0SDimitry Andric
joinValues(QualType Ty,Value * Val1,const Environment & Env1,Value * Val2,const Environment & Env2,Environment & JoinedEnv,Environment::ValueModel & Model)813*0fca6ea1SDimitry Andric Value *Environment::joinValues(QualType Ty, Value *Val1,
814*0fca6ea1SDimitry Andric const Environment &Env1, Value *Val2,
815*0fca6ea1SDimitry Andric const Environment &Env2, Environment &JoinedEnv,
816*0fca6ea1SDimitry Andric Environment::ValueModel &Model) {
817*0fca6ea1SDimitry Andric if (Val1 == nullptr || Val2 == nullptr)
818*0fca6ea1SDimitry Andric // We can't say anything about the joined value -- even if one of the values
819*0fca6ea1SDimitry Andric // is non-null, we don't want to simply propagate it, because it would be
820*0fca6ea1SDimitry Andric // too specific: Because the other value is null, that means we have no
821*0fca6ea1SDimitry Andric // information at all about the value (i.e. the value is unconstrained).
822*0fca6ea1SDimitry Andric return nullptr;
823*0fca6ea1SDimitry Andric
824*0fca6ea1SDimitry Andric if (areEquivalentValues(*Val1, *Val2))
825*0fca6ea1SDimitry Andric // Arbitrarily return one of the two values.
826*0fca6ea1SDimitry Andric return Val1;
827*0fca6ea1SDimitry Andric
828*0fca6ea1SDimitry Andric return joinDistinctValues(Ty, *Val1, Env1, *Val2, Env2, JoinedEnv, Model);
829*0fca6ea1SDimitry Andric }
830*0fca6ea1SDimitry Andric
createStorageLocation(QualType Type)83104eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(QualType Type) {
832bdd1243dSDimitry Andric return DACtx->createStorageLocation(Type);
83304eeddc0SDimitry Andric }
83404eeddc0SDimitry Andric
createStorageLocation(const ValueDecl & D)8355f757f3fSDimitry Andric StorageLocation &Environment::createStorageLocation(const ValueDecl &D) {
83604eeddc0SDimitry Andric // Evaluated declarations are always assigned the same storage locations to
83704eeddc0SDimitry Andric // ensure that the environment stabilizes across loop iterations. Storage
83804eeddc0SDimitry Andric // locations for evaluated declarations are stored in the analysis context.
83981ad6265SDimitry Andric return DACtx->getStableStorageLocation(D);
84004eeddc0SDimitry Andric }
84104eeddc0SDimitry Andric
createStorageLocation(const Expr & E)84204eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const Expr &E) {
84304eeddc0SDimitry Andric // Evaluated expressions are always assigned the same storage locations to
84404eeddc0SDimitry Andric // ensure that the environment stabilizes across loop iterations. Storage
84504eeddc0SDimitry Andric // locations for evaluated expressions are stored in the analysis context.
84681ad6265SDimitry Andric return DACtx->getStableStorageLocation(E);
84704eeddc0SDimitry Andric }
84804eeddc0SDimitry Andric
setStorageLocation(const ValueDecl & D,StorageLocation & Loc)84904eeddc0SDimitry Andric void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
85006c3fb27SDimitry Andric assert(!DeclToLoc.contains(&D));
851*0fca6ea1SDimitry Andric // The only kinds of declarations that may have a "variable" storage location
852*0fca6ea1SDimitry Andric // are declarations of reference type and `BindingDecl`. For all other
853*0fca6ea1SDimitry Andric // declaration, the storage location should be the stable storage location
854*0fca6ea1SDimitry Andric // returned by `createStorageLocation()`.
855*0fca6ea1SDimitry Andric assert(D.getType()->isReferenceType() || isa<BindingDecl>(D) ||
856*0fca6ea1SDimitry Andric &Loc == &createStorageLocation(D));
85704eeddc0SDimitry Andric DeclToLoc[&D] = &Loc;
85804eeddc0SDimitry Andric }
85904eeddc0SDimitry Andric
getStorageLocation(const ValueDecl & D) const86006c3fb27SDimitry Andric StorageLocation *Environment::getStorageLocation(const ValueDecl &D) const {
86104eeddc0SDimitry Andric auto It = DeclToLoc.find(&D);
86206c3fb27SDimitry Andric if (It == DeclToLoc.end())
86306c3fb27SDimitry Andric return nullptr;
86406c3fb27SDimitry Andric
86506c3fb27SDimitry Andric StorageLocation *Loc = It->second;
86606c3fb27SDimitry Andric
86706c3fb27SDimitry Andric return Loc;
86804eeddc0SDimitry Andric }
86904eeddc0SDimitry Andric
removeDecl(const ValueDecl & D)8705f757f3fSDimitry Andric void Environment::removeDecl(const ValueDecl &D) { DeclToLoc.erase(&D); }
87104eeddc0SDimitry Andric
setStorageLocation(const Expr & E,StorageLocation & Loc)8725f757f3fSDimitry Andric void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
87306c3fb27SDimitry Andric // `DeclRefExpr`s to builtin function types aren't glvalues, for some reason,
87406c3fb27SDimitry Andric // but we still want to be able to associate a `StorageLocation` with them,
87506c3fb27SDimitry Andric // so allow these as an exception.
87606c3fb27SDimitry Andric assert(E.isGLValue() ||
87706c3fb27SDimitry Andric E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
878cb14a3feSDimitry Andric const Expr &CanonE = ignoreCFGOmittedNodes(E);
879cb14a3feSDimitry Andric assert(!ExprToLoc.contains(&CanonE));
880cb14a3feSDimitry Andric ExprToLoc[&CanonE] = &Loc;
88106c3fb27SDimitry Andric }
88206c3fb27SDimitry Andric
getStorageLocation(const Expr & E) const8835f757f3fSDimitry Andric StorageLocation *Environment::getStorageLocation(const Expr &E) const {
8845f757f3fSDimitry Andric // See comment in `setStorageLocation()`.
88506c3fb27SDimitry Andric assert(E.isGLValue() ||
88606c3fb27SDimitry Andric E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
887cb14a3feSDimitry Andric auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));
888cb14a3feSDimitry Andric return It == ExprToLoc.end() ? nullptr : &*It->second;
889cb14a3feSDimitry Andric }
890cb14a3feSDimitry Andric
8915f757f3fSDimitry Andric RecordStorageLocation &
getResultObjectLocation(const Expr & RecordPRValue) const892cb14a3feSDimitry Andric Environment::getResultObjectLocation(const Expr &RecordPRValue) const {
89306c3fb27SDimitry Andric assert(RecordPRValue.getType()->isRecordType());
89406c3fb27SDimitry Andric assert(RecordPRValue.isPRValue());
89506c3fb27SDimitry Andric
896*0fca6ea1SDimitry Andric assert(ResultObjectMap != nullptr);
897*0fca6ea1SDimitry Andric RecordStorageLocation *Loc = ResultObjectMap->lookup(&RecordPRValue);
898*0fca6ea1SDimitry Andric assert(Loc != nullptr);
899*0fca6ea1SDimitry Andric // In release builds, use the "stable" storage location if the map lookup
900*0fca6ea1SDimitry Andric // failed.
901*0fca6ea1SDimitry Andric if (Loc == nullptr)
902cb14a3feSDimitry Andric return cast<RecordStorageLocation>(
90306c3fb27SDimitry Andric DACtx->getStableStorageLocation(RecordPRValue));
904*0fca6ea1SDimitry Andric return *Loc;
90504eeddc0SDimitry Andric }
90604eeddc0SDimitry Andric
getOrCreateNullPointerValue(QualType PointeeType)90781ad6265SDimitry Andric PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) {
90881ad6265SDimitry Andric return DACtx->getOrCreateNullPointerValue(PointeeType);
90981ad6265SDimitry Andric }
91081ad6265SDimitry Andric
initializeFieldsWithValues(RecordStorageLocation & Loc,QualType Type)911*0fca6ea1SDimitry Andric void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc,
912*0fca6ea1SDimitry Andric QualType Type) {
913*0fca6ea1SDimitry Andric llvm::DenseSet<QualType> Visited;
914*0fca6ea1SDimitry Andric int CreatedValuesCount = 0;
915*0fca6ea1SDimitry Andric initializeFieldsWithValues(Loc, Type, Visited, 0, CreatedValuesCount);
916*0fca6ea1SDimitry Andric if (CreatedValuesCount > MaxCompositeValueSize) {
917*0fca6ea1SDimitry Andric llvm::errs() << "Attempting to initialize a huge value of type: " << Type
918*0fca6ea1SDimitry Andric << '\n';
919*0fca6ea1SDimitry Andric }
920*0fca6ea1SDimitry Andric }
92106c3fb27SDimitry Andric
setValue(const StorageLocation & Loc,Value & Val)922*0fca6ea1SDimitry Andric void Environment::setValue(const StorageLocation &Loc, Value &Val) {
923*0fca6ea1SDimitry Andric // Records should not be associated with values.
924*0fca6ea1SDimitry Andric assert(!isa<RecordStorageLocation>(Loc));
92504eeddc0SDimitry Andric LocToVal[&Loc] = &Val;
92606c3fb27SDimitry Andric }
92706c3fb27SDimitry Andric
setValue(const Expr & E,Value & Val)9285f757f3fSDimitry Andric void Environment::setValue(const Expr &E, Value &Val) {
9297a6dacacSDimitry Andric const Expr &CanonE = ignoreCFGOmittedNodes(E);
9307a6dacacSDimitry Andric
9317a6dacacSDimitry Andric assert(CanonE.isPRValue());
932*0fca6ea1SDimitry Andric // Records should not be associated with values.
933*0fca6ea1SDimitry Andric assert(!CanonE.getType()->isRecordType());
9347a6dacacSDimitry Andric ExprToVal[&CanonE] = &Val;
93504eeddc0SDimitry Andric }
93604eeddc0SDimitry Andric
getValue(const StorageLocation & Loc) const93704eeddc0SDimitry Andric Value *Environment::getValue(const StorageLocation &Loc) const {
938*0fca6ea1SDimitry Andric // Records should not be associated with values.
939*0fca6ea1SDimitry Andric assert(!isa<RecordStorageLocation>(Loc));
94006c3fb27SDimitry Andric return LocToVal.lookup(&Loc);
94104eeddc0SDimitry Andric }
94204eeddc0SDimitry Andric
getValue(const ValueDecl & D) const94306c3fb27SDimitry Andric Value *Environment::getValue(const ValueDecl &D) const {
94406c3fb27SDimitry Andric auto *Loc = getStorageLocation(D);
94504eeddc0SDimitry Andric if (Loc == nullptr)
94604eeddc0SDimitry Andric return nullptr;
94704eeddc0SDimitry Andric return getValue(*Loc);
94804eeddc0SDimitry Andric }
94904eeddc0SDimitry Andric
getValue(const Expr & E) const9505f757f3fSDimitry Andric Value *Environment::getValue(const Expr &E) const {
951*0fca6ea1SDimitry Andric // Records should not be associated with values.
952*0fca6ea1SDimitry Andric assert(!E.getType()->isRecordType());
953*0fca6ea1SDimitry Andric
9545f757f3fSDimitry Andric if (E.isPRValue()) {
9555f757f3fSDimitry Andric auto It = ExprToVal.find(&ignoreCFGOmittedNodes(E));
9565f757f3fSDimitry Andric return It == ExprToVal.end() ? nullptr : It->second;
95704eeddc0SDimitry Andric }
95804eeddc0SDimitry Andric
9595f757f3fSDimitry Andric auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));
9605f757f3fSDimitry Andric if (It == ExprToLoc.end())
9615f757f3fSDimitry Andric return nullptr;
9625f757f3fSDimitry Andric return getValue(*It->second);
96306c3fb27SDimitry Andric }
96406c3fb27SDimitry Andric
createValue(QualType Type)96504eeddc0SDimitry Andric Value *Environment::createValue(QualType Type) {
96604eeddc0SDimitry Andric llvm::DenseSet<QualType> Visited;
96781ad6265SDimitry Andric int CreatedValuesCount = 0;
96881ad6265SDimitry Andric Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0,
96981ad6265SDimitry Andric CreatedValuesCount);
97081ad6265SDimitry Andric if (CreatedValuesCount > MaxCompositeValueSize) {
97181ad6265SDimitry Andric llvm::errs() << "Attempting to initialize a huge value of type: " << Type
97281ad6265SDimitry Andric << '\n';
97381ad6265SDimitry Andric }
97481ad6265SDimitry Andric return Val;
97504eeddc0SDimitry Andric }
97604eeddc0SDimitry Andric
createValueUnlessSelfReferential(QualType Type,llvm::DenseSet<QualType> & Visited,int Depth,int & CreatedValuesCount)97704eeddc0SDimitry Andric Value *Environment::createValueUnlessSelfReferential(
97881ad6265SDimitry Andric QualType Type, llvm::DenseSet<QualType> &Visited, int Depth,
97981ad6265SDimitry Andric int &CreatedValuesCount) {
98004eeddc0SDimitry Andric assert(!Type.isNull());
9815f757f3fSDimitry Andric assert(!Type->isReferenceType());
982*0fca6ea1SDimitry Andric assert(!Type->isRecordType());
98304eeddc0SDimitry Andric
98481ad6265SDimitry Andric // Allow unlimited fields at depth 1; only cap at deeper nesting levels.
98581ad6265SDimitry Andric if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) ||
98681ad6265SDimitry Andric Depth > MaxCompositeValueDepth)
98781ad6265SDimitry Andric return nullptr;
98881ad6265SDimitry Andric
98981ad6265SDimitry Andric if (Type->isBooleanType()) {
99081ad6265SDimitry Andric CreatedValuesCount++;
99181ad6265SDimitry Andric return &makeAtomicBoolValue();
99281ad6265SDimitry Andric }
99381ad6265SDimitry Andric
99404eeddc0SDimitry Andric if (Type->isIntegerType()) {
995bdd1243dSDimitry Andric // FIXME: consider instead `return nullptr`, given that we do nothing useful
996bdd1243dSDimitry Andric // with integers, and so distinguishing them serves no purpose, but could
997bdd1243dSDimitry Andric // prevent convergence.
99881ad6265SDimitry Andric CreatedValuesCount++;
99906c3fb27SDimitry Andric return &arena().create<IntegerValue>();
100004eeddc0SDimitry Andric }
100104eeddc0SDimitry Andric
10025f757f3fSDimitry Andric if (Type->isPointerType()) {
100381ad6265SDimitry Andric CreatedValuesCount++;
100406c3fb27SDimitry Andric QualType PointeeType = Type->getPointeeType();
100506c3fb27SDimitry Andric StorageLocation &PointeeLoc =
100606c3fb27SDimitry Andric createLocAndMaybeValue(PointeeType, Visited, Depth, CreatedValuesCount);
100704eeddc0SDimitry Andric
100806c3fb27SDimitry Andric return &arena().create<PointerValue>(PointeeLoc);
100904eeddc0SDimitry Andric }
101004eeddc0SDimitry Andric
101104eeddc0SDimitry Andric return nullptr;
101204eeddc0SDimitry Andric }
101304eeddc0SDimitry Andric
101406c3fb27SDimitry Andric StorageLocation &
createLocAndMaybeValue(QualType Ty,llvm::DenseSet<QualType> & Visited,int Depth,int & CreatedValuesCount)101506c3fb27SDimitry Andric Environment::createLocAndMaybeValue(QualType Ty,
101606c3fb27SDimitry Andric llvm::DenseSet<QualType> &Visited,
101706c3fb27SDimitry Andric int Depth, int &CreatedValuesCount) {
101806c3fb27SDimitry Andric if (!Visited.insert(Ty.getCanonicalType()).second)
101906c3fb27SDimitry Andric return createStorageLocation(Ty.getNonReferenceType());
1020*0fca6ea1SDimitry Andric auto EraseVisited = llvm::make_scope_exit(
1021*0fca6ea1SDimitry Andric [&Visited, Ty] { Visited.erase(Ty.getCanonicalType()); });
102206c3fb27SDimitry Andric
102306c3fb27SDimitry Andric Ty = Ty.getNonReferenceType();
102406c3fb27SDimitry Andric
1025*0fca6ea1SDimitry Andric if (Ty->isRecordType()) {
1026*0fca6ea1SDimitry Andric auto &Loc = cast<RecordStorageLocation>(createStorageLocation(Ty));
1027*0fca6ea1SDimitry Andric initializeFieldsWithValues(Loc, Ty, Visited, Depth, CreatedValuesCount);
1028*0fca6ea1SDimitry Andric return Loc;
1029*0fca6ea1SDimitry Andric }
103006c3fb27SDimitry Andric
103106c3fb27SDimitry Andric StorageLocation &Loc = createStorageLocation(Ty);
1032*0fca6ea1SDimitry Andric
1033*0fca6ea1SDimitry Andric if (Value *Val = createValueUnlessSelfReferential(Ty, Visited, Depth,
1034*0fca6ea1SDimitry Andric CreatedValuesCount))
103506c3fb27SDimitry Andric setValue(Loc, *Val);
1036*0fca6ea1SDimitry Andric
103706c3fb27SDimitry Andric return Loc;
103806c3fb27SDimitry Andric }
103906c3fb27SDimitry Andric
initializeFieldsWithValues(RecordStorageLocation & Loc,QualType Type,llvm::DenseSet<QualType> & Visited,int Depth,int & CreatedValuesCount)1040*0fca6ea1SDimitry Andric void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc,
1041*0fca6ea1SDimitry Andric QualType Type,
1042*0fca6ea1SDimitry Andric llvm::DenseSet<QualType> &Visited,
1043*0fca6ea1SDimitry Andric int Depth,
1044*0fca6ea1SDimitry Andric int &CreatedValuesCount) {
1045*0fca6ea1SDimitry Andric auto initField = [&](QualType FieldType, StorageLocation &FieldLoc) {
1046*0fca6ea1SDimitry Andric if (FieldType->isRecordType()) {
1047*0fca6ea1SDimitry Andric auto &FieldRecordLoc = cast<RecordStorageLocation>(FieldLoc);
1048*0fca6ea1SDimitry Andric initializeFieldsWithValues(FieldRecordLoc, FieldRecordLoc.getType(),
1049*0fca6ea1SDimitry Andric Visited, Depth + 1, CreatedValuesCount);
1050*0fca6ea1SDimitry Andric } else {
1051*0fca6ea1SDimitry Andric if (getValue(FieldLoc) != nullptr)
1052*0fca6ea1SDimitry Andric return;
1053*0fca6ea1SDimitry Andric if (!Visited.insert(FieldType.getCanonicalType()).second)
1054*0fca6ea1SDimitry Andric return;
1055*0fca6ea1SDimitry Andric if (Value *Val = createValueUnlessSelfReferential(
1056*0fca6ea1SDimitry Andric FieldType, Visited, Depth + 1, CreatedValuesCount))
1057*0fca6ea1SDimitry Andric setValue(FieldLoc, *Val);
1058*0fca6ea1SDimitry Andric Visited.erase(FieldType.getCanonicalType());
1059*0fca6ea1SDimitry Andric }
1060*0fca6ea1SDimitry Andric };
1061*0fca6ea1SDimitry Andric
1062*0fca6ea1SDimitry Andric for (const FieldDecl *Field : DACtx->getModeledFields(Type)) {
1063*0fca6ea1SDimitry Andric assert(Field != nullptr);
1064*0fca6ea1SDimitry Andric QualType FieldType = Field->getType();
1065*0fca6ea1SDimitry Andric
1066*0fca6ea1SDimitry Andric if (FieldType->isReferenceType()) {
1067*0fca6ea1SDimitry Andric Loc.setChild(*Field,
1068*0fca6ea1SDimitry Andric &createLocAndMaybeValue(FieldType, Visited, Depth + 1,
1069*0fca6ea1SDimitry Andric CreatedValuesCount));
1070*0fca6ea1SDimitry Andric } else {
1071*0fca6ea1SDimitry Andric StorageLocation *FieldLoc = Loc.getChild(*Field);
1072*0fca6ea1SDimitry Andric assert(FieldLoc != nullptr);
1073*0fca6ea1SDimitry Andric initField(FieldType, *FieldLoc);
1074*0fca6ea1SDimitry Andric }
1075*0fca6ea1SDimitry Andric }
1076*0fca6ea1SDimitry Andric for (const auto &[FieldName, FieldType] : DACtx->getSyntheticFields(Type)) {
1077*0fca6ea1SDimitry Andric // Synthetic fields cannot have reference type, so we don't need to deal
1078*0fca6ea1SDimitry Andric // with this case.
1079*0fca6ea1SDimitry Andric assert(!FieldType->isReferenceType());
1080*0fca6ea1SDimitry Andric initField(FieldType, Loc.getSyntheticField(FieldName));
1081*0fca6ea1SDimitry Andric }
1082*0fca6ea1SDimitry Andric }
1083*0fca6ea1SDimitry Andric
createObjectInternal(const ValueDecl * D,QualType Ty,const Expr * InitExpr)10845f757f3fSDimitry Andric StorageLocation &Environment::createObjectInternal(const ValueDecl *D,
108506c3fb27SDimitry Andric QualType Ty,
108606c3fb27SDimitry Andric const Expr *InitExpr) {
108706c3fb27SDimitry Andric if (Ty->isReferenceType()) {
108806c3fb27SDimitry Andric // Although variables of reference type always need to be initialized, it
108906c3fb27SDimitry Andric // can happen that we can't see the initializer, so `InitExpr` may still
109006c3fb27SDimitry Andric // be null.
109106c3fb27SDimitry Andric if (InitExpr) {
10925f757f3fSDimitry Andric if (auto *InitExprLoc = getStorageLocation(*InitExpr))
109306c3fb27SDimitry Andric return *InitExprLoc;
109406c3fb27SDimitry Andric }
109506c3fb27SDimitry Andric
109606c3fb27SDimitry Andric // Even though we have an initializer, we might not get an
109706c3fb27SDimitry Andric // InitExprLoc, for example if the InitExpr is a CallExpr for which we
109806c3fb27SDimitry Andric // don't have a function body. In this case, we just invent a storage
109906c3fb27SDimitry Andric // location and value -- it's the best we can do.
110006c3fb27SDimitry Andric return createObjectInternal(D, Ty.getNonReferenceType(), nullptr);
110106c3fb27SDimitry Andric }
110206c3fb27SDimitry Andric
1103*0fca6ea1SDimitry Andric StorageLocation &Loc =
1104*0fca6ea1SDimitry Andric D ? createStorageLocation(*D) : createStorageLocation(Ty);
1105*0fca6ea1SDimitry Andric
1106*0fca6ea1SDimitry Andric if (Ty->isRecordType()) {
1107*0fca6ea1SDimitry Andric auto &RecordLoc = cast<RecordStorageLocation>(Loc);
1108*0fca6ea1SDimitry Andric if (!InitExpr)
1109*0fca6ea1SDimitry Andric initializeFieldsWithValues(RecordLoc);
1110*0fca6ea1SDimitry Andric } else {
111106c3fb27SDimitry Andric Value *Val = nullptr;
111206c3fb27SDimitry Andric if (InitExpr)
111306c3fb27SDimitry Andric // In the (few) cases where an expression is intentionally
111406c3fb27SDimitry Andric // "uninterpreted", `InitExpr` is not associated with a value. There are
111506c3fb27SDimitry Andric // two ways to handle this situation: propagate the status, so that
111606c3fb27SDimitry Andric // uninterpreted initializers result in uninterpreted variables, or
111706c3fb27SDimitry Andric // provide a default value. We choose the latter so that later refinements
111806c3fb27SDimitry Andric // of the variable can be used for reasoning about the surrounding code.
111906c3fb27SDimitry Andric // For this reason, we let this case be handled by the `createValue()`
112006c3fb27SDimitry Andric // call below.
112106c3fb27SDimitry Andric //
112206c3fb27SDimitry Andric // FIXME. If and when we interpret all language cases, change this to
112306c3fb27SDimitry Andric // assert that `InitExpr` is interpreted, rather than supplying a
112406c3fb27SDimitry Andric // default value (assuming we don't update the environment API to return
112506c3fb27SDimitry Andric // references).
11265f757f3fSDimitry Andric Val = getValue(*InitExpr);
112706c3fb27SDimitry Andric if (!Val)
112806c3fb27SDimitry Andric Val = createValue(Ty);
112906c3fb27SDimitry Andric if (Val)
113006c3fb27SDimitry Andric setValue(Loc, *Val);
1131*0fca6ea1SDimitry Andric }
113206c3fb27SDimitry Andric
113306c3fb27SDimitry Andric return Loc;
113406c3fb27SDimitry Andric }
113506c3fb27SDimitry Andric
assume(const Formula & F)11365f757f3fSDimitry Andric void Environment::assume(const Formula &F) {
11375f757f3fSDimitry Andric DACtx->addFlowConditionConstraint(FlowConditionToken, F);
113804eeddc0SDimitry Andric }
113904eeddc0SDimitry Andric
proves(const Formula & F) const11405f757f3fSDimitry Andric bool Environment::proves(const Formula &F) const {
11415f757f3fSDimitry Andric return DACtx->flowConditionImplies(FlowConditionToken, F);
114204eeddc0SDimitry Andric }
114304eeddc0SDimitry Andric
allows(const Formula & F) const11445f757f3fSDimitry Andric bool Environment::allows(const Formula &F) const {
11455f757f3fSDimitry Andric return DACtx->flowConditionAllows(FlowConditionToken, F);
114681ad6265SDimitry Andric }
114781ad6265SDimitry Andric
dump(raw_ostream & OS) const1148bdd1243dSDimitry Andric void Environment::dump(raw_ostream &OS) const {
1149*0fca6ea1SDimitry Andric llvm::DenseMap<const StorageLocation *, std::string> LocToName;
1150*0fca6ea1SDimitry Andric if (LocForRecordReturnVal != nullptr)
1151*0fca6ea1SDimitry Andric LocToName[LocForRecordReturnVal] = "(returned record)";
1152*0fca6ea1SDimitry Andric if (ThisPointeeLoc != nullptr)
1153*0fca6ea1SDimitry Andric LocToName[ThisPointeeLoc] = "this";
1154bdd1243dSDimitry Andric
1155*0fca6ea1SDimitry Andric OS << "DeclToLoc:\n";
1156*0fca6ea1SDimitry Andric for (auto [D, L] : DeclToLoc) {
1157*0fca6ea1SDimitry Andric auto Iter = LocToName.insert({L, D->getNameAsString()}).first;
1158*0fca6ea1SDimitry Andric OS << " [" << Iter->second << ", " << L << "]\n";
1159*0fca6ea1SDimitry Andric }
1160bdd1243dSDimitry Andric OS << "ExprToLoc:\n";
1161bdd1243dSDimitry Andric for (auto [E, L] : ExprToLoc)
1162bdd1243dSDimitry Andric OS << " [" << E << ", " << L << "]\n";
1163bdd1243dSDimitry Andric
11645f757f3fSDimitry Andric OS << "ExprToVal:\n";
11655f757f3fSDimitry Andric for (auto [E, V] : ExprToVal)
11665f757f3fSDimitry Andric OS << " [" << E << ", " << V << ": " << *V << "]\n";
11675f757f3fSDimitry Andric
1168bdd1243dSDimitry Andric OS << "LocToVal:\n";
1169bdd1243dSDimitry Andric for (auto [L, V] : LocToVal) {
1170*0fca6ea1SDimitry Andric OS << " [" << L;
1171*0fca6ea1SDimitry Andric if (auto Iter = LocToName.find(L); Iter != LocToName.end())
1172*0fca6ea1SDimitry Andric OS << " (" << Iter->second << ")";
1173*0fca6ea1SDimitry Andric OS << ", " << V << ": " << *V << "]\n";
1174*0fca6ea1SDimitry Andric }
1175*0fca6ea1SDimitry Andric
1176*0fca6ea1SDimitry Andric if (const FunctionDecl *Func = getCurrentFunc()) {
1177*0fca6ea1SDimitry Andric if (Func->getReturnType()->isReferenceType()) {
1178*0fca6ea1SDimitry Andric OS << "ReturnLoc: " << ReturnLoc;
1179*0fca6ea1SDimitry Andric if (auto Iter = LocToName.find(ReturnLoc); Iter != LocToName.end())
1180*0fca6ea1SDimitry Andric OS << " (" << Iter->second << ")";
1181*0fca6ea1SDimitry Andric OS << "\n";
1182*0fca6ea1SDimitry Andric } else if (Func->getReturnType()->isRecordType() ||
1183*0fca6ea1SDimitry Andric isa<CXXConstructorDecl>(Func)) {
1184*0fca6ea1SDimitry Andric OS << "LocForRecordReturnVal: " << LocForRecordReturnVal << "\n";
1185*0fca6ea1SDimitry Andric } else if (!Func->getReturnType()->isVoidType()) {
1186*0fca6ea1SDimitry Andric if (ReturnVal == nullptr)
1187*0fca6ea1SDimitry Andric OS << "ReturnVal: nullptr\n";
1188*0fca6ea1SDimitry Andric else
1189*0fca6ea1SDimitry Andric OS << "ReturnVal: " << *ReturnVal << "\n";
1190*0fca6ea1SDimitry Andric }
1191*0fca6ea1SDimitry Andric
1192*0fca6ea1SDimitry Andric if (isa<CXXMethodDecl>(Func)) {
1193*0fca6ea1SDimitry Andric OS << "ThisPointeeLoc: " << ThisPointeeLoc << "\n";
1194*0fca6ea1SDimitry Andric }
1195bdd1243dSDimitry Andric }
1196bdd1243dSDimitry Andric
11975f757f3fSDimitry Andric OS << "\n";
119806c3fb27SDimitry Andric DACtx->dumpFlowCondition(FlowConditionToken, OS);
1199fcaf7f86SDimitry Andric }
1200fcaf7f86SDimitry Andric
dump() const1201*0fca6ea1SDimitry Andric void Environment::dump() const { dump(llvm::dbgs()); }
1202*0fca6ea1SDimitry Andric
buildResultObjectMap(DataflowAnalysisContext * DACtx,const FunctionDecl * FuncDecl,RecordStorageLocation * ThisPointeeLoc,RecordStorageLocation * LocForRecordReturnVal)1203*0fca6ea1SDimitry Andric Environment::PrValueToResultObject Environment::buildResultObjectMap(
1204*0fca6ea1SDimitry Andric DataflowAnalysisContext *DACtx, const FunctionDecl *FuncDecl,
1205*0fca6ea1SDimitry Andric RecordStorageLocation *ThisPointeeLoc,
1206*0fca6ea1SDimitry Andric RecordStorageLocation *LocForRecordReturnVal) {
1207*0fca6ea1SDimitry Andric assert(FuncDecl->doesThisDeclarationHaveABody());
1208*0fca6ea1SDimitry Andric
1209*0fca6ea1SDimitry Andric PrValueToResultObject Map = buildResultObjectMap(
1210*0fca6ea1SDimitry Andric DACtx, FuncDecl->getBody(), ThisPointeeLoc, LocForRecordReturnVal);
1211*0fca6ea1SDimitry Andric
1212*0fca6ea1SDimitry Andric ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
1213*0fca6ea1SDimitry Andric if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(FuncDecl))
1214*0fca6ea1SDimitry Andric Visitor.TraverseConstructorInits(Ctor, ThisPointeeLoc);
1215*0fca6ea1SDimitry Andric
1216*0fca6ea1SDimitry Andric return Map;
1217*0fca6ea1SDimitry Andric }
1218*0fca6ea1SDimitry Andric
buildResultObjectMap(DataflowAnalysisContext * DACtx,Stmt * S,RecordStorageLocation * ThisPointeeLoc,RecordStorageLocation * LocForRecordReturnVal)1219*0fca6ea1SDimitry Andric Environment::PrValueToResultObject Environment::buildResultObjectMap(
1220*0fca6ea1SDimitry Andric DataflowAnalysisContext *DACtx, Stmt *S,
1221*0fca6ea1SDimitry Andric RecordStorageLocation *ThisPointeeLoc,
1222*0fca6ea1SDimitry Andric RecordStorageLocation *LocForRecordReturnVal) {
1223*0fca6ea1SDimitry Andric PrValueToResultObject Map;
1224*0fca6ea1SDimitry Andric ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
1225*0fca6ea1SDimitry Andric Visitor.TraverseStmt(S);
1226*0fca6ea1SDimitry Andric return Map;
1227bdd1243dSDimitry Andric }
1228bdd1243dSDimitry Andric
getImplicitObjectLocation(const CXXMemberCallExpr & MCE,const Environment & Env)12295f757f3fSDimitry Andric RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
123006c3fb27SDimitry Andric const Environment &Env) {
123106c3fb27SDimitry Andric Expr *ImplicitObject = MCE.getImplicitObjectArgument();
123206c3fb27SDimitry Andric if (ImplicitObject == nullptr)
123306c3fb27SDimitry Andric return nullptr;
123406c3fb27SDimitry Andric if (ImplicitObject->getType()->isPointerType()) {
1235cb14a3feSDimitry Andric if (auto *Val = Env.get<PointerValue>(*ImplicitObject))
12365f757f3fSDimitry Andric return &cast<RecordStorageLocation>(Val->getPointeeLoc());
123706c3fb27SDimitry Andric return nullptr;
123806c3fb27SDimitry Andric }
12395f757f3fSDimitry Andric return cast_or_null<RecordStorageLocation>(
12405f757f3fSDimitry Andric Env.getStorageLocation(*ImplicitObject));
124106c3fb27SDimitry Andric }
124206c3fb27SDimitry Andric
getBaseObjectLocation(const MemberExpr & ME,const Environment & Env)12435f757f3fSDimitry Andric RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
124406c3fb27SDimitry Andric const Environment &Env) {
124506c3fb27SDimitry Andric Expr *Base = ME.getBase();
124606c3fb27SDimitry Andric if (Base == nullptr)
124706c3fb27SDimitry Andric return nullptr;
124806c3fb27SDimitry Andric if (ME.isArrow()) {
1249cb14a3feSDimitry Andric if (auto *Val = Env.get<PointerValue>(*Base))
12505f757f3fSDimitry Andric return &cast<RecordStorageLocation>(Val->getPointeeLoc());
125106c3fb27SDimitry Andric return nullptr;
125206c3fb27SDimitry Andric }
1253cb14a3feSDimitry Andric return Env.get<RecordStorageLocation>(*Base);
125406c3fb27SDimitry Andric }
125506c3fb27SDimitry Andric
125604eeddc0SDimitry Andric } // namespace dataflow
125704eeddc0SDimitry Andric } // namespace clang
1258