xref: /llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (revision 65c36179be68dda0d1cc5d7e5c5b312a6b52cc0e)
1af7bc39bSStanislav Gatev //===-- DataflowEnvironment.cpp ---------------------------------*- C++ -*-===//
2af7bc39bSStanislav Gatev //
3af7bc39bSStanislav Gatev // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4af7bc39bSStanislav Gatev // See https://llvm.org/LICENSE.txt for license information.
5af7bc39bSStanislav Gatev // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6af7bc39bSStanislav Gatev //
7af7bc39bSStanislav Gatev //===----------------------------------------------------------------------===//
8af7bc39bSStanislav Gatev //
9af7bc39bSStanislav Gatev //  This file defines an Environment class that is used by dataflow analyses
10af7bc39bSStanislav Gatev //  that run over Control-Flow Graphs (CFGs) to keep track of the state of the
11af7bc39bSStanislav Gatev //  program at given program points.
12af7bc39bSStanislav Gatev //
13af7bc39bSStanislav Gatev //===----------------------------------------------------------------------===//
14af7bc39bSStanislav Gatev 
15af7bc39bSStanislav Gatev #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
16af7bc39bSStanislav Gatev #include "clang/AST/Decl.h"
1799f7d55eSStanislav Gatev #include "clang/AST/DeclCXX.h"
183fed312dSSamira Bazuzi #include "clang/AST/ExprCXX.h"
1971f1932bSmartinboehme #include "clang/AST/RecursiveASTVisitor.h"
2080d9ae9cSSamira Bazuzi #include "clang/AST/Stmt.h"
21af7bc39bSStanislav Gatev #include "clang/AST/Type.h"
229ec8c961SSamira Bazuzi #include "clang/Analysis/FlowSensitive/ASTOps.h"
2380d9ae9cSSamira Bazuzi #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
24af7bc39bSStanislav Gatev #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
25af7bc39bSStanislav Gatev #include "clang/Analysis/FlowSensitive/Value.h"
26af7bc39bSStanislav Gatev #include "llvm/ADT/DenseMap.h"
27af7bc39bSStanislav Gatev #include "llvm/ADT/DenseSet.h"
287d935d08SSam McCall #include "llvm/ADT/MapVector.h"
2980d9ae9cSSamira Bazuzi #include "llvm/ADT/PointerUnion.h"
30941959d6SDmitri Gribenko #include "llvm/ADT/STLExtras.h"
31e8fce958Smartinboehme #include "llvm/ADT/ScopeExit.h"
32e7481f6eSStanislav Gatev #include "llvm/Support/ErrorHandling.h"
3380d9ae9cSSamira Bazuzi #include <algorithm>
3403dff121SStanislav Gatev #include <cassert>
3580d9ae9cSSamira Bazuzi #include <memory>
36af7bc39bSStanislav Gatev #include <utility>
37af7bc39bSStanislav Gatev 
3871f1932bSmartinboehme #define DEBUG_TYPE "dataflow"
3971f1932bSmartinboehme 
40af7bc39bSStanislav Gatev namespace clang {
41af7bc39bSStanislav Gatev namespace dataflow {
42af7bc39bSStanislav Gatev 
43208c25fcSYitzhak Mandelbaum // FIXME: convert these to parameters of the analysis or environment. Current
44208c25fcSYitzhak Mandelbaum // settings have been experimentaly validated, but only for a particular
45208c25fcSYitzhak Mandelbaum // analysis.
46208c25fcSYitzhak Mandelbaum static constexpr int MaxCompositeValueDepth = 3;
47208c25fcSYitzhak Mandelbaum static constexpr int MaxCompositeValueSize = 1000;
48208c25fcSYitzhak Mandelbaum 
49af7bc39bSStanislav Gatev /// Returns a map consisting of key-value entries that are present in both maps.
50c4c59192Smartinboehme static llvm::DenseMap<const ValueDecl *, StorageLocation *> intersectDeclToLoc(
51c4c59192Smartinboehme     const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc1,
52c4c59192Smartinboehme     const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc2) {
53c4c59192Smartinboehme   llvm::DenseMap<const ValueDecl *, StorageLocation *> Result;
54c4c59192Smartinboehme   for (auto &Entry : DeclToLoc1) {
55c4c59192Smartinboehme     auto It = DeclToLoc2.find(Entry.first);
56c4c59192Smartinboehme     if (It != DeclToLoc2.end() && Entry.second == It->second)
57af7bc39bSStanislav Gatev       Result.insert({Entry.first, Entry.second});
58af7bc39bSStanislav Gatev   }
59af7bc39bSStanislav Gatev   return Result;
60af7bc39bSStanislav Gatev }
61af7bc39bSStanislav Gatev 
62d5aecf0cSmartinboehme // Performs a join on either `ExprToLoc` or `ExprToVal`.
63d5aecf0cSmartinboehme // The maps must be consistent in the sense that any entries for the same
64d5aecf0cSmartinboehme // expression must map to the same location / value. This is the case if we are
65d5aecf0cSmartinboehme // performing a join for control flow within a full-expression (which is the
66d5aecf0cSmartinboehme // only case when this function should be used).
67*65c36179SCongcong Cai template <typename MapT>
68*65c36179SCongcong Cai static MapT joinExprMaps(const MapT &Map1, const MapT &Map2) {
69d5aecf0cSmartinboehme   MapT Result = Map1;
70d5aecf0cSmartinboehme 
71d5aecf0cSmartinboehme   for (const auto &Entry : Map2) {
72d5aecf0cSmartinboehme     [[maybe_unused]] auto [It, Inserted] = Result.insert(Entry);
73d5aecf0cSmartinboehme     // If there was an existing entry, its value should be the same as for the
74d5aecf0cSmartinboehme     // entry we were trying to insert.
75d5aecf0cSmartinboehme     assert(It->second == Entry.second);
76d5aecf0cSmartinboehme   }
77d5aecf0cSmartinboehme 
78d5aecf0cSmartinboehme   return Result;
79d5aecf0cSmartinboehme }
80d5aecf0cSmartinboehme 
8180f0dc3aSYitzhak Mandelbaum // Whether to consider equivalent two values with an unknown relation.
8280f0dc3aSYitzhak Mandelbaum //
8380f0dc3aSYitzhak Mandelbaum // FIXME: this function is a hack enabling unsoundness to support
8480f0dc3aSYitzhak Mandelbaum // convergence. Once we have widening support for the reference/pointer and
8580f0dc3aSYitzhak Mandelbaum // struct built-in models, this should be unconditionally `false` (and inlined
8680f0dc3aSYitzhak Mandelbaum // as such at its call sites).
8780f0dc3aSYitzhak Mandelbaum static bool equateUnknownValues(Value::Kind K) {
8880f0dc3aSYitzhak Mandelbaum   switch (K) {
8980f0dc3aSYitzhak Mandelbaum   case Value::Kind::Integer:
9080f0dc3aSYitzhak Mandelbaum   case Value::Kind::Pointer:
9180f0dc3aSYitzhak Mandelbaum     return true;
9280f0dc3aSYitzhak Mandelbaum   default:
9380f0dc3aSYitzhak Mandelbaum     return false;
9480f0dc3aSYitzhak Mandelbaum   }
9580f0dc3aSYitzhak Mandelbaum }
9680f0dc3aSYitzhak Mandelbaum 
9784dd12b2SYitzhak Mandelbaum static bool compareDistinctValues(QualType Type, Value &Val1,
9884dd12b2SYitzhak Mandelbaum                                   const Environment &Env1, Value &Val2,
9984dd12b2SYitzhak Mandelbaum                                   const Environment &Env2,
10084dd12b2SYitzhak Mandelbaum                                   Environment::ValueModel &Model) {
10184dd12b2SYitzhak Mandelbaum   // Note: Potentially costly, but, for booleans, we could check whether both
10284dd12b2SYitzhak Mandelbaum   // can be proven equivalent in their respective environments.
10384dd12b2SYitzhak Mandelbaum 
10484dd12b2SYitzhak Mandelbaum   // FIXME: move the reference/pointers logic from `areEquivalentValues` to here
10584dd12b2SYitzhak Mandelbaum   // and implement separate, join/widen specific handling for
10684dd12b2SYitzhak Mandelbaum   // reference/pointers.
10784dd12b2SYitzhak Mandelbaum   switch (Model.compare(Type, Val1, Env1, Val2, Env2)) {
10884dd12b2SYitzhak Mandelbaum   case ComparisonResult::Same:
10984dd12b2SYitzhak Mandelbaum     return true;
11084dd12b2SYitzhak Mandelbaum   case ComparisonResult::Different:
11184dd12b2SYitzhak Mandelbaum     return false;
11284dd12b2SYitzhak Mandelbaum   case ComparisonResult::Unknown:
11380f0dc3aSYitzhak Mandelbaum     return equateUnknownValues(Val1.getKind());
11484dd12b2SYitzhak Mandelbaum   }
11584dd12b2SYitzhak Mandelbaum   llvm_unreachable("All cases covered in switch");
11684dd12b2SYitzhak Mandelbaum }
11784dd12b2SYitzhak Mandelbaum 
118672fb27bSYitzhak Mandelbaum /// Attempts to join distinct values `Val1` and `Val2` in `Env1` and `Env2`,
119672fb27bSYitzhak Mandelbaum /// respectively, of the same type `Type`. Joining generally produces a single
12001db1036SYitzhak Mandelbaum /// value that (soundly) approximates the two inputs, although the actual
12101db1036SYitzhak Mandelbaum /// meaning depends on `Model`.
122672fb27bSYitzhak Mandelbaum static Value *joinDistinctValues(QualType Type, Value &Val1,
12384dd12b2SYitzhak Mandelbaum                                  const Environment &Env1, Value &Val2,
12437b4782eSYitzhak Mandelbaum                                  const Environment &Env2,
125672fb27bSYitzhak Mandelbaum                                  Environment &JoinedEnv,
12601db1036SYitzhak Mandelbaum                                  Environment::ValueModel &Model) {
12701db1036SYitzhak Mandelbaum   // Join distinct boolean values preserving information about the constraints
128955a05a2SStanislav Gatev   // in the respective path conditions.
129daa316bcSYitzhak Mandelbaum   if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) {
130daa316bcSYitzhak Mandelbaum     // FIXME: Checking both values should be unnecessary, since they should have
131daa316bcSYitzhak Mandelbaum     // a consistent shape.  However, right now we can end up with BoolValue's in
132daa316bcSYitzhak Mandelbaum     // integer-typed variables due to our incorrect handling of
133daa316bcSYitzhak Mandelbaum     // boolean-to-integer casts (we just propagate the BoolValue to the result
134daa316bcSYitzhak Mandelbaum     // of the cast). So, a join can encounter an integer in one branch but a
135daa316bcSYitzhak Mandelbaum     // bool in the other.
136daa316bcSYitzhak Mandelbaum     // For example:
137daa316bcSYitzhak Mandelbaum     // ```
138eda2eaabSJun Zhang     // std::optional<bool> o;
139eda2eaabSJun Zhang     // int x;
140daa316bcSYitzhak Mandelbaum     // if (o.has_value())
141eda2eaabSJun Zhang     //   x = o.value();
142daa316bcSYitzhak Mandelbaum     // ```
143fc9821a8SSam McCall     auto &Expr1 = cast<BoolValue>(Val1).formula();
144fc9821a8SSam McCall     auto &Expr2 = cast<BoolValue>(Val2).formula();
145672fb27bSYitzhak Mandelbaum     auto &A = JoinedEnv.arena();
146672fb27bSYitzhak Mandelbaum     auto &JoinedVal = A.makeAtomRef(A.makeAtom());
147672fb27bSYitzhak Mandelbaum     JoinedEnv.assume(
148fc9821a8SSam McCall         A.makeOr(A.makeAnd(A.makeAtomRef(Env1.getFlowConditionToken()),
149672fb27bSYitzhak Mandelbaum                            A.makeEquals(JoinedVal, Expr1)),
150fc9821a8SSam McCall                  A.makeAnd(A.makeAtomRef(Env2.getFlowConditionToken()),
151672fb27bSYitzhak Mandelbaum                            A.makeEquals(JoinedVal, Expr2))));
152672fb27bSYitzhak Mandelbaum     return &A.makeBoolValue(JoinedVal);
15301db1036SYitzhak Mandelbaum   }
15401db1036SYitzhak Mandelbaum 
155e8fce958Smartinboehme   Value *JoinedVal = JoinedEnv.createValue(Type);
156672fb27bSYitzhak Mandelbaum   if (JoinedVal)
157672fb27bSYitzhak Mandelbaum     Model.join(Type, Val1, Env1, Val2, Env2, *JoinedVal, JoinedEnv);
15801db1036SYitzhak Mandelbaum 
159672fb27bSYitzhak Mandelbaum   return JoinedVal;
16001db1036SYitzhak Mandelbaum }
16101db1036SYitzhak Mandelbaum 
162bbd259afSYitzhak Mandelbaum static WidenResult widenDistinctValues(QualType Type, Value &Prev,
163bbd259afSYitzhak Mandelbaum                                        const Environment &PrevEnv,
164bbd259afSYitzhak Mandelbaum                                        Value &Current, Environment &CurrentEnv,
16584dd12b2SYitzhak Mandelbaum                                        Environment::ValueModel &Model) {
16684dd12b2SYitzhak Mandelbaum   // Boolean-model widening.
167b9208ce3Smartinboehme   if (isa<BoolValue>(Prev) && isa<BoolValue>(Current)) {
168b9208ce3Smartinboehme     // FIXME: Checking both values should be unnecessary, but we can currently
169b9208ce3Smartinboehme     // end up with `BoolValue`s in integer-typed variables. See comment in
170b9208ce3Smartinboehme     // `joinDistinctValues()` for details.
171b9208ce3Smartinboehme     auto &PrevBool = cast<BoolValue>(Prev);
172b9208ce3Smartinboehme     auto &CurBool = cast<BoolValue>(Current);
173b9208ce3Smartinboehme 
17484dd12b2SYitzhak Mandelbaum     if (isa<TopBoolValue>(Prev))
175bbd259afSYitzhak Mandelbaum       // Safe to return `Prev` here, because Top is never dependent on the
176bbd259afSYitzhak Mandelbaum       // environment.
177bbd259afSYitzhak Mandelbaum       return {&Prev, LatticeEffect::Unchanged};
1785bd643e1Smartinboehme 
1795bd643e1Smartinboehme     // We may need to widen to Top, but before we do so, check whether both
1805bd643e1Smartinboehme     // values are implied to be either true or false in the current environment.
1815bd643e1Smartinboehme     // In that case, we can simply return a literal instead.
182b9208ce3Smartinboehme     bool TruePrev = PrevEnv.proves(PrevBool.formula());
1835bd643e1Smartinboehme     bool TrueCur = CurrentEnv.proves(CurBool.formula());
1845bd643e1Smartinboehme     if (TruePrev && TrueCur)
185bbd259afSYitzhak Mandelbaum       return {&CurrentEnv.getBoolLiteralValue(true), LatticeEffect::Unchanged};
1865bd643e1Smartinboehme     if (!TruePrev && !TrueCur &&
187b9208ce3Smartinboehme         PrevEnv.proves(PrevEnv.arena().makeNot(PrevBool.formula())) &&
1885bd643e1Smartinboehme         CurrentEnv.proves(CurrentEnv.arena().makeNot(CurBool.formula())))
189bbd259afSYitzhak Mandelbaum       return {&CurrentEnv.getBoolLiteralValue(false), LatticeEffect::Unchanged};
1905bd643e1Smartinboehme 
191bbd259afSYitzhak Mandelbaum     return {&CurrentEnv.makeTopBoolValue(), LatticeEffect::Changed};
19284dd12b2SYitzhak Mandelbaum   }
19384dd12b2SYitzhak Mandelbaum 
19484dd12b2SYitzhak Mandelbaum   // FIXME: Add other built-in model widening.
19584dd12b2SYitzhak Mandelbaum 
19684dd12b2SYitzhak Mandelbaum   // Custom-model widening.
197bbd259afSYitzhak Mandelbaum   if (auto Result = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv))
198bbd259afSYitzhak Mandelbaum     return *Result;
19984dd12b2SYitzhak Mandelbaum 
200bbd259afSYitzhak Mandelbaum   return {&Current, equateUnknownValues(Prev.getKind())
201bbd259afSYitzhak Mandelbaum                         ? LatticeEffect::Unchanged
202bbd259afSYitzhak Mandelbaum                         : LatticeEffect::Changed};
20384dd12b2SYitzhak Mandelbaum }
20484dd12b2SYitzhak Mandelbaum 
205330d5bcbSMartin Braenne // Returns whether the values in `Map1` and `Map2` compare equal for those
206330d5bcbSMartin Braenne // keys that `Map1` and `Map2` have in common.
207330d5bcbSMartin Braenne template <typename Key>
208*65c36179SCongcong Cai static bool compareKeyToValueMaps(const llvm::MapVector<Key, Value *> &Map1,
209330d5bcbSMartin Braenne                                   const llvm::MapVector<Key, Value *> &Map2,
210*65c36179SCongcong Cai                                   const Environment &Env1,
211*65c36179SCongcong Cai                                   const Environment &Env2,
212330d5bcbSMartin Braenne                                   Environment::ValueModel &Model) {
213330d5bcbSMartin Braenne   for (auto &Entry : Map1) {
214330d5bcbSMartin Braenne     Key K = Entry.first;
215330d5bcbSMartin Braenne     assert(K != nullptr);
216330d5bcbSMartin Braenne 
217330d5bcbSMartin Braenne     Value *Val = Entry.second;
218330d5bcbSMartin Braenne     assert(Val != nullptr);
219330d5bcbSMartin Braenne 
220330d5bcbSMartin Braenne     auto It = Map2.find(K);
221330d5bcbSMartin Braenne     if (It == Map2.end())
222330d5bcbSMartin Braenne       continue;
223330d5bcbSMartin Braenne     assert(It->second != nullptr);
224330d5bcbSMartin Braenne 
225330d5bcbSMartin Braenne     if (!areEquivalentValues(*Val, *It->second) &&
226330d5bcbSMartin Braenne         !compareDistinctValues(K->getType(), *Val, Env1, *It->second, Env2,
227330d5bcbSMartin Braenne                                Model))
228330d5bcbSMartin Braenne       return false;
229330d5bcbSMartin Braenne   }
230330d5bcbSMartin Braenne 
231330d5bcbSMartin Braenne   return true;
232330d5bcbSMartin Braenne }
233330d5bcbSMartin Braenne 
234c4c59192Smartinboehme // Perform a join on two `LocToVal` maps.
235c4c59192Smartinboehme static llvm::MapVector<const StorageLocation *, Value *>
236c4c59192Smartinboehme joinLocToVal(const llvm::MapVector<const StorageLocation *, Value *> &LocToVal,
237c4c59192Smartinboehme              const llvm::MapVector<const StorageLocation *, Value *> &LocToVal2,
238330d5bcbSMartin Braenne              const Environment &Env1, const Environment &Env2,
239330d5bcbSMartin Braenne              Environment &JoinedEnv, Environment::ValueModel &Model) {
240c4c59192Smartinboehme   llvm::MapVector<const StorageLocation *, Value *> Result;
241c4c59192Smartinboehme   for (auto &Entry : LocToVal) {
242c4c59192Smartinboehme     const StorageLocation *Loc = Entry.first;
243c4c59192Smartinboehme     assert(Loc != nullptr);
244330d5bcbSMartin Braenne 
245330d5bcbSMartin Braenne     Value *Val = Entry.second;
246330d5bcbSMartin Braenne     assert(Val != nullptr);
247330d5bcbSMartin Braenne 
248c4c59192Smartinboehme     auto It = LocToVal2.find(Loc);
249c4c59192Smartinboehme     if (It == LocToVal2.end())
250330d5bcbSMartin Braenne       continue;
251330d5bcbSMartin Braenne     assert(It->second != nullptr);
252330d5bcbSMartin Braenne 
2539ba6961cSmartinboehme     if (Value *JoinedVal = Environment::joinValues(
2549ba6961cSmartinboehme             Loc->getType(), Val, Env1, It->second, Env2, JoinedEnv, Model)) {
255672fb27bSYitzhak Mandelbaum       Result.insert({Loc, JoinedVal});
256330d5bcbSMartin Braenne     }
257330d5bcbSMartin Braenne   }
258330d5bcbSMartin Braenne 
259c4c59192Smartinboehme   return Result;
260330d5bcbSMartin Braenne }
261330d5bcbSMartin Braenne 
262330d5bcbSMartin Braenne // Perform widening on either `LocToVal` or `ExprToVal`. `Key` must be either
263330d5bcbSMartin Braenne // `const StorageLocation *` or `const Expr *`.
264330d5bcbSMartin Braenne template <typename Key>
265*65c36179SCongcong Cai static llvm::MapVector<Key, Value *>
266330d5bcbSMartin Braenne widenKeyToValueMap(const llvm::MapVector<Key, Value *> &CurMap,
267330d5bcbSMartin Braenne                    const llvm::MapVector<Key, Value *> &PrevMap,
268330d5bcbSMartin Braenne                    Environment &CurEnv, const Environment &PrevEnv,
269bbd259afSYitzhak Mandelbaum                    Environment::ValueModel &Model, LatticeEffect &Effect) {
270330d5bcbSMartin Braenne   llvm::MapVector<Key, Value *> WidenedMap;
271330d5bcbSMartin Braenne   for (auto &Entry : CurMap) {
272330d5bcbSMartin Braenne     Key K = Entry.first;
273330d5bcbSMartin Braenne     assert(K != nullptr);
274330d5bcbSMartin Braenne 
275330d5bcbSMartin Braenne     Value *Val = Entry.second;
276330d5bcbSMartin Braenne     assert(Val != nullptr);
277330d5bcbSMartin Braenne 
278330d5bcbSMartin Braenne     auto PrevIt = PrevMap.find(K);
279330d5bcbSMartin Braenne     if (PrevIt == PrevMap.end())
280330d5bcbSMartin Braenne       continue;
281330d5bcbSMartin Braenne     assert(PrevIt->second != nullptr);
282330d5bcbSMartin Braenne 
283330d5bcbSMartin Braenne     if (areEquivalentValues(*Val, *PrevIt->second)) {
284330d5bcbSMartin Braenne       WidenedMap.insert({K, Val});
285330d5bcbSMartin Braenne       continue;
286330d5bcbSMartin Braenne     }
287330d5bcbSMartin Braenne 
288bbd259afSYitzhak Mandelbaum     auto [WidenedVal, ValEffect] = widenDistinctValues(
289bbd259afSYitzhak Mandelbaum         K->getType(), *PrevIt->second, PrevEnv, *Val, CurEnv, Model);
290bbd259afSYitzhak Mandelbaum     WidenedMap.insert({K, WidenedVal});
291bbd259afSYitzhak Mandelbaum     if (ValEffect == LatticeEffect::Changed)
292bbd259afSYitzhak Mandelbaum       Effect = LatticeEffect::Changed;
293330d5bcbSMartin Braenne   }
294330d5bcbSMartin Braenne 
295330d5bcbSMartin Braenne   return WidenedMap;
296330d5bcbSMartin Braenne }
297330d5bcbSMartin Braenne 
29871f1932bSmartinboehme namespace {
29971f1932bSmartinboehme 
30071f1932bSmartinboehme // Visitor that builds a map from record prvalues to result objects.
30180d9ae9cSSamira Bazuzi // For each result object that it encounters, it propagates the storage location
30280d9ae9cSSamira Bazuzi // of the result object to all record prvalues that can initialize it.
303dde802b1SSirraide class ResultObjectVisitor : public AnalysisASTVisitor {
30471f1932bSmartinboehme public:
30571f1932bSmartinboehme   // `ResultObjectMap` will be filled with a map from record prvalues to result
30680d9ae9cSSamira Bazuzi   // object. If this visitor will traverse a function that returns a record by
30780d9ae9cSSamira Bazuzi   // value, `LocForRecordReturnVal` is the location to which this record should
30880d9ae9cSSamira Bazuzi   // be written; otherwise, it is null.
30971f1932bSmartinboehme   explicit ResultObjectVisitor(
31071f1932bSmartinboehme       llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap,
31171f1932bSmartinboehme       RecordStorageLocation *LocForRecordReturnVal,
31271f1932bSmartinboehme       DataflowAnalysisContext &DACtx)
31371f1932bSmartinboehme       : ResultObjectMap(ResultObjectMap),
31471f1932bSmartinboehme         LocForRecordReturnVal(LocForRecordReturnVal), DACtx(DACtx) {}
31571f1932bSmartinboehme 
31671f1932bSmartinboehme   // Traverse all member and base initializers of `Ctor`. This function is not
31771f1932bSmartinboehme   // called by `RecursiveASTVisitor`; it should be called manually if we are
31871f1932bSmartinboehme   // analyzing a constructor. `ThisPointeeLoc` is the storage location that
31971f1932bSmartinboehme   // `this` points to.
320dde802b1SSirraide   void traverseConstructorInits(const CXXConstructorDecl *Ctor,
32171f1932bSmartinboehme                                 RecordStorageLocation *ThisPointeeLoc) {
32271f1932bSmartinboehme     assert(ThisPointeeLoc != nullptr);
32371f1932bSmartinboehme     for (const CXXCtorInitializer *Init : Ctor->inits()) {
32471f1932bSmartinboehme       Expr *InitExpr = Init->getInit();
32571f1932bSmartinboehme       if (FieldDecl *Field = Init->getMember();
32671f1932bSmartinboehme           Field != nullptr && Field->getType()->isRecordType()) {
32771f1932bSmartinboehme         PropagateResultObject(InitExpr, cast<RecordStorageLocation>(
32871f1932bSmartinboehme                                             ThisPointeeLoc->getChild(*Field)));
32971f1932bSmartinboehme       } else if (Init->getBaseClass()) {
33071f1932bSmartinboehme         PropagateResultObject(InitExpr, ThisPointeeLoc);
33171f1932bSmartinboehme       }
33271f1932bSmartinboehme 
33371f1932bSmartinboehme       // Ensure that any result objects within `InitExpr` (e.g. temporaries)
33471f1932bSmartinboehme       // are also propagated to the prvalues that initialize them.
33571f1932bSmartinboehme       TraverseStmt(InitExpr);
33671f1932bSmartinboehme 
33771f1932bSmartinboehme       // If this is a `CXXDefaultInitExpr`, also propagate any result objects
33871f1932bSmartinboehme       // within the default expression.
33971f1932bSmartinboehme       if (auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(InitExpr))
34071f1932bSmartinboehme         TraverseStmt(DefaultInit->getExpr());
34171f1932bSmartinboehme     }
34271f1932bSmartinboehme   }
34371f1932bSmartinboehme 
344dde802b1SSirraide   bool VisitVarDecl(VarDecl *VD) override {
34571f1932bSmartinboehme     if (VD->getType()->isRecordType() && VD->hasInit())
34671f1932bSmartinboehme       PropagateResultObject(
34771f1932bSmartinboehme           VD->getInit(),
34871f1932bSmartinboehme           &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*VD)));
34971f1932bSmartinboehme     return true;
35071f1932bSmartinboehme   }
35171f1932bSmartinboehme 
352dde802b1SSirraide   bool VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE) override {
35371f1932bSmartinboehme     if (MTE->getType()->isRecordType())
35471f1932bSmartinboehme       PropagateResultObject(
35571f1932bSmartinboehme           MTE->getSubExpr(),
35671f1932bSmartinboehme           &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*MTE)));
35771f1932bSmartinboehme     return true;
35871f1932bSmartinboehme   }
35971f1932bSmartinboehme 
360dde802b1SSirraide   bool VisitReturnStmt(ReturnStmt *Return) override {
36171f1932bSmartinboehme     Expr *RetValue = Return->getRetValue();
36271f1932bSmartinboehme     if (RetValue != nullptr && RetValue->getType()->isRecordType() &&
36371f1932bSmartinboehme         RetValue->isPRValue())
36471f1932bSmartinboehme       PropagateResultObject(RetValue, LocForRecordReturnVal);
36571f1932bSmartinboehme     return true;
36671f1932bSmartinboehme   }
36771f1932bSmartinboehme 
368dde802b1SSirraide   bool VisitExpr(Expr *E) override {
36971f1932bSmartinboehme     // Clang's AST can have record-type prvalues without a result object -- for
37071f1932bSmartinboehme     // example as full-expressions contained in a compound statement or as
37171f1932bSmartinboehme     // arguments of call expressions. We notice this if we get here and a
37271f1932bSmartinboehme     // storage location has not yet been associated with `E`. In this case,
37371f1932bSmartinboehme     // treat this as if it was a `MaterializeTemporaryExpr`.
37471f1932bSmartinboehme     if (E->isPRValue() && E->getType()->isRecordType() &&
37571f1932bSmartinboehme         !ResultObjectMap.contains(E))
37671f1932bSmartinboehme       PropagateResultObject(
37771f1932bSmartinboehme           E, &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*E)));
37871f1932bSmartinboehme     return true;
37971f1932bSmartinboehme   }
38071f1932bSmartinboehme 
381ca7d9442Smartinboehme   void
382ca7d9442Smartinboehme   PropagateResultObjectToRecordInitList(const RecordInitListHelper &InitList,
383ca7d9442Smartinboehme                                         RecordStorageLocation *Loc) {
384ca7d9442Smartinboehme     for (auto [Base, Init] : InitList.base_inits()) {
385ca7d9442Smartinboehme       assert(Base->getType().getCanonicalType() ==
386ca7d9442Smartinboehme              Init->getType().getCanonicalType());
387ca7d9442Smartinboehme 
388ca7d9442Smartinboehme       // Storage location for the base class is the same as that of the
389ca7d9442Smartinboehme       // derived class because we "flatten" the object hierarchy and put all
390ca7d9442Smartinboehme       // fields in `RecordStorageLocation` of the derived class.
391ca7d9442Smartinboehme       PropagateResultObject(Init, Loc);
392ca7d9442Smartinboehme     }
393ca7d9442Smartinboehme 
394ca7d9442Smartinboehme     for (auto [Field, Init] : InitList.field_inits()) {
395ca7d9442Smartinboehme       // Fields of non-record type are handled in
396ca7d9442Smartinboehme       // `TransferVisitor::VisitInitListExpr()`.
397ca7d9442Smartinboehme       if (Field->getType()->isRecordType())
39814122106Smartinboehme         PropagateResultObject(
39914122106Smartinboehme             Init, cast<RecordStorageLocation>(Loc->getChild(*Field)));
400ca7d9442Smartinboehme     }
401ca7d9442Smartinboehme   }
402ca7d9442Smartinboehme 
40371f1932bSmartinboehme   // Assigns `Loc` as the result object location of `E`, then propagates the
40471f1932bSmartinboehme   // location to all lower-level prvalues that initialize the same object as
40571f1932bSmartinboehme   // `E` (or one of its base classes or member variables).
40671f1932bSmartinboehme   void PropagateResultObject(Expr *E, RecordStorageLocation *Loc) {
40771f1932bSmartinboehme     if (!E->isPRValue() || !E->getType()->isRecordType()) {
40871f1932bSmartinboehme       assert(false);
40971f1932bSmartinboehme       // Ensure we don't propagate the result object if we hit this in a
41071f1932bSmartinboehme       // release build.
41171f1932bSmartinboehme       return;
41271f1932bSmartinboehme     }
41371f1932bSmartinboehme 
41471f1932bSmartinboehme     ResultObjectMap[E] = Loc;
41571f1932bSmartinboehme 
41671f1932bSmartinboehme     // The following AST node kinds are "original initializers": They are the
41771f1932bSmartinboehme     // lowest-level AST node that initializes a given object, and nothing
41871f1932bSmartinboehme     // below them can initialize the same object (or part of it).
419b5f2cecfSmartinboehme     if (isa<CXXConstructExpr>(E) || isa<CallExpr>(E) || isa<LambdaExpr>(E) ||
4203fed312dSSamira Bazuzi         isa<CXXDefaultArgExpr>(E) || isa<CXXStdInitializerListExpr>(E) ||
42149cb1701SPasquale Riello         isa<AtomicExpr>(E) || isa<CXXInheritedCtorInitExpr>(E) ||
422b5f2cecfSmartinboehme         // We treat `BuiltinBitCastExpr` as an "original initializer" too as
423b5f2cecfSmartinboehme         // it may not even be casting from a record type -- and even if it is,
424b5f2cecfSmartinboehme         // the two objects are in general of unrelated type.
425b5f2cecfSmartinboehme         isa<BuiltinBitCastExpr>(E)) {
42671f1932bSmartinboehme       return;
42771f1932bSmartinboehme     }
428b5f2cecfSmartinboehme     if (auto *Op = dyn_cast<BinaryOperator>(E);
429b5f2cecfSmartinboehme         Op && Op->getOpcode() == BO_Cmp) {
430b5f2cecfSmartinboehme       // Builtin `<=>` returns a `std::strong_ordering` object.
4313c6f91e5Smartinboehme       return;
4323c6f91e5Smartinboehme     }
433b5f2cecfSmartinboehme 
434b5f2cecfSmartinboehme     if (auto *InitList = dyn_cast<InitListExpr>(E)) {
43571f1932bSmartinboehme       if (!InitList->isSemanticForm())
43671f1932bSmartinboehme         return;
43771f1932bSmartinboehme       if (InitList->isTransparent()) {
43871f1932bSmartinboehme         PropagateResultObject(InitList->getInit(0), Loc);
43971f1932bSmartinboehme         return;
44071f1932bSmartinboehme       }
44171f1932bSmartinboehme 
442ca7d9442Smartinboehme       PropagateResultObjectToRecordInitList(RecordInitListHelper(InitList),
443ca7d9442Smartinboehme                                             Loc);
444ca7d9442Smartinboehme       return;
44571f1932bSmartinboehme     }
44671f1932bSmartinboehme 
447ca7d9442Smartinboehme     if (auto *ParenInitList = dyn_cast<CXXParenListInitExpr>(E)) {
448ca7d9442Smartinboehme       PropagateResultObjectToRecordInitList(RecordInitListHelper(ParenInitList),
449ca7d9442Smartinboehme                                             Loc);
45071f1932bSmartinboehme       return;
45171f1932bSmartinboehme     }
452b5f2cecfSmartinboehme 
453b5f2cecfSmartinboehme     if (auto *Op = dyn_cast<BinaryOperator>(E); Op && Op->isCommaOp()) {
454b5f2cecfSmartinboehme       PropagateResultObject(Op->getRHS(), Loc);
455b5f2cecfSmartinboehme       return;
456b5f2cecfSmartinboehme     }
457b5f2cecfSmartinboehme 
458b5f2cecfSmartinboehme     if (auto *Cond = dyn_cast<AbstractConditionalOperator>(E)) {
459b5f2cecfSmartinboehme       PropagateResultObject(Cond->getTrueExpr(), Loc);
460b5f2cecfSmartinboehme       PropagateResultObject(Cond->getFalseExpr(), Loc);
461b5f2cecfSmartinboehme       return;
462b5f2cecfSmartinboehme     }
463b5f2cecfSmartinboehme 
464b5f2cecfSmartinboehme     if (auto *SE = dyn_cast<StmtExpr>(E)) {
465b5f2cecfSmartinboehme       PropagateResultObject(cast<Expr>(SE->getSubStmt()->body_back()), Loc);
466b5f2cecfSmartinboehme       return;
467b5f2cecfSmartinboehme     }
468b5f2cecfSmartinboehme 
4693fed312dSSamira Bazuzi     if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(E)) {
4703fed312dSSamira Bazuzi       PropagateResultObject(DIE->getExpr(), Loc);
4713fed312dSSamira Bazuzi       return;
4723fed312dSSamira Bazuzi     }
4733fed312dSSamira Bazuzi 
474b5f2cecfSmartinboehme     // All other expression nodes that propagate a record prvalue should have
475b5f2cecfSmartinboehme     // exactly one child.
47671f1932bSmartinboehme     SmallVector<Stmt *, 1> Children(E->child_begin(), E->child_end());
47771f1932bSmartinboehme     LLVM_DEBUG({
47871f1932bSmartinboehme       if (Children.size() != 1)
47971f1932bSmartinboehme         E->dump();
48071f1932bSmartinboehme     });
48171f1932bSmartinboehme     assert(Children.size() == 1);
48271f1932bSmartinboehme     for (Stmt *S : Children)
48371f1932bSmartinboehme       PropagateResultObject(cast<Expr>(S), Loc);
48471f1932bSmartinboehme   }
48571f1932bSmartinboehme 
48671f1932bSmartinboehme private:
48771f1932bSmartinboehme   llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap;
48871f1932bSmartinboehme   RecordStorageLocation *LocForRecordReturnVal;
48971f1932bSmartinboehme   DataflowAnalysisContext &DACtx;
49071f1932bSmartinboehme };
49171f1932bSmartinboehme 
49271f1932bSmartinboehme } // namespace
49371f1932bSmartinboehme 
49480d9ae9cSSamira Bazuzi void Environment::initialize() {
49580d9ae9cSSamira Bazuzi   if (InitialTargetStmt == nullptr)
49680d9ae9cSSamira Bazuzi     return;
49771f2ec2dSmartinboehme 
49880d9ae9cSSamira Bazuzi   if (InitialTargetFunc == nullptr) {
49980d9ae9cSSamira Bazuzi     initFieldsGlobalsAndFuncs(getReferencedDecls(*InitialTargetStmt));
50080d9ae9cSSamira Bazuzi     ResultObjectMap =
50180d9ae9cSSamira Bazuzi         std::make_shared<PrValueToResultObject>(buildResultObjectMap(
50280d9ae9cSSamira Bazuzi             DACtx, InitialTargetStmt, getThisPointeeStorageLocation(),
50380d9ae9cSSamira Bazuzi             /*LocForRecordReturnValue=*/nullptr));
50480d9ae9cSSamira Bazuzi     return;
50571f2ec2dSmartinboehme   }
50671f2ec2dSmartinboehme 
50780d9ae9cSSamira Bazuzi   initFieldsGlobalsAndFuncs(getReferencedDecls(*InitialTargetFunc));
50871f2ec2dSmartinboehme 
50980d9ae9cSSamira Bazuzi   for (const auto *ParamDecl : InitialTargetFunc->parameters()) {
51071f2ec2dSmartinboehme     assert(ParamDecl != nullptr);
51171f2ec2dSmartinboehme     setStorageLocation(*ParamDecl, createObject(*ParamDecl, nullptr));
51271f2ec2dSmartinboehme   }
51371f1932bSmartinboehme 
51480d9ae9cSSamira Bazuzi   if (InitialTargetFunc->getReturnType()->isRecordType())
51571f1932bSmartinboehme     LocForRecordReturnVal = &cast<RecordStorageLocation>(
51680d9ae9cSSamira Bazuzi         createStorageLocation(InitialTargetFunc->getReturnType()));
51771f2ec2dSmartinboehme 
51880d9ae9cSSamira Bazuzi   if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(InitialTargetFunc)) {
51971f2ec2dSmartinboehme     auto *Parent = MethodDecl->getParent();
52071f2ec2dSmartinboehme     assert(Parent != nullptr);
52171f2ec2dSmartinboehme 
52271f2ec2dSmartinboehme     if (Parent->isLambda()) {
5234c4ea249Ssmanna12       for (const auto &Capture : Parent->captures()) {
52471f2ec2dSmartinboehme         if (Capture.capturesVariable()) {
52571f2ec2dSmartinboehme           const auto *VarDecl = Capture.getCapturedVar();
52671f2ec2dSmartinboehme           assert(VarDecl != nullptr);
52771f2ec2dSmartinboehme           setStorageLocation(*VarDecl, createObject(*VarDecl, nullptr));
52871f2ec2dSmartinboehme         } else if (Capture.capturesThis()) {
52983c2bfdaSSamira Bazuzi           if (auto *Ancestor = InitialTargetFunc->getNonClosureAncestor()) {
53083c2bfdaSSamira Bazuzi             const auto *SurroundingMethodDecl = cast<CXXMethodDecl>(Ancestor);
53171f2ec2dSmartinboehme             QualType ThisPointeeType =
53271f2ec2dSmartinboehme                 SurroundingMethodDecl->getFunctionObjectParameterType();
53371f2ec2dSmartinboehme             setThisPointeeStorageLocation(
5347a6c2628Smartinboehme                 cast<RecordStorageLocation>(createObject(ThisPointeeType)));
53583c2bfdaSSamira Bazuzi           } else if (auto *FieldBeingInitialized =
53683c2bfdaSSamira Bazuzi                          dyn_cast<FieldDecl>(Parent->getLambdaContextDecl())) {
53783c2bfdaSSamira Bazuzi             // This is in a field initializer, rather than a method.
53883c2bfdaSSamira Bazuzi             setThisPointeeStorageLocation(
53983c2bfdaSSamira Bazuzi                 cast<RecordStorageLocation>(createObject(QualType(
54083c2bfdaSSamira Bazuzi                     FieldBeingInitialized->getParent()->getTypeForDecl(), 0))));
54183c2bfdaSSamira Bazuzi           } else {
54283c2bfdaSSamira Bazuzi             assert(false && "Unexpected this-capturing lambda context.");
54383c2bfdaSSamira Bazuzi           }
54471f2ec2dSmartinboehme         }
54571f2ec2dSmartinboehme       }
54671f2ec2dSmartinboehme     } else if (MethodDecl->isImplicitObjectMemberFunction()) {
54771f2ec2dSmartinboehme       QualType ThisPointeeType = MethodDecl->getFunctionObjectParameterType();
5482d539db2Smartinboehme       auto &ThisLoc =
5492d539db2Smartinboehme           cast<RecordStorageLocation>(createStorageLocation(ThisPointeeType));
5502d539db2Smartinboehme       setThisPointeeStorageLocation(ThisLoc);
5512d539db2Smartinboehme       // Initialize fields of `*this` with values, but only if we're not
5522d539db2Smartinboehme       // analyzing a constructor; after all, it's the constructor's job to do
5532d539db2Smartinboehme       // this (and we want to be able to test that).
5542d539db2Smartinboehme       if (!isa<CXXConstructorDecl>(MethodDecl))
5552d539db2Smartinboehme         initializeFieldsWithValues(ThisLoc);
55671f2ec2dSmartinboehme     }
55771f2ec2dSmartinboehme   }
55871f1932bSmartinboehme 
55971f1932bSmartinboehme   // We do this below the handling of `CXXMethodDecl` above so that we can
56071f1932bSmartinboehme   // be sure that the storage location for `this` has been set.
56180d9ae9cSSamira Bazuzi   ResultObjectMap =
56280d9ae9cSSamira Bazuzi       std::make_shared<PrValueToResultObject>(buildResultObjectMap(
56380d9ae9cSSamira Bazuzi           DACtx, InitialTargetFunc, getThisPointeeStorageLocation(),
56471f1932bSmartinboehme           LocForRecordReturnVal));
56571f2ec2dSmartinboehme }
56671f2ec2dSmartinboehme 
56780d9ae9cSSamira Bazuzi // FIXME: Add support for resetting globals after function calls to enable the
56880d9ae9cSSamira Bazuzi // implementation of sound analyses.
569ce0ab9d1SMartin Braenne 
57080d9ae9cSSamira Bazuzi void Environment::initFieldsGlobalsAndFuncs(const ReferencedDecls &Referenced) {
571ce0ab9d1SMartin Braenne   // These have to be added before the lines that follow to ensure that
572ce0ab9d1SMartin Braenne   // `create*` work correctly for structs.
5739ec8c961SSamira Bazuzi   DACtx->addModeledFields(Referenced.Fields);
574ce0ab9d1SMartin Braenne 
5759ec8c961SSamira Bazuzi   for (const VarDecl *D : Referenced.Globals) {
5769940fac7SMartin Braenne     if (getStorageLocation(*D) != nullptr)
57701ccf7b3SYitzhak Mandelbaum       continue;
5786d768548SMartin Braenne 
57971f1932bSmartinboehme     // We don't run transfer functions on the initializers of global variables,
58071f1932bSmartinboehme     // so they won't be associated with a value or storage location. We
58180d9ae9cSSamira Bazuzi     // therefore intentionally don't pass an initializer to `createObject()`; in
58280d9ae9cSSamira Bazuzi     // particular, this ensures that `createObject()` will initialize the fields
58380d9ae9cSSamira Bazuzi     // of record-type variables with values.
58471f1932bSmartinboehme     setStorageLocation(*D, createObject(*D, nullptr));
58503dff121SStanislav Gatev   }
586d9e71733SMartin Braenne 
5879ec8c961SSamira Bazuzi   for (const FunctionDecl *FD : Referenced.Functions) {
5889940fac7SMartin Braenne     if (getStorageLocation(*FD) != nullptr)
589d9e71733SMartin Braenne       continue;
59071f1932bSmartinboehme     auto &Loc = createStorageLocation(*FD);
591d9e71733SMartin Braenne     setStorageLocation(*FD, Loc);
592d9e71733SMartin Braenne   }
59303dff121SStanislav Gatev }
59403dff121SStanislav Gatev 
595c2bb6807SSam McCall Environment Environment::fork() const {
596c2bb6807SSam McCall   Environment Copy(*this);
597fc9821a8SSam McCall   Copy.FlowConditionToken = DACtx->forkFlowCondition(FlowConditionToken);
598c2bb6807SSam McCall   return Copy;
599955a05a2SStanislav Gatev }
600955a05a2SStanislav Gatev 
6012efc8f8dSSam Estep bool Environment::canDescend(unsigned MaxDepth,
60280d9ae9cSSamira Bazuzi                              const FunctionDecl *Callee) const {
60380d9ae9cSSamira Bazuzi   return CallStack.size() < MaxDepth && !llvm::is_contained(CallStack, Callee);
6042efc8f8dSSam Estep }
6052efc8f8dSSam Estep 
606300fbf56SSam Estep Environment Environment::pushCall(const CallExpr *Call) const {
607300fbf56SSam Estep   Environment Env(*this);
608eb91fd5cSSam Estep 
609eb91fd5cSSam Estep   if (const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(Call)) {
610eb91fd5cSSam Estep     if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
6110b12efc7SYitzhak Mandelbaum       if (!isa<CXXThisExpr>(Arg))
612f76f6674SMartin Braenne         Env.ThisPointeeLoc =
6139ecdbe38SMartin Braenne             cast<RecordStorageLocation>(getStorageLocation(*Arg));
6140b12efc7SYitzhak Mandelbaum       // Otherwise (when the argument is `this`), retain the current
6150b12efc7SYitzhak Mandelbaum       // environment's `ThisPointeeLoc`.
616eb91fd5cSSam Estep     }
617eb91fd5cSSam Estep   }
6182cb51449SWei Yi Tee 
61971f1932bSmartinboehme   if (Call->getType()->isRecordType() && Call->isPRValue())
62071f1932bSmartinboehme     Env.LocForRecordReturnVal = &Env.getResultObjectLocation(*Call);
62171f1932bSmartinboehme 
622eb91fd5cSSam Estep   Env.pushCallInternal(Call->getDirectCallee(),
623a3c248dbSserge-sans-paille                        llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));
624eb91fd5cSSam Estep 
625eb91fd5cSSam Estep   return Env;
626eb91fd5cSSam Estep }
627eb91fd5cSSam Estep 
628eb91fd5cSSam Estep Environment Environment::pushCall(const CXXConstructExpr *Call) const {
629eb91fd5cSSam Estep   Environment Env(*this);
630eb91fd5cSSam Estep 
63144f98d01SMartin Braenne   Env.ThisPointeeLoc = &Env.getResultObjectLocation(*Call);
63271f1932bSmartinboehme   Env.LocForRecordReturnVal = &Env.getResultObjectLocation(*Call);
633eb91fd5cSSam Estep 
634eb91fd5cSSam Estep   Env.pushCallInternal(Call->getConstructor(),
635a3c248dbSserge-sans-paille                        llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));
636eb91fd5cSSam Estep 
637eb91fd5cSSam Estep   return Env;
638eb91fd5cSSam Estep }
639eb91fd5cSSam Estep 
640eb91fd5cSSam Estep void Environment::pushCallInternal(const FunctionDecl *FuncDecl,
641eb91fd5cSSam Estep                                    ArrayRef<const Expr *> Args) {
64264413584SMartin Braenne   // Canonicalize to the definition of the function. This ensures that we're
64364413584SMartin Braenne   // putting arguments into the same `ParamVarDecl`s` that the callee will later
64464413584SMartin Braenne   // be retrieving them from.
64564413584SMartin Braenne   assert(FuncDecl->getDefinition() != nullptr);
64664413584SMartin Braenne   FuncDecl = FuncDecl->getDefinition();
64764413584SMartin Braenne 
6482efc8f8dSSam Estep   CallStack.push_back(FuncDecl);
6492cb51449SWei Yi Tee 
65080d9ae9cSSamira Bazuzi   initFieldsGlobalsAndFuncs(getReferencedDecls(*FuncDecl));
6513ce03c42SYitzhak Mandelbaum 
65201ccf7b3SYitzhak Mandelbaum   const auto *ParamIt = FuncDecl->param_begin();
653300fbf56SSam Estep 
654300fbf56SSam Estep   // FIXME: Parameters don't always map to arguments 1:1; examples include
655300fbf56SSam Estep   // overloaded operators implemented as member functions, and parameter packs.
656eb91fd5cSSam Estep   for (unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) {
6571f8ae9d7SWeverything     assert(ParamIt != FuncDecl->param_end());
658a6ddc684SSam Estep     const VarDecl *Param = *ParamIt;
6596d768548SMartin Braenne     setStorageLocation(*Param, createObject(*Param, Args[ArgIndex]));
660300fbf56SSam Estep   }
66171f1932bSmartinboehme 
66271f1932bSmartinboehme   ResultObjectMap = std::make_shared<PrValueToResultObject>(
66371f1932bSmartinboehme       buildResultObjectMap(DACtx, FuncDecl, getThisPointeeStorageLocation(),
66471f1932bSmartinboehme                            LocForRecordReturnVal));
665bfbe1378SMartin Braenne }
666300fbf56SSam Estep 
66764413584SMartin Braenne void Environment::popCall(const CallExpr *Call, const Environment &CalleeEnv) {
668330d5bcbSMartin Braenne   // We ignore some entries of `CalleeEnv`:
669330d5bcbSMartin Braenne   // - `DACtx` because is already the same in both
670330d5bcbSMartin Braenne   // - We don't want the callee's `DeclCtx`, `ReturnVal`, `ReturnLoc` or
671330d5bcbSMartin Braenne   //   `ThisPointeeLoc` because they don't apply to us.
672330d5bcbSMartin Braenne   // - `DeclToLoc`, `ExprToLoc`, and `ExprToVal` capture information from the
673330d5bcbSMartin Braenne   //   callee's local scope, so when popping that scope, we do not propagate
674330d5bcbSMartin Braenne   //   the maps.
675a6ddc684SSam Estep   this->LocToVal = std::move(CalleeEnv.LocToVal);
676a6ddc684SSam Estep   this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
67764413584SMartin Braenne 
67864413584SMartin Braenne   if (Call->isGLValue()) {
67964413584SMartin Braenne     if (CalleeEnv.ReturnLoc != nullptr)
680b244b6aeSMartin Braenne       setStorageLocation(*Call, *CalleeEnv.ReturnLoc);
68164413584SMartin Braenne   } else if (!Call->getType()->isVoidType()) {
68264413584SMartin Braenne     if (CalleeEnv.ReturnVal != nullptr)
683b244b6aeSMartin Braenne       setValue(*Call, *CalleeEnv.ReturnVal);
68464413584SMartin Braenne   }
68564413584SMartin Braenne }
68664413584SMartin Braenne 
68764413584SMartin Braenne void Environment::popCall(const CXXConstructExpr *Call,
68864413584SMartin Braenne                           const Environment &CalleeEnv) {
68964413584SMartin Braenne   // See also comment in `popCall(const CallExpr *, const Environment &)` above.
69064413584SMartin Braenne   this->LocToVal = std::move(CalleeEnv.LocToVal);
69164413584SMartin Braenne   this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
692a6ddc684SSam Estep }
693a6ddc684SSam Estep 
6946b8800dfSStanislav Gatev bool Environment::equivalentTo(const Environment &Other,
6956b8800dfSStanislav Gatev                                Environment::ValueModel &Model) const {
696af7bc39bSStanislav Gatev   assert(DACtx == Other.DACtx);
6976b8800dfSStanislav Gatev 
69864413584SMartin Braenne   if (ReturnVal != Other.ReturnVal)
69964413584SMartin Braenne     return false;
70064413584SMartin Braenne 
7010eaecbbcSSam Estep   if (ReturnLoc != Other.ReturnLoc)
7020eaecbbcSSam Estep     return false;
7030eaecbbcSSam Estep 
70471f1932bSmartinboehme   if (LocForRecordReturnVal != Other.LocForRecordReturnVal)
70571f1932bSmartinboehme     return false;
70671f1932bSmartinboehme 
7078611a77eSSam Estep   if (ThisPointeeLoc != Other.ThisPointeeLoc)
7088611a77eSSam Estep     return false;
7098611a77eSSam Estep 
7106b8800dfSStanislav Gatev   if (DeclToLoc != Other.DeclToLoc)
7116b8800dfSStanislav Gatev     return false;
7126b8800dfSStanislav Gatev 
7136b8800dfSStanislav Gatev   if (ExprToLoc != Other.ExprToLoc)
7146b8800dfSStanislav Gatev     return false;
7156b8800dfSStanislav Gatev 
716330d5bcbSMartin Braenne   if (!compareKeyToValueMaps(ExprToVal, Other.ExprToVal, *this, Other, Model))
7176b8800dfSStanislav Gatev     return false;
718330d5bcbSMartin Braenne 
719330d5bcbSMartin Braenne   if (!compareKeyToValueMaps(LocToVal, Other.LocToVal, *this, Other, Model))
720330d5bcbSMartin Braenne     return false;
7216b8800dfSStanislav Gatev 
7226b8800dfSStanislav Gatev   return true;
723af7bc39bSStanislav Gatev }
724af7bc39bSStanislav Gatev 
725bbd259afSYitzhak Mandelbaum LatticeEffect Environment::widen(const Environment &PrevEnv,
72684dd12b2SYitzhak Mandelbaum                                  Environment::ValueModel &Model) {
72784dd12b2SYitzhak Mandelbaum   assert(DACtx == PrevEnv.DACtx);
72864413584SMartin Braenne   assert(ReturnVal == PrevEnv.ReturnVal);
72984dd12b2SYitzhak Mandelbaum   assert(ReturnLoc == PrevEnv.ReturnLoc);
73071f1932bSmartinboehme   assert(LocForRecordReturnVal == PrevEnv.LocForRecordReturnVal);
73184dd12b2SYitzhak Mandelbaum   assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc);
73284dd12b2SYitzhak Mandelbaum   assert(CallStack == PrevEnv.CallStack);
73371f1932bSmartinboehme   assert(ResultObjectMap == PrevEnv.ResultObjectMap);
73480d9ae9cSSamira Bazuzi   assert(InitialTargetFunc == PrevEnv.InitialTargetFunc);
73580d9ae9cSSamira Bazuzi   assert(InitialTargetStmt == PrevEnv.InitialTargetStmt);
73684dd12b2SYitzhak Mandelbaum 
737bbd259afSYitzhak Mandelbaum   auto Effect = LatticeEffect::Unchanged;
73884dd12b2SYitzhak Mandelbaum 
739d2e4aaf6SYitzhak Mandelbaum   // By the API, `PrevEnv` is a previous version of the environment for the same
740d2e4aaf6SYitzhak Mandelbaum   // block, so we have some guarantees about its shape. In particular, it will
741d2e4aaf6SYitzhak Mandelbaum   // be the result of a join or widen operation on previous values for this
742330d5bcbSMartin Braenne   // block. For `DeclToLoc`, `ExprToVal`, and `ExprToLoc`, join guarantees that
743330d5bcbSMartin Braenne   // these maps are subsets of the maps in `PrevEnv`. So, as long as we maintain
744330d5bcbSMartin Braenne   // this property here, we don't need change their current values to widen.
74584dd12b2SYitzhak Mandelbaum   assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size());
746330d5bcbSMartin Braenne   assert(ExprToVal.size() <= PrevEnv.ExprToVal.size());
74784dd12b2SYitzhak Mandelbaum   assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size());
74884dd12b2SYitzhak Mandelbaum 
749330d5bcbSMartin Braenne   ExprToVal = widenKeyToValueMap(ExprToVal, PrevEnv.ExprToVal, *this, PrevEnv,
750330d5bcbSMartin Braenne                                  Model, Effect);
75184dd12b2SYitzhak Mandelbaum 
752330d5bcbSMartin Braenne   LocToVal = widenKeyToValueMap(LocToVal, PrevEnv.LocToVal, *this, PrevEnv,
753330d5bcbSMartin Braenne                                 Model, Effect);
75484dd12b2SYitzhak Mandelbaum   if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() ||
75584dd12b2SYitzhak Mandelbaum       ExprToLoc.size() != PrevEnv.ExprToLoc.size() ||
756330d5bcbSMartin Braenne       ExprToVal.size() != PrevEnv.ExprToVal.size() ||
75744f98d01SMartin Braenne       LocToVal.size() != PrevEnv.LocToVal.size())
758bbd259afSYitzhak Mandelbaum     Effect = LatticeEffect::Changed;
75984dd12b2SYitzhak Mandelbaum 
76084dd12b2SYitzhak Mandelbaum   return Effect;
76184dd12b2SYitzhak Mandelbaum }
76284dd12b2SYitzhak Mandelbaum 
7636f22de67SSam McCall Environment Environment::join(const Environment &EnvA, const Environment &EnvB,
764d5aecf0cSmartinboehme                               Environment::ValueModel &Model,
765d5aecf0cSmartinboehme                               ExprJoinBehavior ExprBehavior) {
7666f22de67SSam McCall   assert(EnvA.DACtx == EnvB.DACtx);
76771f1932bSmartinboehme   assert(EnvA.LocForRecordReturnVal == EnvB.LocForRecordReturnVal);
7686f22de67SSam McCall   assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc);
7696f22de67SSam McCall   assert(EnvA.CallStack == EnvB.CallStack);
77071f1932bSmartinboehme   assert(EnvA.ResultObjectMap == EnvB.ResultObjectMap);
77180d9ae9cSSamira Bazuzi   assert(EnvA.InitialTargetFunc == EnvB.InitialTargetFunc);
77280d9ae9cSSamira Bazuzi   assert(EnvA.InitialTargetStmt == EnvB.InitialTargetStmt);
773af7bc39bSStanislav Gatev 
7746f22de67SSam McCall   Environment JoinedEnv(*EnvA.DACtx);
77537b4782eSYitzhak Mandelbaum 
7766f22de67SSam McCall   JoinedEnv.CallStack = EnvA.CallStack;
77771f1932bSmartinboehme   JoinedEnv.ResultObjectMap = EnvA.ResultObjectMap;
77871f1932bSmartinboehme   JoinedEnv.LocForRecordReturnVal = EnvA.LocForRecordReturnVal;
7796f22de67SSam McCall   JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc;
78080d9ae9cSSamira Bazuzi   JoinedEnv.InitialTargetFunc = EnvA.InitialTargetFunc;
78180d9ae9cSSamira Bazuzi   JoinedEnv.InitialTargetStmt = EnvA.InitialTargetStmt;
7820eaecbbcSSam Estep 
78380d9ae9cSSamira Bazuzi   const FunctionDecl *Func = EnvA.getCurrentFunc();
78480d9ae9cSSamira Bazuzi   if (!Func) {
78564413584SMartin Braenne     JoinedEnv.ReturnVal = nullptr;
78664413584SMartin Braenne   } else {
7879ba6961cSmartinboehme     JoinedEnv.ReturnVal =
7889ba6961cSmartinboehme         joinValues(Func->getReturnType(), EnvA.ReturnVal, EnvA, EnvB.ReturnVal,
7899ba6961cSmartinboehme                    EnvB, JoinedEnv, Model);
79064413584SMartin Braenne   }
79164413584SMartin Braenne 
7926f22de67SSam McCall   if (EnvA.ReturnLoc == EnvB.ReturnLoc)
7936f22de67SSam McCall     JoinedEnv.ReturnLoc = EnvA.ReturnLoc;
79464413584SMartin Braenne   else
79564413584SMartin Braenne     JoinedEnv.ReturnLoc = nullptr;
79664413584SMartin Braenne 
797c4c59192Smartinboehme   JoinedEnv.DeclToLoc = intersectDeclToLoc(EnvA.DeclToLoc, EnvB.DeclToLoc);
798c95cb4deSStanislav Gatev 
79984dd12b2SYitzhak Mandelbaum   // FIXME: update join to detect backedges and simplify the flow condition
80084dd12b2SYitzhak Mandelbaum   // accordingly.
801fc9821a8SSam McCall   JoinedEnv.FlowConditionToken = EnvA.DACtx->joinFlowConditions(
802fc9821a8SSam McCall       EnvA.FlowConditionToken, EnvB.FlowConditionToken);
80337b4782eSYitzhak Mandelbaum 
804c4c59192Smartinboehme   JoinedEnv.LocToVal =
805c4c59192Smartinboehme       joinLocToVal(EnvA.LocToVal, EnvB.LocToVal, EnvA, EnvB, JoinedEnv, Model);
806d3597ec0SStanislav Gatev 
807d5aecf0cSmartinboehme   if (ExprBehavior == KeepExprState) {
808d5aecf0cSmartinboehme     JoinedEnv.ExprToVal = joinExprMaps(EnvA.ExprToVal, EnvB.ExprToVal);
809d5aecf0cSmartinboehme     JoinedEnv.ExprToLoc = joinExprMaps(EnvA.ExprToLoc, EnvB.ExprToLoc);
810d5aecf0cSmartinboehme   }
811af7bc39bSStanislav Gatev 
8121e010c5cSSam McCall   return JoinedEnv;
813af7bc39bSStanislav Gatev }
814af7bc39bSStanislav Gatev 
8159ba6961cSmartinboehme Value *Environment::joinValues(QualType Ty, Value *Val1,
8169ba6961cSmartinboehme                                const Environment &Env1, Value *Val2,
8179ba6961cSmartinboehme                                const Environment &Env2, Environment &JoinedEnv,
8189ba6961cSmartinboehme                                Environment::ValueModel &Model) {
8199ba6961cSmartinboehme   if (Val1 == nullptr || Val2 == nullptr)
8209ba6961cSmartinboehme     // We can't say anything about the joined value -- even if one of the values
8219ba6961cSmartinboehme     // is non-null, we don't want to simply propagate it, because it would be
8229ba6961cSmartinboehme     // too specific: Because the other value is null, that means we have no
8239ba6961cSmartinboehme     // information at all about the value (i.e. the value is unconstrained).
8249ba6961cSmartinboehme     return nullptr;
8259ba6961cSmartinboehme 
8269ba6961cSmartinboehme   if (areEquivalentValues(*Val1, *Val2))
8279ba6961cSmartinboehme     // Arbitrarily return one of the two values.
8289ba6961cSmartinboehme     return Val1;
8299ba6961cSmartinboehme 
8309ba6961cSmartinboehme   return joinDistinctValues(Ty, *Val1, Env1, *Val2, Env2, JoinedEnv, Model);
8319ba6961cSmartinboehme }
8329ba6961cSmartinboehme 
833af7bc39bSStanislav Gatev StorageLocation &Environment::createStorageLocation(QualType Type) {
834817dd5e3SStanislav Gatev   return DACtx->createStorageLocation(Type);
835af7bc39bSStanislav Gatev }
836af7bc39bSStanislav Gatev 
83752d06963SStanislav Gatev StorageLocation &Environment::createStorageLocation(const ValueDecl &D) {
838af7bc39bSStanislav Gatev   // Evaluated declarations are always assigned the same storage locations to
839af7bc39bSStanislav Gatev   // ensure that the environment stabilizes across loop iterations. Storage
840af7bc39bSStanislav Gatev   // locations for evaluated declarations are stored in the analysis context.
84112c7352fSWei Yi Tee   return DACtx->getStableStorageLocation(D);
842af7bc39bSStanislav Gatev }
843af7bc39bSStanislav Gatev 
844e7481f6eSStanislav Gatev StorageLocation &Environment::createStorageLocation(const Expr &E) {
845e7481f6eSStanislav Gatev   // Evaluated expressions are always assigned the same storage locations to
846e7481f6eSStanislav Gatev   // ensure that the environment stabilizes across loop iterations. Storage
847e7481f6eSStanislav Gatev   // locations for evaluated expressions are stored in the analysis context.
84812c7352fSWei Yi Tee   return DACtx->getStableStorageLocation(E);
849e7481f6eSStanislav Gatev }
850e7481f6eSStanislav Gatev 
851af7bc39bSStanislav Gatev void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
8527eaa7b05SKazu Hirata   assert(!DeclToLoc.contains(&D));
85371f1932bSmartinboehme   // The only kinds of declarations that may have a "variable" storage location
85471f1932bSmartinboehme   // are declarations of reference type and `BindingDecl`. For all other
85571f1932bSmartinboehme   // declaration, the storage location should be the stable storage location
85671f1932bSmartinboehme   // returned by `createStorageLocation()`.
85771f1932bSmartinboehme   assert(D.getType()->isReferenceType() || isa<BindingDecl>(D) ||
85871f1932bSmartinboehme          &Loc == &createStorageLocation(D));
859af7bc39bSStanislav Gatev   DeclToLoc[&D] = &Loc;
860af7bc39bSStanislav Gatev }
861af7bc39bSStanislav Gatev 
8629940fac7SMartin Braenne StorageLocation *Environment::getStorageLocation(const ValueDecl &D) const {
863af7bc39bSStanislav Gatev   auto It = DeclToLoc.find(&D);
864bfbe1378SMartin Braenne   if (It == DeclToLoc.end())
865bfbe1378SMartin Braenne     return nullptr;
866bfbe1378SMartin Braenne 
867bfbe1378SMartin Braenne   StorageLocation *Loc = It->second;
868bfbe1378SMartin Braenne 
869bfbe1378SMartin Braenne   return Loc;
870e7481f6eSStanislav Gatev }
871e7481f6eSStanislav Gatev 
87214b039c1Smartinboehme void Environment::removeDecl(const ValueDecl &D) { DeclToLoc.erase(&D); }
873834cb919Smartinboehme 
874b244b6aeSMartin Braenne void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
875080ee850SMartin Braenne   // `DeclRefExpr`s to builtin function types aren't glvalues, for some reason,
876080ee850SMartin Braenne   // but we still want to be able to associate a `StorageLocation` with them,
877080ee850SMartin Braenne   // so allow these as an exception.
878080ee850SMartin Braenne   assert(E.isGLValue() ||
879080ee850SMartin Braenne          E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
880ca103434Smartinboehme   const Expr &CanonE = ignoreCFGOmittedNodes(E);
881ca103434Smartinboehme   assert(!ExprToLoc.contains(&CanonE));
882ca103434Smartinboehme   ExprToLoc[&CanonE] = &Loc;
883af7bc39bSStanislav Gatev }
884af7bc39bSStanislav Gatev 
885b244b6aeSMartin Braenne StorageLocation *Environment::getStorageLocation(const Expr &E) const {
886b244b6aeSMartin Braenne   // See comment in `setStorageLocation()`.
887080ee850SMartin Braenne   assert(E.isGLValue() ||
888080ee850SMartin Braenne          E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
889ca103434Smartinboehme   auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));
890ca103434Smartinboehme   return It == ExprToLoc.end() ? nullptr : &*It->second;
891ca103434Smartinboehme }
892ca103434Smartinboehme 
8939ecdbe38SMartin Braenne RecordStorageLocation &
894ca103434Smartinboehme Environment::getResultObjectLocation(const Expr &RecordPRValue) const {
89544f98d01SMartin Braenne   assert(RecordPRValue.getType()->isRecordType());
89644f98d01SMartin Braenne   assert(RecordPRValue.isPRValue());
89744f98d01SMartin Braenne 
89871f1932bSmartinboehme   assert(ResultObjectMap != nullptr);
89971f1932bSmartinboehme   RecordStorageLocation *Loc = ResultObjectMap->lookup(&RecordPRValue);
90071f1932bSmartinboehme   assert(Loc != nullptr);
90171f1932bSmartinboehme   // In release builds, use the "stable" storage location if the map lookup
90271f1932bSmartinboehme   // failed.
90371f1932bSmartinboehme   if (Loc == nullptr)
904ca103434Smartinboehme     return cast<RecordStorageLocation>(
90544f98d01SMartin Braenne         DACtx->getStableStorageLocation(RecordPRValue));
90671f1932bSmartinboehme   return *Loc;
90744f98d01SMartin Braenne }
90844f98d01SMartin Braenne 
909b611376eSWei Yi Tee PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) {
910b611376eSWei Yi Tee   return DACtx->getOrCreateNullPointerValue(PointeeType);
911b611376eSWei Yi Tee }
912b611376eSWei Yi Tee 
91371f1932bSmartinboehme void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc,
91471f1932bSmartinboehme                                              QualType Type) {
9152d539db2Smartinboehme   llvm::DenseSet<QualType> Visited;
9162d539db2Smartinboehme   int CreatedValuesCount = 0;
91771f1932bSmartinboehme   initializeFieldsWithValues(Loc, Type, Visited, 0, CreatedValuesCount);
9182d539db2Smartinboehme   if (CreatedValuesCount > MaxCompositeValueSize) {
91971f1932bSmartinboehme     llvm::errs() << "Attempting to initialize a huge value of type: " << Type
92071f1932bSmartinboehme                  << '\n';
9212d539db2Smartinboehme   }
9222d539db2Smartinboehme }
9232d539db2Smartinboehme 
9247d941d6dSStanislav Gatev void Environment::setValue(const StorageLocation &Loc, Value &Val) {
925e8fce958Smartinboehme   // Records should not be associated with values.
926e8fce958Smartinboehme   assert(!isa<RecordStorageLocation>(Loc));
9277d941d6dSStanislav Gatev   LocToVal[&Loc] = &Val;
928f2123af1SMartin Braenne }
929f2123af1SMartin Braenne 
930b244b6aeSMartin Braenne void Environment::setValue(const Expr &E, Value &Val) {
93123bfc271Smartinboehme   const Expr &CanonE = ignoreCFGOmittedNodes(E);
93223bfc271Smartinboehme 
93323bfc271Smartinboehme   assert(CanonE.isPRValue());
934e8fce958Smartinboehme   // Records should not be associated with values.
935e8fce958Smartinboehme   assert(!CanonE.getType()->isRecordType());
93623bfc271Smartinboehme   ExprToVal[&CanonE] = &Val;
937080ee850SMartin Braenne }
938080ee850SMartin Braenne 
939af7bc39bSStanislav Gatev Value *Environment::getValue(const StorageLocation &Loc) const {
940e8fce958Smartinboehme   // Records should not be associated with values.
941e8fce958Smartinboehme   assert(!isa<RecordStorageLocation>(Loc));
942583371beSKazu Hirata   return LocToVal.lookup(&Loc);
943af7bc39bSStanislav Gatev }
944af7bc39bSStanislav Gatev 
9450c852dc8SMartin Braenne Value *Environment::getValue(const ValueDecl &D) const {
9469940fac7SMartin Braenne   auto *Loc = getStorageLocation(D);
947e7481f6eSStanislav Gatev   if (Loc == nullptr)
948e7481f6eSStanislav Gatev     return nullptr;
949e7481f6eSStanislav Gatev   return getValue(*Loc);
950e7481f6eSStanislav Gatev }
951e7481f6eSStanislav Gatev 
95217ba278fSMartin Braenne Value *Environment::getValue(const Expr &E) const {
953e8fce958Smartinboehme   // Records should not be associated with values.
954e8fce958Smartinboehme   assert(!E.getType()->isRecordType());
955e8fce958Smartinboehme 
956330d5bcbSMartin Braenne   if (E.isPRValue()) {
957330d5bcbSMartin Braenne     auto It = ExprToVal.find(&ignoreCFGOmittedNodes(E));
958330d5bcbSMartin Braenne     return It == ExprToVal.end() ? nullptr : It->second;
959330d5bcbSMartin Braenne   }
960330d5bcbSMartin Braenne 
96117ba278fSMartin Braenne   auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));
96217ba278fSMartin Braenne   if (It == ExprToLoc.end())
963e7481f6eSStanislav Gatev     return nullptr;
96417ba278fSMartin Braenne   return getValue(*It->second);
965080ee850SMartin Braenne }
966080ee850SMartin Braenne 
967782eced5SStanislav Gatev Value *Environment::createValue(QualType Type) {
968af7bc39bSStanislav Gatev   llvm::DenseSet<QualType> Visited;
969208c25fcSYitzhak Mandelbaum   int CreatedValuesCount = 0;
970208c25fcSYitzhak Mandelbaum   Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0,
971208c25fcSYitzhak Mandelbaum                                                 CreatedValuesCount);
972208c25fcSYitzhak Mandelbaum   if (CreatedValuesCount > MaxCompositeValueSize) {
973cfb81690SNathan James     llvm::errs() << "Attempting to initialize a huge value of type: " << Type
974cfb81690SNathan James                  << '\n';
975208c25fcSYitzhak Mandelbaum   }
976208c25fcSYitzhak Mandelbaum   return Val;
977af7bc39bSStanislav Gatev }
978af7bc39bSStanislav Gatev 
979782eced5SStanislav Gatev Value *Environment::createValueUnlessSelfReferential(
980208c25fcSYitzhak Mandelbaum     QualType Type, llvm::DenseSet<QualType> &Visited, int Depth,
981208c25fcSYitzhak Mandelbaum     int &CreatedValuesCount) {
982af7bc39bSStanislav Gatev   assert(!Type.isNull());
9831b334a2aSMartin Braenne   assert(!Type->isReferenceType());
984e8fce958Smartinboehme   assert(!Type->isRecordType());
985af7bc39bSStanislav Gatev 
986208c25fcSYitzhak Mandelbaum   // Allow unlimited fields at depth 1; only cap at deeper nesting levels.
987208c25fcSYitzhak Mandelbaum   if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) ||
988208c25fcSYitzhak Mandelbaum       Depth > MaxCompositeValueDepth)
989208c25fcSYitzhak Mandelbaum     return nullptr;
990208c25fcSYitzhak Mandelbaum 
9911e571585SStanislav Gatev   if (Type->isBooleanType()) {
9921e571585SStanislav Gatev     CreatedValuesCount++;
9931e571585SStanislav Gatev     return &makeAtomicBoolValue();
9941e571585SStanislav Gatev   }
9951e571585SStanislav Gatev 
996af7bc39bSStanislav Gatev   if (Type->isIntegerType()) {
99784dd12b2SYitzhak Mandelbaum     // FIXME: consider instead `return nullptr`, given that we do nothing useful
99884dd12b2SYitzhak Mandelbaum     // with integers, and so distinguishing them serves no purpose, but could
99984dd12b2SYitzhak Mandelbaum     // prevent convergence.
1000208c25fcSYitzhak Mandelbaum     CreatedValuesCount++;
1001fc9821a8SSam McCall     return &arena().create<IntegerValue>();
1002af7bc39bSStanislav Gatev   }
1003af7bc39bSStanislav Gatev 
10041b334a2aSMartin Braenne   if (Type->isPointerType()) {
1005208c25fcSYitzhak Mandelbaum     CreatedValuesCount++;
10063c8ead26SMartin Braenne     QualType PointeeType = Type->getPointeeType();
100744f98d01SMartin Braenne     StorageLocation &PointeeLoc =
100844f98d01SMartin Braenne         createLocAndMaybeValue(PointeeType, Visited, Depth, CreatedValuesCount);
1009af7bc39bSStanislav Gatev 
1010fc9821a8SSam McCall     return &arena().create<PointerValue>(PointeeLoc);
1011af7bc39bSStanislav Gatev   }
1012af7bc39bSStanislav Gatev 
1013af7bc39bSStanislav Gatev   return nullptr;
1014af7bc39bSStanislav Gatev }
1015af7bc39bSStanislav Gatev 
101644f98d01SMartin Braenne StorageLocation &
101744f98d01SMartin Braenne Environment::createLocAndMaybeValue(QualType Ty,
101844f98d01SMartin Braenne                                     llvm::DenseSet<QualType> &Visited,
101944f98d01SMartin Braenne                                     int Depth, int &CreatedValuesCount) {
102044f98d01SMartin Braenne   if (!Visited.insert(Ty.getCanonicalType()).second)
102144f98d01SMartin Braenne     return createStorageLocation(Ty.getNonReferenceType());
1022e8fce958Smartinboehme   auto EraseVisited = llvm::make_scope_exit(
1023e8fce958Smartinboehme       [&Visited, Ty] { Visited.erase(Ty.getCanonicalType()); });
102444f98d01SMartin Braenne 
102544f98d01SMartin Braenne   Ty = Ty.getNonReferenceType();
102644f98d01SMartin Braenne 
1027e8fce958Smartinboehme   if (Ty->isRecordType()) {
1028e8fce958Smartinboehme     auto &Loc = cast<RecordStorageLocation>(createStorageLocation(Ty));
1029e8fce958Smartinboehme     initializeFieldsWithValues(Loc, Ty, Visited, Depth, CreatedValuesCount);
1030e8fce958Smartinboehme     return Loc;
1031e8fce958Smartinboehme   }
103244f98d01SMartin Braenne 
103344f98d01SMartin Braenne   StorageLocation &Loc = createStorageLocation(Ty);
1034e8fce958Smartinboehme 
1035e8fce958Smartinboehme   if (Value *Val = createValueUnlessSelfReferential(Ty, Visited, Depth,
1036e8fce958Smartinboehme                                                     CreatedValuesCount))
103744f98d01SMartin Braenne     setValue(Loc, *Val);
1038e8fce958Smartinboehme 
103944f98d01SMartin Braenne   return Loc;
104044f98d01SMartin Braenne }
104144f98d01SMartin Braenne 
1042270f2c55Smartinboehme void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc,
104371f1932bSmartinboehme                                              QualType Type,
1044270f2c55Smartinboehme                                              llvm::DenseSet<QualType> &Visited,
1045270f2c55Smartinboehme                                              int Depth,
1046270f2c55Smartinboehme                                              int &CreatedValuesCount) {
1047270f2c55Smartinboehme   auto initField = [&](QualType FieldType, StorageLocation &FieldLoc) {
1048270f2c55Smartinboehme     if (FieldType->isRecordType()) {
1049270f2c55Smartinboehme       auto &FieldRecordLoc = cast<RecordStorageLocation>(FieldLoc);
105071f1932bSmartinboehme       initializeFieldsWithValues(FieldRecordLoc, FieldRecordLoc.getType(),
105171f1932bSmartinboehme                                  Visited, Depth + 1, CreatedValuesCount);
1052270f2c55Smartinboehme     } else {
1053e8fce958Smartinboehme       if (getValue(FieldLoc) != nullptr)
1054e8fce958Smartinboehme         return;
1055270f2c55Smartinboehme       if (!Visited.insert(FieldType.getCanonicalType()).second)
1056270f2c55Smartinboehme         return;
1057270f2c55Smartinboehme       if (Value *Val = createValueUnlessSelfReferential(
1058270f2c55Smartinboehme               FieldType, Visited, Depth + 1, CreatedValuesCount))
1059270f2c55Smartinboehme         setValue(FieldLoc, *Val);
1060270f2c55Smartinboehme       Visited.erase(FieldType.getCanonicalType());
1061270f2c55Smartinboehme     }
1062270f2c55Smartinboehme   };
1063270f2c55Smartinboehme 
106471f1932bSmartinboehme   for (const FieldDecl *Field : DACtx->getModeledFields(Type)) {
1065270f2c55Smartinboehme     assert(Field != nullptr);
1066270f2c55Smartinboehme     QualType FieldType = Field->getType();
1067270f2c55Smartinboehme 
1068270f2c55Smartinboehme     if (FieldType->isReferenceType()) {
1069270f2c55Smartinboehme       Loc.setChild(*Field,
1070270f2c55Smartinboehme                    &createLocAndMaybeValue(FieldType, Visited, Depth + 1,
1071270f2c55Smartinboehme                                            CreatedValuesCount));
1072270f2c55Smartinboehme     } else {
107371f1932bSmartinboehme       StorageLocation *FieldLoc = Loc.getChild(*Field);
1074270f2c55Smartinboehme       assert(FieldLoc != nullptr);
1075270f2c55Smartinboehme       initField(FieldType, *FieldLoc);
1076270f2c55Smartinboehme     }
1077270f2c55Smartinboehme   }
107871f1932bSmartinboehme   for (const auto &[FieldName, FieldType] : DACtx->getSyntheticFields(Type)) {
1079270f2c55Smartinboehme     // Synthetic fields cannot have reference type, so we don't need to deal
1080270f2c55Smartinboehme     // with this case.
1081270f2c55Smartinboehme     assert(!FieldType->isReferenceType());
1082270f2c55Smartinboehme     initField(FieldType, Loc.getSyntheticField(FieldName));
1083270f2c55Smartinboehme   }
1084270f2c55Smartinboehme }
1085270f2c55Smartinboehme 
108652d06963SStanislav Gatev StorageLocation &Environment::createObjectInternal(const ValueDecl *D,
10876d768548SMartin Braenne                                                    QualType Ty,
10886d768548SMartin Braenne                                                    const Expr *InitExpr) {
10896d768548SMartin Braenne   if (Ty->isReferenceType()) {
10906d768548SMartin Braenne     // Although variables of reference type always need to be initialized, it
10916d768548SMartin Braenne     // can happen that we can't see the initializer, so `InitExpr` may still
10926d768548SMartin Braenne     // be null.
10936d768548SMartin Braenne     if (InitExpr) {
1094b244b6aeSMartin Braenne       if (auto *InitExprLoc = getStorageLocation(*InitExpr))
10956d768548SMartin Braenne         return *InitExprLoc;
10966d768548SMartin Braenne     }
10976d768548SMartin Braenne 
10986d768548SMartin Braenne     // Even though we have an initializer, we might not get an
10996d768548SMartin Braenne     // InitExprLoc, for example if the InitExpr is a CallExpr for which we
11006d768548SMartin Braenne     // don't have a function body. In this case, we just invent a storage
11016d768548SMartin Braenne     // location and value -- it's the best we can do.
11026d768548SMartin Braenne     return createObjectInternal(D, Ty.getNonReferenceType(), nullptr);
11036d768548SMartin Braenne   }
11046d768548SMartin Braenne 
110571f1932bSmartinboehme   StorageLocation &Loc =
110671f1932bSmartinboehme       D ? createStorageLocation(*D) : createStorageLocation(Ty);
110771f1932bSmartinboehme 
110871f1932bSmartinboehme   if (Ty->isRecordType()) {
110971f1932bSmartinboehme     auto &RecordLoc = cast<RecordStorageLocation>(Loc);
111071f1932bSmartinboehme     if (!InitExpr)
111171f1932bSmartinboehme       initializeFieldsWithValues(RecordLoc);
111271f1932bSmartinboehme   } else {
11136d768548SMartin Braenne     Value *Val = nullptr;
111471f1932bSmartinboehme     if (InitExpr)
11156d768548SMartin Braenne       // In the (few) cases where an expression is intentionally
11166d768548SMartin Braenne       // "uninterpreted", `InitExpr` is not associated with a value.  There are
11176d768548SMartin Braenne       // two ways to handle this situation: propagate the status, so that
11186d768548SMartin Braenne       // uninterpreted initializers result in uninterpreted variables, or
11196d768548SMartin Braenne       // provide a default value. We choose the latter so that later refinements
11206d768548SMartin Braenne       // of the variable can be used for reasoning about the surrounding code.
11216d768548SMartin Braenne       // For this reason, we let this case be handled by the `createValue()`
11226d768548SMartin Braenne       // call below.
11236d768548SMartin Braenne       //
11246d768548SMartin Braenne       // FIXME. If and when we interpret all language cases, change this to
11256d768548SMartin Braenne       // assert that `InitExpr` is interpreted, rather than supplying a
11266d768548SMartin Braenne       // default value (assuming we don't update the environment API to return
11276d768548SMartin Braenne       // references).
1128e95134b9SMartin Braenne       Val = getValue(*InitExpr);
11296d768548SMartin Braenne     if (!Val)
11306d768548SMartin Braenne       Val = createValue(Ty);
11316d768548SMartin Braenne     if (Val)
11326d768548SMartin Braenne       setValue(Loc, *Val);
113371f1932bSmartinboehme   }
11346d768548SMartin Braenne 
11356d768548SMartin Braenne   return Loc;
11366d768548SMartin Braenne }
11376d768548SMartin Braenne 
1138d1f59544Smartinboehme void Environment::assume(const Formula &F) {
1139d1f59544Smartinboehme   DACtx->addFlowConditionConstraint(FlowConditionToken, F);
1140fc9821a8SSam McCall }
1141ae60884dSStanislav Gatev 
1142d1f59544Smartinboehme bool Environment::proves(const Formula &F) const {
1143d1f59544Smartinboehme   return DACtx->flowConditionImplies(FlowConditionToken, F);
1144d1f59544Smartinboehme }
1145d1f59544Smartinboehme 
1146d1f59544Smartinboehme bool Environment::allows(const Formula &F) const {
1147d1f59544Smartinboehme   return DACtx->flowConditionAllows(FlowConditionToken, F);
1148fc9821a8SSam McCall }
1149ae60884dSStanislav Gatev 
1150c441f65fSYitzhak Mandelbaum void Environment::dump(raw_ostream &OS) const {
1151c83ec847Smartinboehme   llvm::DenseMap<const StorageLocation *, std::string> LocToName;
115271f1932bSmartinboehme   if (LocForRecordReturnVal != nullptr)
115371f1932bSmartinboehme     LocToName[LocForRecordReturnVal] = "(returned record)";
1154c83ec847Smartinboehme   if (ThisPointeeLoc != nullptr)
1155c83ec847Smartinboehme     LocToName[ThisPointeeLoc] = "this";
1156c441f65fSYitzhak Mandelbaum 
1157c83ec847Smartinboehme   OS << "DeclToLoc:\n";
1158c83ec847Smartinboehme   for (auto [D, L] : DeclToLoc) {
1159c83ec847Smartinboehme     auto Iter = LocToName.insert({L, D->getNameAsString()}).first;
1160c83ec847Smartinboehme     OS << "  [" << Iter->second << ", " << L << "]\n";
1161c83ec847Smartinboehme   }
1162c441f65fSYitzhak Mandelbaum   OS << "ExprToLoc:\n";
1163c441f65fSYitzhak Mandelbaum   for (auto [E, L] : ExprToLoc)
1164c441f65fSYitzhak Mandelbaum     OS << "  [" << E << ", " << L << "]\n";
1165c441f65fSYitzhak Mandelbaum 
1166330d5bcbSMartin Braenne   OS << "ExprToVal:\n";
1167330d5bcbSMartin Braenne   for (auto [E, V] : ExprToVal)
1168266c12a1SMartin Braenne     OS << "  [" << E << ", " << V << ": " << *V << "]\n";
1169330d5bcbSMartin Braenne 
1170c441f65fSYitzhak Mandelbaum   OS << "LocToVal:\n";
1171c441f65fSYitzhak Mandelbaum   for (auto [L, V] : LocToVal) {
1172c83ec847Smartinboehme     OS << "  [" << L;
1173c83ec847Smartinboehme     if (auto Iter = LocToName.find(L); Iter != LocToName.end())
1174c83ec847Smartinboehme       OS << " (" << Iter->second << ")";
1175c83ec847Smartinboehme     OS << ", " << V << ": " << *V << "]\n";
1176c83ec847Smartinboehme   }
1177c83ec847Smartinboehme 
1178c83ec847Smartinboehme   if (const FunctionDecl *Func = getCurrentFunc()) {
1179c83ec847Smartinboehme     if (Func->getReturnType()->isReferenceType()) {
1180c83ec847Smartinboehme       OS << "ReturnLoc: " << ReturnLoc;
1181c83ec847Smartinboehme       if (auto Iter = LocToName.find(ReturnLoc); Iter != LocToName.end())
1182c83ec847Smartinboehme         OS << " (" << Iter->second << ")";
1183c83ec847Smartinboehme       OS << "\n";
118471f1932bSmartinboehme     } else if (Func->getReturnType()->isRecordType() ||
118571f1932bSmartinboehme                isa<CXXConstructorDecl>(Func)) {
118671f1932bSmartinboehme       OS << "LocForRecordReturnVal: " << LocForRecordReturnVal << "\n";
1187c83ec847Smartinboehme     } else if (!Func->getReturnType()->isVoidType()) {
1188c83ec847Smartinboehme       if (ReturnVal == nullptr)
1189c83ec847Smartinboehme         OS << "ReturnVal: nullptr\n";
1190c83ec847Smartinboehme       else
1191c83ec847Smartinboehme         OS << "ReturnVal: " << *ReturnVal << "\n";
1192c83ec847Smartinboehme     }
1193c83ec847Smartinboehme 
1194c83ec847Smartinboehme     if (isa<CXXMethodDecl>(Func)) {
1195c83ec847Smartinboehme       OS << "ThisPointeeLoc: " << ThisPointeeLoc << "\n";
1196c83ec847Smartinboehme     }
1197c441f65fSYitzhak Mandelbaum   }
1198c441f65fSYitzhak Mandelbaum 
11997c636728Smartinboehme   OS << "\n";
1200fc9821a8SSam McCall   DACtx->dumpFlowCondition(FlowConditionToken, OS);
1201b5414b56SDmitri Gribenko }
1202b5414b56SDmitri Gribenko 
120314122106Smartinboehme void Environment::dump() const { dump(llvm::dbgs()); }
1204c441f65fSYitzhak Mandelbaum 
120571f1932bSmartinboehme Environment::PrValueToResultObject Environment::buildResultObjectMap(
120671f1932bSmartinboehme     DataflowAnalysisContext *DACtx, const FunctionDecl *FuncDecl,
120771f1932bSmartinboehme     RecordStorageLocation *ThisPointeeLoc,
120871f1932bSmartinboehme     RecordStorageLocation *LocForRecordReturnVal) {
120971f1932bSmartinboehme   assert(FuncDecl->doesThisDeclarationHaveABody());
121071f1932bSmartinboehme 
121180d9ae9cSSamira Bazuzi   PrValueToResultObject Map = buildResultObjectMap(
121280d9ae9cSSamira Bazuzi       DACtx, FuncDecl->getBody(), ThisPointeeLoc, LocForRecordReturnVal);
121371f1932bSmartinboehme 
121471f1932bSmartinboehme   ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
121571f1932bSmartinboehme   if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(FuncDecl))
1216dde802b1SSirraide     Visitor.traverseConstructorInits(Ctor, ThisPointeeLoc);
121771f1932bSmartinboehme 
121871f1932bSmartinboehme   return Map;
121971f1932bSmartinboehme }
122071f1932bSmartinboehme 
122180d9ae9cSSamira Bazuzi Environment::PrValueToResultObject Environment::buildResultObjectMap(
122280d9ae9cSSamira Bazuzi     DataflowAnalysisContext *DACtx, Stmt *S,
122380d9ae9cSSamira Bazuzi     RecordStorageLocation *ThisPointeeLoc,
122480d9ae9cSSamira Bazuzi     RecordStorageLocation *LocForRecordReturnVal) {
122580d9ae9cSSamira Bazuzi   PrValueToResultObject Map;
122680d9ae9cSSamira Bazuzi   ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
122780d9ae9cSSamira Bazuzi   Visitor.TraverseStmt(S);
122880d9ae9cSSamira Bazuzi   return Map;
122980d9ae9cSSamira Bazuzi }
123080d9ae9cSSamira Bazuzi 
12319ecdbe38SMartin Braenne RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
123248bc7150SMartin Braenne                                                  const Environment &Env) {
123348bc7150SMartin Braenne   Expr *ImplicitObject = MCE.getImplicitObjectArgument();
123448bc7150SMartin Braenne   if (ImplicitObject == nullptr)
123548bc7150SMartin Braenne     return nullptr;
123648bc7150SMartin Braenne   if (ImplicitObject->getType()->isPointerType()) {
12372ee396b0Smartinboehme     if (auto *Val = Env.get<PointerValue>(*ImplicitObject))
12389ecdbe38SMartin Braenne       return &cast<RecordStorageLocation>(Val->getPointeeLoc());
123948bc7150SMartin Braenne     return nullptr;
124048bc7150SMartin Braenne   }
12419ecdbe38SMartin Braenne   return cast_or_null<RecordStorageLocation>(
1242b244b6aeSMartin Braenne       Env.getStorageLocation(*ImplicitObject));
124348bc7150SMartin Braenne }
124448bc7150SMartin Braenne 
12459ecdbe38SMartin Braenne RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
124648bc7150SMartin Braenne                                              const Environment &Env) {
124748bc7150SMartin Braenne   Expr *Base = ME.getBase();
124848bc7150SMartin Braenne   if (Base == nullptr)
124948bc7150SMartin Braenne     return nullptr;
125048bc7150SMartin Braenne   if (ME.isArrow()) {
12512ee396b0Smartinboehme     if (auto *Val = Env.get<PointerValue>(*Base))
12529ecdbe38SMartin Braenne       return &cast<RecordStorageLocation>(Val->getPointeeLoc());
125348bc7150SMartin Braenne     return nullptr;
125448bc7150SMartin Braenne   }
12552ee396b0Smartinboehme   return Env.get<RecordStorageLocation>(*Base);
125648bc7150SMartin Braenne }
125748bc7150SMartin Braenne 
1258af7bc39bSStanislav Gatev } // namespace dataflow
1259af7bc39bSStanislav Gatev } // namespace clang
1260