xref: /freebsd/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
104eeddc0SDimitry Andric //===-- DataflowEnvironment.cpp ---------------------------------*- C++ -*-===//
204eeddc0SDimitry Andric //
304eeddc0SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
404eeddc0SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
504eeddc0SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
604eeddc0SDimitry Andric //
704eeddc0SDimitry Andric //===----------------------------------------------------------------------===//
804eeddc0SDimitry Andric //
904eeddc0SDimitry Andric //  This file defines an Environment class that is used by dataflow analyses
1004eeddc0SDimitry Andric //  that run over Control-Flow Graphs (CFGs) to keep track of the state of the
1104eeddc0SDimitry Andric //  program at given program points.
1204eeddc0SDimitry Andric //
1304eeddc0SDimitry Andric //===----------------------------------------------------------------------===//
1404eeddc0SDimitry Andric 
1504eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
1604eeddc0SDimitry Andric #include "clang/AST/Decl.h"
1704eeddc0SDimitry Andric #include "clang/AST/DeclCXX.h"
1804eeddc0SDimitry Andric #include "clang/AST/Type.h"
1904eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
2004eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h"
2104eeddc0SDimitry Andric #include "llvm/ADT/DenseMap.h"
2204eeddc0SDimitry Andric #include "llvm/ADT/DenseSet.h"
23*06c3fb27SDimitry Andric #include "llvm/ADT/MapVector.h"
24bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h"
2581ad6265SDimitry Andric #include "llvm/Support/Casting.h"
2604eeddc0SDimitry Andric #include "llvm/Support/ErrorHandling.h"
2781ad6265SDimitry Andric #include <cassert>
2804eeddc0SDimitry Andric #include <memory>
2904eeddc0SDimitry Andric #include <utility>
3004eeddc0SDimitry Andric 
3104eeddc0SDimitry Andric namespace clang {
3204eeddc0SDimitry Andric namespace dataflow {
3304eeddc0SDimitry Andric 
3481ad6265SDimitry Andric // FIXME: convert these to parameters of the analysis or environment. Current
3581ad6265SDimitry Andric // settings have been experimentaly validated, but only for a particular
3681ad6265SDimitry Andric // analysis.
3781ad6265SDimitry Andric static constexpr int MaxCompositeValueDepth = 3;
3881ad6265SDimitry Andric static constexpr int MaxCompositeValueSize = 1000;
3981ad6265SDimitry Andric 
4004eeddc0SDimitry Andric /// Returns a map consisting of key-value entries that are present in both maps.
4104eeddc0SDimitry Andric template <typename K, typename V>
4204eeddc0SDimitry Andric llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1,
4304eeddc0SDimitry Andric                                         const llvm::DenseMap<K, V> &Map2) {
4404eeddc0SDimitry Andric   llvm::DenseMap<K, V> Result;
4504eeddc0SDimitry Andric   for (auto &Entry : Map1) {
4604eeddc0SDimitry Andric     auto It = Map2.find(Entry.first);
4704eeddc0SDimitry Andric     if (It != Map2.end() && Entry.second == It->second)
4804eeddc0SDimitry Andric       Result.insert({Entry.first, Entry.second});
4904eeddc0SDimitry Andric   }
5004eeddc0SDimitry Andric   return Result;
5104eeddc0SDimitry Andric }
5204eeddc0SDimitry Andric 
53bdd1243dSDimitry Andric static bool compareDistinctValues(QualType Type, Value &Val1,
54bdd1243dSDimitry Andric                                   const Environment &Env1, Value &Val2,
5581ad6265SDimitry Andric                                   const Environment &Env2,
5681ad6265SDimitry Andric                                   Environment::ValueModel &Model) {
57bdd1243dSDimitry Andric   // Note: Potentially costly, but, for booleans, we could check whether both
58bdd1243dSDimitry Andric   // can be proven equivalent in their respective environments.
59bdd1243dSDimitry Andric 
60bdd1243dSDimitry Andric   // FIXME: move the reference/pointers logic from `areEquivalentValues` to here
61bdd1243dSDimitry Andric   // and implement separate, join/widen specific handling for
62bdd1243dSDimitry Andric   // reference/pointers.
63bdd1243dSDimitry Andric   switch (Model.compare(Type, Val1, Env1, Val2, Env2)) {
64bdd1243dSDimitry Andric   case ComparisonResult::Same:
65bdd1243dSDimitry Andric     return true;
66bdd1243dSDimitry Andric   case ComparisonResult::Different:
67bdd1243dSDimitry Andric     return false;
68bdd1243dSDimitry Andric   case ComparisonResult::Unknown:
69bdd1243dSDimitry Andric     switch (Val1.getKind()) {
70bdd1243dSDimitry Andric     case Value::Kind::Integer:
71bdd1243dSDimitry Andric     case Value::Kind::Reference:
72bdd1243dSDimitry Andric     case Value::Kind::Pointer:
73bdd1243dSDimitry Andric     case Value::Kind::Struct:
74bdd1243dSDimitry Andric       // FIXME: this choice intentionally introduces unsoundness to allow
75bdd1243dSDimitry Andric       // for convergence. Once we have widening support for the
76bdd1243dSDimitry Andric       // reference/pointer and struct built-in models, this should be
77bdd1243dSDimitry Andric       // `false`.
78bdd1243dSDimitry Andric       return true;
79bdd1243dSDimitry Andric     default:
80bdd1243dSDimitry Andric       return false;
81bdd1243dSDimitry Andric     }
82bdd1243dSDimitry Andric   }
83bdd1243dSDimitry Andric   llvm_unreachable("All cases covered in switch");
8481ad6265SDimitry Andric }
8581ad6265SDimitry Andric 
8681ad6265SDimitry Andric /// Attempts to merge distinct values `Val1` and `Val2` in `Env1` and `Env2`,
8781ad6265SDimitry Andric /// respectively, of the same type `Type`. Merging generally produces a single
8881ad6265SDimitry Andric /// value that (soundly) approximates the two inputs, although the actual
8981ad6265SDimitry Andric /// meaning depends on `Model`.
90bdd1243dSDimitry Andric static Value *mergeDistinctValues(QualType Type, Value &Val1,
91bdd1243dSDimitry Andric                                   const Environment &Env1, Value &Val2,
9281ad6265SDimitry Andric                                   const Environment &Env2,
9381ad6265SDimitry Andric                                   Environment &MergedEnv,
9481ad6265SDimitry Andric                                   Environment::ValueModel &Model) {
9581ad6265SDimitry Andric   // Join distinct boolean values preserving information about the constraints
9681ad6265SDimitry Andric   // in the respective path conditions.
97bdd1243dSDimitry Andric   if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) {
98bdd1243dSDimitry Andric     // FIXME: Checking both values should be unnecessary, since they should have
99bdd1243dSDimitry Andric     // a consistent shape.  However, right now we can end up with BoolValue's in
100bdd1243dSDimitry Andric     // integer-typed variables due to our incorrect handling of
101bdd1243dSDimitry Andric     // boolean-to-integer casts (we just propagate the BoolValue to the result
102bdd1243dSDimitry Andric     // of the cast). So, a join can encounter an integer in one branch but a
103bdd1243dSDimitry Andric     // bool in the other.
104bdd1243dSDimitry Andric     // For example:
105bdd1243dSDimitry Andric     // ```
106bdd1243dSDimitry Andric     // std::optional<bool> o;
107bdd1243dSDimitry Andric     // int x;
108bdd1243dSDimitry Andric     // if (o.has_value())
109bdd1243dSDimitry Andric     //   x = o.value();
110bdd1243dSDimitry Andric     // ```
111*06c3fb27SDimitry Andric     auto &Expr1 = cast<BoolValue>(Val1).formula();
112*06c3fb27SDimitry Andric     auto &Expr2 = cast<BoolValue>(Val2).formula();
113*06c3fb27SDimitry Andric     auto &A = MergedEnv.arena();
114*06c3fb27SDimitry Andric     auto &MergedVal = A.makeAtomRef(A.makeAtom());
115*06c3fb27SDimitry Andric     MergedEnv.addToFlowCondition(
116*06c3fb27SDimitry Andric         A.makeOr(A.makeAnd(A.makeAtomRef(Env1.getFlowConditionToken()),
117*06c3fb27SDimitry Andric                            A.makeEquals(MergedVal, Expr1)),
118*06c3fb27SDimitry Andric                  A.makeAnd(A.makeAtomRef(Env2.getFlowConditionToken()),
119*06c3fb27SDimitry Andric                            A.makeEquals(MergedVal, Expr2))));
120*06c3fb27SDimitry Andric     return &A.makeBoolValue(MergedVal);
121*06c3fb27SDimitry Andric   }
122*06c3fb27SDimitry Andric 
123*06c3fb27SDimitry Andric   Value *MergedVal = nullptr;
124*06c3fb27SDimitry Andric   if (auto *StructVal1 = dyn_cast<StructValue>(&Val1)) {
125*06c3fb27SDimitry Andric     [[maybe_unused]] auto *StructVal2 = cast<StructValue>(&Val2);
126*06c3fb27SDimitry Andric 
127*06c3fb27SDimitry Andric     // Values to be merged are always associated with the same location in
128*06c3fb27SDimitry Andric     // `LocToVal`. The location stored in `StructVal` should therefore also
129*06c3fb27SDimitry Andric     // be the same.
130*06c3fb27SDimitry Andric     assert(&StructVal1->getAggregateLoc() == &StructVal2->getAggregateLoc());
131*06c3fb27SDimitry Andric 
132*06c3fb27SDimitry Andric     // `StructVal1` and `StructVal2` may have different properties associated
133*06c3fb27SDimitry Andric     // with them. Create a new `StructValue` without any properties so that we
134*06c3fb27SDimitry Andric     // soundly approximate both values. If a particular analysis needs to merge
135*06c3fb27SDimitry Andric     // properties, it should do so in `DataflowAnalysis::merge()`.
136*06c3fb27SDimitry Andric     MergedVal = &MergedEnv.create<StructValue>(StructVal1->getAggregateLoc());
137*06c3fb27SDimitry Andric   } else {
138*06c3fb27SDimitry Andric     MergedVal = MergedEnv.createValue(Type);
13981ad6265SDimitry Andric   }
14081ad6265SDimitry Andric 
14181ad6265SDimitry Andric   // FIXME: Consider destroying `MergedValue` immediately if `ValueModel::merge`
14281ad6265SDimitry Andric   // returns false to avoid storing unneeded values in `DACtx`.
143bdd1243dSDimitry Andric   // FIXME: Creating the value based on the type alone creates misshapen values
144bdd1243dSDimitry Andric   // for lvalues, since the type does not reflect the need for `ReferenceValue`.
145*06c3fb27SDimitry Andric   // This issue will be resolved when `ReferenceValue` is eliminated as part
146*06c3fb27SDimitry Andric   // of the ongoing migration to strict handling of value categories (see
147*06c3fb27SDimitry Andric   // https://discourse.llvm.org/t/70086 for details).
148*06c3fb27SDimitry Andric   if (MergedVal)
149bdd1243dSDimitry Andric     if (Model.merge(Type, Val1, Env1, Val2, Env2, *MergedVal, MergedEnv))
15081ad6265SDimitry Andric       return MergedVal;
15181ad6265SDimitry Andric 
15281ad6265SDimitry Andric   return nullptr;
15381ad6265SDimitry Andric }
15481ad6265SDimitry Andric 
155bdd1243dSDimitry Andric // When widening does not change `Current`, return value will equal `&Prev`.
156bdd1243dSDimitry Andric static Value &widenDistinctValues(QualType Type, Value &Prev,
157bdd1243dSDimitry Andric                                   const Environment &PrevEnv, Value &Current,
158bdd1243dSDimitry Andric                                   Environment &CurrentEnv,
159bdd1243dSDimitry Andric                                   Environment::ValueModel &Model) {
160bdd1243dSDimitry Andric   // Boolean-model widening.
161bdd1243dSDimitry Andric   if (isa<BoolValue>(&Prev)) {
162bdd1243dSDimitry Andric     assert(isa<BoolValue>(Current));
163bdd1243dSDimitry Andric     // Widen to Top, because we know they are different values. If previous was
164bdd1243dSDimitry Andric     // already Top, re-use that to (implicitly) indicate that no change occured.
165bdd1243dSDimitry Andric     if (isa<TopBoolValue>(Prev))
166bdd1243dSDimitry Andric       return Prev;
167bdd1243dSDimitry Andric     return CurrentEnv.makeTopBoolValue();
168bdd1243dSDimitry Andric   }
16981ad6265SDimitry Andric 
170bdd1243dSDimitry Andric   // FIXME: Add other built-in model widening.
171bdd1243dSDimitry Andric 
172bdd1243dSDimitry Andric   // Custom-model widening.
173bdd1243dSDimitry Andric   if (auto *W = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv))
174bdd1243dSDimitry Andric     return *W;
175bdd1243dSDimitry Andric 
176bdd1243dSDimitry Andric   // Default of widening is a no-op: leave the current value unchanged.
177bdd1243dSDimitry Andric   return Current;
17881ad6265SDimitry Andric }
17981ad6265SDimitry Andric 
18081ad6265SDimitry Andric /// Initializes a global storage value.
181bdd1243dSDimitry Andric static void insertIfGlobal(const Decl &D,
182bdd1243dSDimitry Andric                            llvm::DenseSet<const VarDecl *> &Vars) {
18381ad6265SDimitry Andric   if (auto *V = dyn_cast<VarDecl>(&D))
184bdd1243dSDimitry Andric     if (V->hasGlobalStorage())
185bdd1243dSDimitry Andric       Vars.insert(V);
18681ad6265SDimitry Andric }
18781ad6265SDimitry Andric 
188*06c3fb27SDimitry Andric static void insertIfFunction(const Decl &D,
189*06c3fb27SDimitry Andric                              llvm::DenseSet<const FunctionDecl *> &Funcs) {
190*06c3fb27SDimitry Andric   if (auto *FD = dyn_cast<FunctionDecl>(&D))
191*06c3fb27SDimitry Andric     Funcs.insert(FD);
192*06c3fb27SDimitry Andric }
193*06c3fb27SDimitry Andric 
194*06c3fb27SDimitry Andric static void
195*06c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(const Decl &D, FieldSet &Fields,
196*06c3fb27SDimitry Andric                          llvm::DenseSet<const VarDecl *> &Vars,
197*06c3fb27SDimitry Andric                          llvm::DenseSet<const FunctionDecl *> &Funcs) {
198*06c3fb27SDimitry Andric   insertIfGlobal(D, Vars);
199*06c3fb27SDimitry Andric   insertIfFunction(D, Funcs);
200bdd1243dSDimitry Andric   if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D))
201bdd1243dSDimitry Andric     for (const auto *B : Decomp->bindings())
202bdd1243dSDimitry Andric       if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding()))
203bdd1243dSDimitry Andric         // FIXME: should we be using `E->getFoundDecl()`?
204bdd1243dSDimitry Andric         if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
205bdd1243dSDimitry Andric           Fields.insert(FD);
20681ad6265SDimitry Andric }
20781ad6265SDimitry Andric 
208*06c3fb27SDimitry Andric /// Traverses `S` and inserts into `Fields`, `Vars` and `Funcs` any fields,
209*06c3fb27SDimitry Andric /// global variables and functions that are declared in or referenced from
210*06c3fb27SDimitry Andric /// sub-statements.
211*06c3fb27SDimitry Andric static void
212*06c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(const Stmt &S, FieldSet &Fields,
213*06c3fb27SDimitry Andric                          llvm::DenseSet<const VarDecl *> &Vars,
214*06c3fb27SDimitry Andric                          llvm::DenseSet<const FunctionDecl *> &Funcs) {
215bdd1243dSDimitry Andric   for (auto *Child : S.children())
216bdd1243dSDimitry Andric     if (Child != nullptr)
217*06c3fb27SDimitry Andric       getFieldsGlobalsAndFuncs(*Child, Fields, Vars, Funcs);
218*06c3fb27SDimitry Andric   if (const auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(&S))
219*06c3fb27SDimitry Andric     getFieldsGlobalsAndFuncs(*DefaultInit->getExpr(), Fields, Vars, Funcs);
220bdd1243dSDimitry Andric 
22181ad6265SDimitry Andric   if (auto *DS = dyn_cast<DeclStmt>(&S)) {
222bdd1243dSDimitry Andric     if (DS->isSingleDecl())
223*06c3fb27SDimitry Andric       getFieldsGlobalsAndFuncs(*DS->getSingleDecl(), Fields, Vars, Funcs);
224bdd1243dSDimitry Andric     else
22581ad6265SDimitry Andric       for (auto *D : DS->getDeclGroup())
226*06c3fb27SDimitry Andric         getFieldsGlobalsAndFuncs(*D, Fields, Vars, Funcs);
22781ad6265SDimitry Andric   } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) {
228*06c3fb27SDimitry Andric     insertIfGlobal(*E->getDecl(), Vars);
229*06c3fb27SDimitry Andric     insertIfFunction(*E->getDecl(), Funcs);
23081ad6265SDimitry Andric   } else if (auto *E = dyn_cast<MemberExpr>(&S)) {
231bdd1243dSDimitry Andric     // FIXME: should we be using `E->getFoundDecl()`?
232bdd1243dSDimitry Andric     const ValueDecl *VD = E->getMemberDecl();
233*06c3fb27SDimitry Andric     insertIfGlobal(*VD, Vars);
234*06c3fb27SDimitry Andric     insertIfFunction(*VD, Funcs);
235bdd1243dSDimitry Andric     if (const auto *FD = dyn_cast<FieldDecl>(VD))
236bdd1243dSDimitry Andric       Fields.insert(FD);
237*06c3fb27SDimitry Andric   } else if (auto *InitList = dyn_cast<InitListExpr>(&S)) {
238*06c3fb27SDimitry Andric     if (RecordDecl *RD = InitList->getType()->getAsRecordDecl())
239*06c3fb27SDimitry Andric       for (const auto *FD : getFieldsForInitListExpr(RD))
240*06c3fb27SDimitry Andric         Fields.insert(FD);
241bdd1243dSDimitry Andric   }
242bdd1243dSDimitry Andric }
243bdd1243dSDimitry Andric 
244bdd1243dSDimitry Andric // FIXME: Add support for resetting globals after function calls to enable
245bdd1243dSDimitry Andric // the implementation of sound analyses.
246*06c3fb27SDimitry Andric void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) {
247*06c3fb27SDimitry Andric   assert(FuncDecl->getBody() != nullptr);
248*06c3fb27SDimitry Andric 
249*06c3fb27SDimitry Andric   FieldSet Fields;
250*06c3fb27SDimitry Andric   llvm::DenseSet<const VarDecl *> Vars;
251*06c3fb27SDimitry Andric   llvm::DenseSet<const FunctionDecl *> Funcs;
252*06c3fb27SDimitry Andric 
253*06c3fb27SDimitry Andric   // Look for global variable and field references in the
254*06c3fb27SDimitry Andric   // constructor-initializers.
255*06c3fb27SDimitry Andric   if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FuncDecl)) {
256*06c3fb27SDimitry Andric     for (const auto *Init : CtorDecl->inits()) {
257*06c3fb27SDimitry Andric       if (Init->isMemberInitializer()) {
258*06c3fb27SDimitry Andric         Fields.insert(Init->getMember());
259*06c3fb27SDimitry Andric       } else if (Init->isIndirectMemberInitializer()) {
260*06c3fb27SDimitry Andric         for (const auto *I : Init->getIndirectMember()->chain())
261*06c3fb27SDimitry Andric           Fields.insert(cast<FieldDecl>(I));
262*06c3fb27SDimitry Andric       }
263*06c3fb27SDimitry Andric       const Expr *E = Init->getInit();
264*06c3fb27SDimitry Andric       assert(E != nullptr);
265*06c3fb27SDimitry Andric       getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs);
266*06c3fb27SDimitry Andric     }
267*06c3fb27SDimitry Andric     // Add all fields mentioned in default member initializers.
268*06c3fb27SDimitry Andric     for (const FieldDecl *F : CtorDecl->getParent()->fields())
269*06c3fb27SDimitry Andric       if (const auto *I = F->getInClassInitializer())
270*06c3fb27SDimitry Andric           getFieldsGlobalsAndFuncs(*I, Fields, Vars, Funcs);
271*06c3fb27SDimitry Andric   }
272*06c3fb27SDimitry Andric   getFieldsGlobalsAndFuncs(*FuncDecl->getBody(), Fields, Vars, Funcs);
273*06c3fb27SDimitry Andric 
274*06c3fb27SDimitry Andric   // These have to be added before the lines that follow to ensure that
275*06c3fb27SDimitry Andric   // `create*` work correctly for structs.
276*06c3fb27SDimitry Andric   DACtx->addModeledFields(Fields);
277*06c3fb27SDimitry Andric 
278bdd1243dSDimitry Andric   for (const VarDecl *D : Vars) {
279*06c3fb27SDimitry Andric     if (getStorageLocation(*D) != nullptr)
280bdd1243dSDimitry Andric       continue;
281*06c3fb27SDimitry Andric 
282*06c3fb27SDimitry Andric     setStorageLocation(*D, createObject(*D));
283*06c3fb27SDimitry Andric   }
284*06c3fb27SDimitry Andric 
285*06c3fb27SDimitry Andric   for (const FunctionDecl *FD : Funcs) {
286*06c3fb27SDimitry Andric     if (getStorageLocation(*FD) != nullptr)
287*06c3fb27SDimitry Andric       continue;
288*06c3fb27SDimitry Andric     auto &Loc = createStorageLocation(FD->getType());
289*06c3fb27SDimitry Andric     setStorageLocation(*FD, Loc);
29081ad6265SDimitry Andric   }
29181ad6265SDimitry Andric }
29281ad6265SDimitry Andric 
29381ad6265SDimitry Andric Environment::Environment(DataflowAnalysisContext &DACtx)
294*06c3fb27SDimitry Andric     : DACtx(&DACtx),
295*06c3fb27SDimitry Andric       FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {}
29681ad6265SDimitry Andric 
297*06c3fb27SDimitry Andric Environment Environment::fork() const {
298*06c3fb27SDimitry Andric   Environment Copy(*this);
299*06c3fb27SDimitry Andric   Copy.FlowConditionToken = DACtx->forkFlowCondition(FlowConditionToken);
300*06c3fb27SDimitry Andric   return Copy;
3011fd87a68SDimitry Andric }
3021fd87a68SDimitry Andric 
30304eeddc0SDimitry Andric Environment::Environment(DataflowAnalysisContext &DACtx,
30404eeddc0SDimitry Andric                          const DeclContext &DeclCtx)
30504eeddc0SDimitry Andric     : Environment(DACtx) {
306bdd1243dSDimitry Andric   CallStack.push_back(&DeclCtx);
307bdd1243dSDimitry Andric 
30804eeddc0SDimitry Andric   if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) {
30981ad6265SDimitry Andric     assert(FuncDecl->getBody() != nullptr);
310bdd1243dSDimitry Andric 
311*06c3fb27SDimitry Andric     initFieldsGlobalsAndFuncs(FuncDecl);
312bdd1243dSDimitry Andric 
31304eeddc0SDimitry Andric     for (const auto *ParamDecl : FuncDecl->parameters()) {
31404eeddc0SDimitry Andric       assert(ParamDecl != nullptr);
315*06c3fb27SDimitry Andric       setStorageLocation(*ParamDecl, createObject(*ParamDecl, nullptr));
31604eeddc0SDimitry Andric     }
31704eeddc0SDimitry Andric   }
31804eeddc0SDimitry Andric 
31904eeddc0SDimitry Andric   if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) {
32081ad6265SDimitry Andric     auto *Parent = MethodDecl->getParent();
32181ad6265SDimitry Andric     assert(Parent != nullptr);
32281ad6265SDimitry Andric     if (Parent->isLambda())
32381ad6265SDimitry Andric       MethodDecl = dyn_cast<CXXMethodDecl>(Parent->getDeclContext());
32481ad6265SDimitry Andric 
325bdd1243dSDimitry Andric     // FIXME: Initialize the ThisPointeeLoc of lambdas too.
32681ad6265SDimitry Andric     if (MethodDecl && !MethodDecl->isStatic()) {
32704eeddc0SDimitry Andric       QualType ThisPointeeType = MethodDecl->getThisObjectType();
328*06c3fb27SDimitry Andric       ThisPointeeLoc =
329*06c3fb27SDimitry Andric           &cast<StructValue>(createValue(ThisPointeeType))->getAggregateLoc();
33004eeddc0SDimitry Andric     }
33104eeddc0SDimitry Andric   }
33204eeddc0SDimitry Andric }
333bdd1243dSDimitry Andric 
334bdd1243dSDimitry Andric bool Environment::canDescend(unsigned MaxDepth,
335bdd1243dSDimitry Andric                              const DeclContext *Callee) const {
336bdd1243dSDimitry Andric   return CallStack.size() <= MaxDepth && !llvm::is_contained(CallStack, Callee);
33704eeddc0SDimitry Andric }
33804eeddc0SDimitry Andric 
339972a253aSDimitry Andric Environment Environment::pushCall(const CallExpr *Call) const {
340972a253aSDimitry Andric   Environment Env(*this);
341972a253aSDimitry Andric 
342bdd1243dSDimitry Andric   if (const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(Call)) {
343bdd1243dSDimitry Andric     if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
344bdd1243dSDimitry Andric       if (!isa<CXXThisExpr>(Arg))
345*06c3fb27SDimitry Andric         Env.ThisPointeeLoc = cast<AggregateStorageLocation>(
346*06c3fb27SDimitry Andric             getStorageLocation(*Arg, SkipPast::Reference));
347bdd1243dSDimitry Andric       // Otherwise (when the argument is `this`), retain the current
348bdd1243dSDimitry Andric       // environment's `ThisPointeeLoc`.
349bdd1243dSDimitry Andric     }
350bdd1243dSDimitry Andric   }
351972a253aSDimitry Andric 
352bdd1243dSDimitry Andric   Env.pushCallInternal(Call->getDirectCallee(),
353bdd1243dSDimitry Andric                        llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));
354bdd1243dSDimitry Andric 
355bdd1243dSDimitry Andric   return Env;
356bdd1243dSDimitry Andric }
357bdd1243dSDimitry Andric 
358bdd1243dSDimitry Andric Environment Environment::pushCall(const CXXConstructExpr *Call) const {
359bdd1243dSDimitry Andric   Environment Env(*this);
360bdd1243dSDimitry Andric 
361*06c3fb27SDimitry Andric   Env.ThisPointeeLoc = &Env.getResultObjectLocation(*Call);
362bdd1243dSDimitry Andric 
363bdd1243dSDimitry Andric   Env.pushCallInternal(Call->getConstructor(),
364bdd1243dSDimitry Andric                        llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));
365bdd1243dSDimitry Andric 
366bdd1243dSDimitry Andric   return Env;
367bdd1243dSDimitry Andric }
368bdd1243dSDimitry Andric 
369bdd1243dSDimitry Andric void Environment::pushCallInternal(const FunctionDecl *FuncDecl,
370bdd1243dSDimitry Andric                                    ArrayRef<const Expr *> Args) {
371*06c3fb27SDimitry Andric   // Canonicalize to the definition of the function. This ensures that we're
372*06c3fb27SDimitry Andric   // putting arguments into the same `ParamVarDecl`s` that the callee will later
373*06c3fb27SDimitry Andric   // be retrieving them from.
374*06c3fb27SDimitry Andric   assert(FuncDecl->getDefinition() != nullptr);
375*06c3fb27SDimitry Andric   FuncDecl = FuncDecl->getDefinition();
376*06c3fb27SDimitry Andric 
377bdd1243dSDimitry Andric   CallStack.push_back(FuncDecl);
378bdd1243dSDimitry Andric 
379*06c3fb27SDimitry Andric   initFieldsGlobalsAndFuncs(FuncDecl);
380bdd1243dSDimitry Andric 
381bdd1243dSDimitry Andric   const auto *ParamIt = FuncDecl->param_begin();
382972a253aSDimitry Andric 
383972a253aSDimitry Andric   // FIXME: Parameters don't always map to arguments 1:1; examples include
384972a253aSDimitry Andric   // overloaded operators implemented as member functions, and parameter packs.
385bdd1243dSDimitry Andric   for (unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) {
386972a253aSDimitry Andric     assert(ParamIt != FuncDecl->param_end());
387972a253aSDimitry Andric     const VarDecl *Param = *ParamIt;
388*06c3fb27SDimitry Andric     setStorageLocation(*Param, createObject(*Param, Args[ArgIndex]));
389bdd1243dSDimitry Andric   }
390972a253aSDimitry Andric }
391972a253aSDimitry Andric 
392*06c3fb27SDimitry Andric void Environment::popCall(const CallExpr *Call, const Environment &CalleeEnv) {
393bdd1243dSDimitry Andric   // We ignore `DACtx` because it's already the same in both. We don't want the
394*06c3fb27SDimitry Andric   // callee's `DeclCtx`, `ReturnVal`, `ReturnLoc` or `ThisPointeeLoc`. We don't
395*06c3fb27SDimitry Andric   // bring back `DeclToLoc` and `ExprToLoc` because we want to be able to later
396*06c3fb27SDimitry Andric   // analyze the same callee in a different context, and `setStorageLocation`
397*06c3fb27SDimitry Andric   // requires there to not already be a storage location assigned. Conceptually,
398*06c3fb27SDimitry Andric   // these maps capture information from the local scope, so when popping that
399*06c3fb27SDimitry Andric   // scope, we do not propagate the maps.
400bdd1243dSDimitry Andric   this->LocToVal = std::move(CalleeEnv.LocToVal);
401bdd1243dSDimitry Andric   this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
402*06c3fb27SDimitry Andric 
403*06c3fb27SDimitry Andric   if (Call->isGLValue()) {
404*06c3fb27SDimitry Andric     if (CalleeEnv.ReturnLoc != nullptr)
405*06c3fb27SDimitry Andric       setStorageLocationStrict(*Call, *CalleeEnv.ReturnLoc);
406*06c3fb27SDimitry Andric   } else if (!Call->getType()->isVoidType()) {
407*06c3fb27SDimitry Andric     if (CalleeEnv.ReturnVal != nullptr)
408*06c3fb27SDimitry Andric       setValueStrict(*Call, *CalleeEnv.ReturnVal);
409*06c3fb27SDimitry Andric   }
410*06c3fb27SDimitry Andric }
411*06c3fb27SDimitry Andric 
412*06c3fb27SDimitry Andric void Environment::popCall(const CXXConstructExpr *Call,
413*06c3fb27SDimitry Andric                           const Environment &CalleeEnv) {
414*06c3fb27SDimitry Andric   // See also comment in `popCall(const CallExpr *, const Environment &)` above.
415*06c3fb27SDimitry Andric   this->LocToVal = std::move(CalleeEnv.LocToVal);
416*06c3fb27SDimitry Andric   this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
417*06c3fb27SDimitry Andric 
418*06c3fb27SDimitry Andric   if (Value *Val = CalleeEnv.getValue(*CalleeEnv.ThisPointeeLoc)) {
419*06c3fb27SDimitry Andric     setValueStrict(*Call, *Val);
420*06c3fb27SDimitry Andric   }
421972a253aSDimitry Andric }
422972a253aSDimitry Andric 
4231fd87a68SDimitry Andric bool Environment::equivalentTo(const Environment &Other,
4241fd87a68SDimitry Andric                                Environment::ValueModel &Model) const {
42504eeddc0SDimitry Andric   assert(DACtx == Other.DACtx);
4261fd87a68SDimitry Andric 
427*06c3fb27SDimitry Andric   if (ReturnVal != Other.ReturnVal)
428*06c3fb27SDimitry Andric     return false;
429*06c3fb27SDimitry Andric 
430bdd1243dSDimitry Andric   if (ReturnLoc != Other.ReturnLoc)
431bdd1243dSDimitry Andric     return false;
432bdd1243dSDimitry Andric 
433bdd1243dSDimitry Andric   if (ThisPointeeLoc != Other.ThisPointeeLoc)
434bdd1243dSDimitry Andric     return false;
435bdd1243dSDimitry Andric 
4361fd87a68SDimitry Andric   if (DeclToLoc != Other.DeclToLoc)
4371fd87a68SDimitry Andric     return false;
4381fd87a68SDimitry Andric 
4391fd87a68SDimitry Andric   if (ExprToLoc != Other.ExprToLoc)
4401fd87a68SDimitry Andric     return false;
4411fd87a68SDimitry Andric 
44281ad6265SDimitry Andric   // Compare the contents for the intersection of their domains.
4431fd87a68SDimitry Andric   for (auto &Entry : LocToVal) {
4441fd87a68SDimitry Andric     const StorageLocation *Loc = Entry.first;
4451fd87a68SDimitry Andric     assert(Loc != nullptr);
4461fd87a68SDimitry Andric 
4471fd87a68SDimitry Andric     Value *Val = Entry.second;
4481fd87a68SDimitry Andric     assert(Val != nullptr);
4491fd87a68SDimitry Andric 
4501fd87a68SDimitry Andric     auto It = Other.LocToVal.find(Loc);
4511fd87a68SDimitry Andric     if (It == Other.LocToVal.end())
45281ad6265SDimitry Andric       continue;
4531fd87a68SDimitry Andric     assert(It->second != nullptr);
4541fd87a68SDimitry Andric 
455bdd1243dSDimitry Andric     if (!areEquivalentValues(*Val, *It->second) &&
456bdd1243dSDimitry Andric         !compareDistinctValues(Loc->getType(), *Val, *this, *It->second, Other,
457bdd1243dSDimitry Andric                                Model))
4581fd87a68SDimitry Andric       return false;
4591fd87a68SDimitry Andric   }
4601fd87a68SDimitry Andric 
4611fd87a68SDimitry Andric   return true;
46204eeddc0SDimitry Andric }
46304eeddc0SDimitry Andric 
464bdd1243dSDimitry Andric LatticeJoinEffect Environment::widen(const Environment &PrevEnv,
465bdd1243dSDimitry Andric                                      Environment::ValueModel &Model) {
466bdd1243dSDimitry Andric   assert(DACtx == PrevEnv.DACtx);
467*06c3fb27SDimitry Andric   assert(ReturnVal == PrevEnv.ReturnVal);
468bdd1243dSDimitry Andric   assert(ReturnLoc == PrevEnv.ReturnLoc);
469bdd1243dSDimitry Andric   assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc);
470bdd1243dSDimitry Andric   assert(CallStack == PrevEnv.CallStack);
471bdd1243dSDimitry Andric 
472bdd1243dSDimitry Andric   auto Effect = LatticeJoinEffect::Unchanged;
473bdd1243dSDimitry Andric 
474bdd1243dSDimitry Andric   // By the API, `PrevEnv` is a previous version of the environment for the same
475bdd1243dSDimitry Andric   // block, so we have some guarantees about its shape. In particular, it will
476bdd1243dSDimitry Andric   // be the result of a join or widen operation on previous values for this
477bdd1243dSDimitry Andric   // block. For `DeclToLoc` and `ExprToLoc`, join guarantees that these maps are
478bdd1243dSDimitry Andric   // subsets of the maps in `PrevEnv`. So, as long as we maintain this property
479bdd1243dSDimitry Andric   // here, we don't need change their current values to widen.
480bdd1243dSDimitry Andric   assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size());
481bdd1243dSDimitry Andric   assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size());
482bdd1243dSDimitry Andric 
483*06c3fb27SDimitry Andric   llvm::MapVector<const StorageLocation *, Value *> WidenedLocToVal;
484bdd1243dSDimitry Andric   for (auto &Entry : LocToVal) {
485bdd1243dSDimitry Andric     const StorageLocation *Loc = Entry.first;
486bdd1243dSDimitry Andric     assert(Loc != nullptr);
487bdd1243dSDimitry Andric 
488bdd1243dSDimitry Andric     Value *Val = Entry.second;
489bdd1243dSDimitry Andric     assert(Val != nullptr);
490bdd1243dSDimitry Andric 
491bdd1243dSDimitry Andric     auto PrevIt = PrevEnv.LocToVal.find(Loc);
492bdd1243dSDimitry Andric     if (PrevIt == PrevEnv.LocToVal.end())
493bdd1243dSDimitry Andric       continue;
494bdd1243dSDimitry Andric     assert(PrevIt->second != nullptr);
495bdd1243dSDimitry Andric 
496bdd1243dSDimitry Andric     if (areEquivalentValues(*Val, *PrevIt->second)) {
497bdd1243dSDimitry Andric       WidenedLocToVal.insert({Loc, Val});
498bdd1243dSDimitry Andric       continue;
499bdd1243dSDimitry Andric     }
500bdd1243dSDimitry Andric 
501bdd1243dSDimitry Andric     Value &WidenedVal = widenDistinctValues(Loc->getType(), *PrevIt->second,
502bdd1243dSDimitry Andric                                             PrevEnv, *Val, *this, Model);
503bdd1243dSDimitry Andric     WidenedLocToVal.insert({Loc, &WidenedVal});
504bdd1243dSDimitry Andric     if (&WidenedVal != PrevIt->second)
505bdd1243dSDimitry Andric       Effect = LatticeJoinEffect::Changed;
506bdd1243dSDimitry Andric   }
507bdd1243dSDimitry Andric   LocToVal = std::move(WidenedLocToVal);
508bdd1243dSDimitry Andric   if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() ||
509bdd1243dSDimitry Andric       ExprToLoc.size() != PrevEnv.ExprToLoc.size() ||
510*06c3fb27SDimitry Andric       LocToVal.size() != PrevEnv.LocToVal.size())
511bdd1243dSDimitry Andric     Effect = LatticeJoinEffect::Changed;
512bdd1243dSDimitry Andric 
513bdd1243dSDimitry Andric   return Effect;
514bdd1243dSDimitry Andric }
515bdd1243dSDimitry Andric 
516*06c3fb27SDimitry Andric Environment Environment::join(const Environment &EnvA, const Environment &EnvB,
5171fd87a68SDimitry Andric                               Environment::ValueModel &Model) {
518*06c3fb27SDimitry Andric   assert(EnvA.DACtx == EnvB.DACtx);
519*06c3fb27SDimitry Andric   assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc);
520*06c3fb27SDimitry Andric   assert(EnvA.CallStack == EnvB.CallStack);
52104eeddc0SDimitry Andric 
522*06c3fb27SDimitry Andric   Environment JoinedEnv(*EnvA.DACtx);
52304eeddc0SDimitry Andric 
524*06c3fb27SDimitry Andric   JoinedEnv.CallStack = EnvA.CallStack;
525*06c3fb27SDimitry Andric   JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc;
52681ad6265SDimitry Andric 
527*06c3fb27SDimitry Andric   if (EnvA.ReturnVal == nullptr || EnvB.ReturnVal == nullptr) {
528*06c3fb27SDimitry Andric     // `ReturnVal` might not always get set -- for example if we have a return
529*06c3fb27SDimitry Andric     // statement of the form `return some_other_func()` and we decide not to
530*06c3fb27SDimitry Andric     // analyze `some_other_func()`.
531*06c3fb27SDimitry Andric     // In this case, we can't say anything about the joined return value -- we
532*06c3fb27SDimitry Andric     // don't simply want to propagate the return value that we do have, because
533*06c3fb27SDimitry Andric     // it might not be the correct one.
534*06c3fb27SDimitry Andric     // This occurs for example in the test `ContextSensitiveMutualRecursion`.
535*06c3fb27SDimitry Andric     JoinedEnv.ReturnVal = nullptr;
536*06c3fb27SDimitry Andric   } else if (areEquivalentValues(*EnvA.ReturnVal, *EnvB.ReturnVal)) {
537*06c3fb27SDimitry Andric     JoinedEnv.ReturnVal = EnvA.ReturnVal;
538*06c3fb27SDimitry Andric   } else {
539*06c3fb27SDimitry Andric     assert(!EnvA.CallStack.empty());
540*06c3fb27SDimitry Andric     // FIXME: Make `CallStack` a vector of `FunctionDecl` so we don't need this
541*06c3fb27SDimitry Andric     // cast.
542*06c3fb27SDimitry Andric     auto *Func = dyn_cast<FunctionDecl>(EnvA.CallStack.back());
543*06c3fb27SDimitry Andric     assert(Func != nullptr);
544*06c3fb27SDimitry Andric     if (Value *MergedVal =
545*06c3fb27SDimitry Andric             mergeDistinctValues(Func->getReturnType(), *EnvA.ReturnVal, EnvA,
546*06c3fb27SDimitry Andric                                 *EnvB.ReturnVal, EnvB, JoinedEnv, Model))
547*06c3fb27SDimitry Andric       JoinedEnv.ReturnVal = MergedVal;
548*06c3fb27SDimitry Andric   }
549bdd1243dSDimitry Andric 
550*06c3fb27SDimitry Andric   if (EnvA.ReturnLoc == EnvB.ReturnLoc)
551*06c3fb27SDimitry Andric     JoinedEnv.ReturnLoc = EnvA.ReturnLoc;
552*06c3fb27SDimitry Andric   else
553*06c3fb27SDimitry Andric     JoinedEnv.ReturnLoc = nullptr;
55404eeddc0SDimitry Andric 
555*06c3fb27SDimitry Andric   // FIXME: Once we're able to remove declarations from `DeclToLoc` when their
556*06c3fb27SDimitry Andric   // lifetime ends, add an assertion that there aren't any entries in
557*06c3fb27SDimitry Andric   // `DeclToLoc` and `Other.DeclToLoc` that map the same declaration to
558*06c3fb27SDimitry Andric   // different storage locations.
559*06c3fb27SDimitry Andric   JoinedEnv.DeclToLoc = intersectDenseMaps(EnvA.DeclToLoc, EnvB.DeclToLoc);
56004eeddc0SDimitry Andric 
561*06c3fb27SDimitry Andric   JoinedEnv.ExprToLoc = intersectDenseMaps(EnvA.ExprToLoc, EnvB.ExprToLoc);
56281ad6265SDimitry Andric 
563bdd1243dSDimitry Andric   // FIXME: update join to detect backedges and simplify the flow condition
564bdd1243dSDimitry Andric   // accordingly.
565*06c3fb27SDimitry Andric   JoinedEnv.FlowConditionToken = EnvA.DACtx->joinFlowConditions(
566*06c3fb27SDimitry Andric       EnvA.FlowConditionToken, EnvB.FlowConditionToken);
56781ad6265SDimitry Andric 
568*06c3fb27SDimitry Andric   for (auto &Entry : EnvA.LocToVal) {
56904eeddc0SDimitry Andric     const StorageLocation *Loc = Entry.first;
57004eeddc0SDimitry Andric     assert(Loc != nullptr);
57104eeddc0SDimitry Andric 
57204eeddc0SDimitry Andric     Value *Val = Entry.second;
57304eeddc0SDimitry Andric     assert(Val != nullptr);
57404eeddc0SDimitry Andric 
575*06c3fb27SDimitry Andric     auto It = EnvB.LocToVal.find(Loc);
576*06c3fb27SDimitry Andric     if (It == EnvB.LocToVal.end())
57704eeddc0SDimitry Andric       continue;
57804eeddc0SDimitry Andric     assert(It->second != nullptr);
57904eeddc0SDimitry Andric 
580bdd1243dSDimitry Andric     if (areEquivalentValues(*Val, *It->second)) {
58181ad6265SDimitry Andric       JoinedEnv.LocToVal.insert({Loc, Val});
58204eeddc0SDimitry Andric       continue;
58304eeddc0SDimitry Andric     }
58404eeddc0SDimitry Andric 
585*06c3fb27SDimitry Andric     if (Value *MergedVal = mergeDistinctValues(
586*06c3fb27SDimitry Andric             Loc->getType(), *Val, EnvA, *It->second, EnvB, JoinedEnv, Model)) {
58781ad6265SDimitry Andric       JoinedEnv.LocToVal.insert({Loc, MergedVal});
588bdd1243dSDimitry Andric     }
58904eeddc0SDimitry Andric   }
59004eeddc0SDimitry Andric 
591*06c3fb27SDimitry Andric   return JoinedEnv;
59204eeddc0SDimitry Andric }
59304eeddc0SDimitry Andric 
59404eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(QualType Type) {
595bdd1243dSDimitry Andric   return DACtx->createStorageLocation(Type);
59604eeddc0SDimitry Andric }
59704eeddc0SDimitry Andric 
59804eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const VarDecl &D) {
59904eeddc0SDimitry Andric   // Evaluated declarations are always assigned the same storage locations to
60004eeddc0SDimitry Andric   // ensure that the environment stabilizes across loop iterations. Storage
60104eeddc0SDimitry Andric   // locations for evaluated declarations are stored in the analysis context.
60281ad6265SDimitry Andric   return DACtx->getStableStorageLocation(D);
60304eeddc0SDimitry Andric }
60404eeddc0SDimitry Andric 
60504eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const Expr &E) {
60604eeddc0SDimitry Andric   // Evaluated expressions are always assigned the same storage locations to
60704eeddc0SDimitry Andric   // ensure that the environment stabilizes across loop iterations. Storage
60804eeddc0SDimitry Andric   // locations for evaluated expressions are stored in the analysis context.
60981ad6265SDimitry Andric   return DACtx->getStableStorageLocation(E);
61004eeddc0SDimitry Andric }
61104eeddc0SDimitry Andric 
61204eeddc0SDimitry Andric void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
613*06c3fb27SDimitry Andric   assert(!DeclToLoc.contains(&D));
614*06c3fb27SDimitry Andric   assert(!isa_and_nonnull<ReferenceValue>(getValue(Loc)));
61504eeddc0SDimitry Andric   DeclToLoc[&D] = &Loc;
61604eeddc0SDimitry Andric }
61704eeddc0SDimitry Andric 
618*06c3fb27SDimitry Andric StorageLocation *Environment::getStorageLocation(const ValueDecl &D) const {
61904eeddc0SDimitry Andric   auto It = DeclToLoc.find(&D);
620*06c3fb27SDimitry Andric   if (It == DeclToLoc.end())
621*06c3fb27SDimitry Andric     return nullptr;
622*06c3fb27SDimitry Andric 
623*06c3fb27SDimitry Andric   StorageLocation *Loc = It->second;
624*06c3fb27SDimitry Andric 
625*06c3fb27SDimitry Andric   assert(!isa_and_nonnull<ReferenceValue>(getValue(*Loc)));
626*06c3fb27SDimitry Andric 
627*06c3fb27SDimitry Andric   return Loc;
62804eeddc0SDimitry Andric }
62904eeddc0SDimitry Andric 
63004eeddc0SDimitry Andric void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
63181ad6265SDimitry Andric   const Expr &CanonE = ignoreCFGOmittedNodes(E);
632*06c3fb27SDimitry Andric   assert(!ExprToLoc.contains(&CanonE));
63381ad6265SDimitry Andric   ExprToLoc[&CanonE] = &Loc;
63404eeddc0SDimitry Andric }
63504eeddc0SDimitry Andric 
636*06c3fb27SDimitry Andric void Environment::setStorageLocationStrict(const Expr &E,
637*06c3fb27SDimitry Andric                                            StorageLocation &Loc) {
638*06c3fb27SDimitry Andric   // `DeclRefExpr`s to builtin function types aren't glvalues, for some reason,
639*06c3fb27SDimitry Andric   // but we still want to be able to associate a `StorageLocation` with them,
640*06c3fb27SDimitry Andric   // so allow these as an exception.
641*06c3fb27SDimitry Andric   assert(E.isGLValue() ||
642*06c3fb27SDimitry Andric          E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
643*06c3fb27SDimitry Andric   setStorageLocation(E, Loc);
644*06c3fb27SDimitry Andric }
645*06c3fb27SDimitry Andric 
64604eeddc0SDimitry Andric StorageLocation *Environment::getStorageLocation(const Expr &E,
64704eeddc0SDimitry Andric                                                  SkipPast SP) const {
64881ad6265SDimitry Andric   // FIXME: Add a test with parens.
64981ad6265SDimitry Andric   auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));
65004eeddc0SDimitry Andric   return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP);
65104eeddc0SDimitry Andric }
65204eeddc0SDimitry Andric 
653*06c3fb27SDimitry Andric StorageLocation *Environment::getStorageLocationStrict(const Expr &E) const {
654*06c3fb27SDimitry Andric   // See comment in `setStorageLocationStrict()`.
655*06c3fb27SDimitry Andric   assert(E.isGLValue() ||
656*06c3fb27SDimitry Andric          E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
657*06c3fb27SDimitry Andric   StorageLocation *Loc = getStorageLocation(E, SkipPast::None);
658*06c3fb27SDimitry Andric 
659*06c3fb27SDimitry Andric   if (Loc == nullptr)
660*06c3fb27SDimitry Andric     return nullptr;
661*06c3fb27SDimitry Andric 
662*06c3fb27SDimitry Andric   if (auto *RefVal = dyn_cast_or_null<ReferenceValue>(getValue(*Loc)))
663*06c3fb27SDimitry Andric     return &RefVal->getReferentLoc();
664*06c3fb27SDimitry Andric 
665*06c3fb27SDimitry Andric   return Loc;
666*06c3fb27SDimitry Andric }
667*06c3fb27SDimitry Andric 
668*06c3fb27SDimitry Andric AggregateStorageLocation *Environment::getThisPointeeStorageLocation() const {
669bdd1243dSDimitry Andric   return ThisPointeeLoc;
670bdd1243dSDimitry Andric }
671bdd1243dSDimitry Andric 
672*06c3fb27SDimitry Andric AggregateStorageLocation &
673*06c3fb27SDimitry Andric Environment::getResultObjectLocation(const Expr &RecordPRValue) {
674*06c3fb27SDimitry Andric   assert(RecordPRValue.getType()->isRecordType());
675*06c3fb27SDimitry Andric   assert(RecordPRValue.isPRValue());
676*06c3fb27SDimitry Andric 
677*06c3fb27SDimitry Andric   if (StorageLocation *ExistingLoc =
678*06c3fb27SDimitry Andric           getStorageLocation(RecordPRValue, SkipPast::None))
679*06c3fb27SDimitry Andric     return *cast<AggregateStorageLocation>(ExistingLoc);
680*06c3fb27SDimitry Andric   auto &Loc = cast<AggregateStorageLocation>(
681*06c3fb27SDimitry Andric       DACtx->getStableStorageLocation(RecordPRValue));
682*06c3fb27SDimitry Andric   setStorageLocation(RecordPRValue, Loc);
683*06c3fb27SDimitry Andric   return Loc;
68404eeddc0SDimitry Andric }
68504eeddc0SDimitry Andric 
68681ad6265SDimitry Andric PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) {
68781ad6265SDimitry Andric   return DACtx->getOrCreateNullPointerValue(PointeeType);
68881ad6265SDimitry Andric }
68981ad6265SDimitry Andric 
69004eeddc0SDimitry Andric void Environment::setValue(const StorageLocation &Loc, Value &Val) {
691*06c3fb27SDimitry Andric   assert(!isa<StructValue>(&Val) ||
692*06c3fb27SDimitry Andric          &cast<StructValue>(&Val)->getAggregateLoc() == &Loc);
693*06c3fb27SDimitry Andric 
69404eeddc0SDimitry Andric   LocToVal[&Loc] = &Val;
695*06c3fb27SDimitry Andric }
696*06c3fb27SDimitry Andric 
697*06c3fb27SDimitry Andric void Environment::setValueStrict(const Expr &E, Value &Val) {
698*06c3fb27SDimitry Andric   assert(E.isPRValue());
699*06c3fb27SDimitry Andric   assert(!isa<ReferenceValue>(Val));
70004eeddc0SDimitry Andric 
70104eeddc0SDimitry Andric   if (auto *StructVal = dyn_cast<StructValue>(&Val)) {
702*06c3fb27SDimitry Andric     if (auto *ExistingVal = cast_or_null<StructValue>(getValueStrict(E)))
703*06c3fb27SDimitry Andric       assert(&ExistingVal->getAggregateLoc() == &StructVal->getAggregateLoc());
704*06c3fb27SDimitry Andric     if (StorageLocation *ExistingLoc = getStorageLocation(E, SkipPast::None))
705*06c3fb27SDimitry Andric       assert(ExistingLoc == &StructVal->getAggregateLoc());
706*06c3fb27SDimitry Andric     else
707*06c3fb27SDimitry Andric       setStorageLocation(E, StructVal->getAggregateLoc());
708*06c3fb27SDimitry Andric     setValue(StructVal->getAggregateLoc(), Val);
709*06c3fb27SDimitry Andric     return;
71004eeddc0SDimitry Andric   }
71181ad6265SDimitry Andric 
712*06c3fb27SDimitry Andric   StorageLocation *Loc = getStorageLocation(E, SkipPast::None);
713*06c3fb27SDimitry Andric   if (Loc == nullptr) {
714*06c3fb27SDimitry Andric     Loc = &createStorageLocation(E);
715*06c3fb27SDimitry Andric     setStorageLocation(E, *Loc);
71681ad6265SDimitry Andric   }
717*06c3fb27SDimitry Andric   setValue(*Loc, Val);
71804eeddc0SDimitry Andric }
71904eeddc0SDimitry Andric 
72004eeddc0SDimitry Andric Value *Environment::getValue(const StorageLocation &Loc) const {
721*06c3fb27SDimitry Andric   return LocToVal.lookup(&Loc);
72204eeddc0SDimitry Andric }
72304eeddc0SDimitry Andric 
724*06c3fb27SDimitry Andric Value *Environment::getValue(const ValueDecl &D) const {
725*06c3fb27SDimitry Andric   auto *Loc = getStorageLocation(D);
72604eeddc0SDimitry Andric   if (Loc == nullptr)
72704eeddc0SDimitry Andric     return nullptr;
72804eeddc0SDimitry Andric   return getValue(*Loc);
72904eeddc0SDimitry Andric }
73004eeddc0SDimitry Andric 
73104eeddc0SDimitry Andric Value *Environment::getValue(const Expr &E, SkipPast SP) const {
73204eeddc0SDimitry Andric   auto *Loc = getStorageLocation(E, SP);
73304eeddc0SDimitry Andric   if (Loc == nullptr)
73404eeddc0SDimitry Andric     return nullptr;
73504eeddc0SDimitry Andric   return getValue(*Loc);
73604eeddc0SDimitry Andric }
73704eeddc0SDimitry Andric 
738*06c3fb27SDimitry Andric Value *Environment::getValueStrict(const Expr &E) const {
739*06c3fb27SDimitry Andric   assert(E.isPRValue());
740*06c3fb27SDimitry Andric   Value *Val = getValue(E, SkipPast::None);
741*06c3fb27SDimitry Andric 
742*06c3fb27SDimitry Andric   assert(Val == nullptr || !isa<ReferenceValue>(Val));
743*06c3fb27SDimitry Andric 
744*06c3fb27SDimitry Andric   return Val;
745*06c3fb27SDimitry Andric }
746*06c3fb27SDimitry Andric 
74704eeddc0SDimitry Andric Value *Environment::createValue(QualType Type) {
74804eeddc0SDimitry Andric   llvm::DenseSet<QualType> Visited;
74981ad6265SDimitry Andric   int CreatedValuesCount = 0;
75081ad6265SDimitry Andric   Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0,
75181ad6265SDimitry Andric                                                 CreatedValuesCount);
75281ad6265SDimitry Andric   if (CreatedValuesCount > MaxCompositeValueSize) {
75381ad6265SDimitry Andric     llvm::errs() << "Attempting to initialize a huge value of type: " << Type
75481ad6265SDimitry Andric                  << '\n';
75581ad6265SDimitry Andric   }
75681ad6265SDimitry Andric   return Val;
75704eeddc0SDimitry Andric }
75804eeddc0SDimitry Andric 
75904eeddc0SDimitry Andric Value *Environment::createValueUnlessSelfReferential(
76081ad6265SDimitry Andric     QualType Type, llvm::DenseSet<QualType> &Visited, int Depth,
76181ad6265SDimitry Andric     int &CreatedValuesCount) {
76204eeddc0SDimitry Andric   assert(!Type.isNull());
76304eeddc0SDimitry Andric 
76481ad6265SDimitry Andric   // Allow unlimited fields at depth 1; only cap at deeper nesting levels.
76581ad6265SDimitry Andric   if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) ||
76681ad6265SDimitry Andric       Depth > MaxCompositeValueDepth)
76781ad6265SDimitry Andric     return nullptr;
76881ad6265SDimitry Andric 
76981ad6265SDimitry Andric   if (Type->isBooleanType()) {
77081ad6265SDimitry Andric     CreatedValuesCount++;
77181ad6265SDimitry Andric     return &makeAtomicBoolValue();
77281ad6265SDimitry Andric   }
77381ad6265SDimitry Andric 
77404eeddc0SDimitry Andric   if (Type->isIntegerType()) {
775bdd1243dSDimitry Andric     // FIXME: consider instead `return nullptr`, given that we do nothing useful
776bdd1243dSDimitry Andric     // with integers, and so distinguishing them serves no purpose, but could
777bdd1243dSDimitry Andric     // prevent convergence.
77881ad6265SDimitry Andric     CreatedValuesCount++;
779*06c3fb27SDimitry Andric     return &arena().create<IntegerValue>();
78004eeddc0SDimitry Andric   }
78104eeddc0SDimitry Andric 
782*06c3fb27SDimitry Andric   if (Type->isReferenceType() || Type->isPointerType()) {
78381ad6265SDimitry Andric     CreatedValuesCount++;
784*06c3fb27SDimitry Andric     QualType PointeeType = Type->getPointeeType();
785*06c3fb27SDimitry Andric     StorageLocation &PointeeLoc =
786*06c3fb27SDimitry Andric         createLocAndMaybeValue(PointeeType, Visited, Depth, CreatedValuesCount);
78704eeddc0SDimitry Andric 
788*06c3fb27SDimitry Andric     if (Type->isReferenceType())
789*06c3fb27SDimitry Andric       return &arena().create<ReferenceValue>(PointeeLoc);
790*06c3fb27SDimitry Andric     else
791*06c3fb27SDimitry Andric       return &arena().create<PointerValue>(PointeeLoc);
79204eeddc0SDimitry Andric   }
79304eeddc0SDimitry Andric 
794*06c3fb27SDimitry Andric   if (Type->isRecordType()) {
79581ad6265SDimitry Andric     CreatedValuesCount++;
796*06c3fb27SDimitry Andric     llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
797*06c3fb27SDimitry Andric     for (const FieldDecl *Field : DACtx->getModeledFields(Type)) {
79804eeddc0SDimitry Andric       assert(Field != nullptr);
79904eeddc0SDimitry Andric 
80004eeddc0SDimitry Andric       QualType FieldType = Field->getType();
80104eeddc0SDimitry Andric 
802*06c3fb27SDimitry Andric       FieldLocs.insert(
803*06c3fb27SDimitry Andric           {Field, &createLocAndMaybeValue(FieldType, Visited, Depth + 1,
804*06c3fb27SDimitry Andric                                           CreatedValuesCount)});
80504eeddc0SDimitry Andric     }
80604eeddc0SDimitry Andric 
807*06c3fb27SDimitry Andric     AggregateStorageLocation &Loc =
808*06c3fb27SDimitry Andric         arena().create<AggregateStorageLocation>(Type, std::move(FieldLocs));
809*06c3fb27SDimitry Andric     StructValue &StructVal = create<StructValue>(Loc);
810*06c3fb27SDimitry Andric 
811*06c3fb27SDimitry Andric     // As we already have a storage location for the `StructValue`, we can and
812*06c3fb27SDimitry Andric     // should associate them in the environment.
813*06c3fb27SDimitry Andric     setValue(Loc, StructVal);
814*06c3fb27SDimitry Andric 
815*06c3fb27SDimitry Andric     return &StructVal;
81604eeddc0SDimitry Andric   }
81704eeddc0SDimitry Andric 
81804eeddc0SDimitry Andric   return nullptr;
81904eeddc0SDimitry Andric }
82004eeddc0SDimitry Andric 
821*06c3fb27SDimitry Andric StorageLocation &
822*06c3fb27SDimitry Andric Environment::createLocAndMaybeValue(QualType Ty,
823*06c3fb27SDimitry Andric                                     llvm::DenseSet<QualType> &Visited,
824*06c3fb27SDimitry Andric                                     int Depth, int &CreatedValuesCount) {
825*06c3fb27SDimitry Andric   if (!Visited.insert(Ty.getCanonicalType()).second)
826*06c3fb27SDimitry Andric     return createStorageLocation(Ty.getNonReferenceType());
827*06c3fb27SDimitry Andric   Value *Val = createValueUnlessSelfReferential(
828*06c3fb27SDimitry Andric       Ty.getNonReferenceType(), Visited, Depth, CreatedValuesCount);
829*06c3fb27SDimitry Andric   Visited.erase(Ty.getCanonicalType());
830*06c3fb27SDimitry Andric 
831*06c3fb27SDimitry Andric   Ty = Ty.getNonReferenceType();
832*06c3fb27SDimitry Andric 
833*06c3fb27SDimitry Andric   if (Val == nullptr)
834*06c3fb27SDimitry Andric     return createStorageLocation(Ty);
835*06c3fb27SDimitry Andric 
836*06c3fb27SDimitry Andric   if (Ty->isRecordType())
837*06c3fb27SDimitry Andric     return cast<StructValue>(Val)->getAggregateLoc();
838*06c3fb27SDimitry Andric 
839*06c3fb27SDimitry Andric   StorageLocation &Loc = createStorageLocation(Ty);
840*06c3fb27SDimitry Andric   setValue(Loc, *Val);
841*06c3fb27SDimitry Andric   return Loc;
842*06c3fb27SDimitry Andric }
843*06c3fb27SDimitry Andric 
844*06c3fb27SDimitry Andric StorageLocation &Environment::createObjectInternal(const VarDecl *D,
845*06c3fb27SDimitry Andric                                                    QualType Ty,
846*06c3fb27SDimitry Andric                                                    const Expr *InitExpr) {
847*06c3fb27SDimitry Andric   if (Ty->isReferenceType()) {
848*06c3fb27SDimitry Andric     // Although variables of reference type always need to be initialized, it
849*06c3fb27SDimitry Andric     // can happen that we can't see the initializer, so `InitExpr` may still
850*06c3fb27SDimitry Andric     // be null.
851*06c3fb27SDimitry Andric     if (InitExpr) {
852*06c3fb27SDimitry Andric       if (auto *InitExprLoc =
853*06c3fb27SDimitry Andric               getStorageLocation(*InitExpr, SkipPast::Reference))
854*06c3fb27SDimitry Andric         return *InitExprLoc;
855*06c3fb27SDimitry Andric     }
856*06c3fb27SDimitry Andric 
857*06c3fb27SDimitry Andric     // Even though we have an initializer, we might not get an
858*06c3fb27SDimitry Andric     // InitExprLoc, for example if the InitExpr is a CallExpr for which we
859*06c3fb27SDimitry Andric     // don't have a function body. In this case, we just invent a storage
860*06c3fb27SDimitry Andric     // location and value -- it's the best we can do.
861*06c3fb27SDimitry Andric     return createObjectInternal(D, Ty.getNonReferenceType(), nullptr);
862*06c3fb27SDimitry Andric   }
863*06c3fb27SDimitry Andric 
864*06c3fb27SDimitry Andric   Value *Val = nullptr;
865*06c3fb27SDimitry Andric   if (InitExpr)
866*06c3fb27SDimitry Andric     // In the (few) cases where an expression is intentionally
867*06c3fb27SDimitry Andric     // "uninterpreted", `InitExpr` is not associated with a value.  There are
868*06c3fb27SDimitry Andric     // two ways to handle this situation: propagate the status, so that
869*06c3fb27SDimitry Andric     // uninterpreted initializers result in uninterpreted variables, or
870*06c3fb27SDimitry Andric     // provide a default value. We choose the latter so that later refinements
871*06c3fb27SDimitry Andric     // of the variable can be used for reasoning about the surrounding code.
872*06c3fb27SDimitry Andric     // For this reason, we let this case be handled by the `createValue()`
873*06c3fb27SDimitry Andric     // call below.
874*06c3fb27SDimitry Andric     //
875*06c3fb27SDimitry Andric     // FIXME. If and when we interpret all language cases, change this to
876*06c3fb27SDimitry Andric     // assert that `InitExpr` is interpreted, rather than supplying a
877*06c3fb27SDimitry Andric     // default value (assuming we don't update the environment API to return
878*06c3fb27SDimitry Andric     // references).
879*06c3fb27SDimitry Andric     Val = getValueStrict(*InitExpr);
880*06c3fb27SDimitry Andric   if (!Val)
881*06c3fb27SDimitry Andric     Val = createValue(Ty);
882*06c3fb27SDimitry Andric 
883*06c3fb27SDimitry Andric   if (Ty->isRecordType())
884*06c3fb27SDimitry Andric     return cast<StructValue>(Val)->getAggregateLoc();
885*06c3fb27SDimitry Andric 
886*06c3fb27SDimitry Andric   StorageLocation &Loc =
887*06c3fb27SDimitry Andric       D ? createStorageLocation(*D) : createStorageLocation(Ty);
888*06c3fb27SDimitry Andric 
889*06c3fb27SDimitry Andric   if (Val)
890*06c3fb27SDimitry Andric     setValue(Loc, *Val);
891*06c3fb27SDimitry Andric 
892*06c3fb27SDimitry Andric   return Loc;
893*06c3fb27SDimitry Andric }
894*06c3fb27SDimitry Andric 
89504eeddc0SDimitry Andric StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const {
89604eeddc0SDimitry Andric   switch (SP) {
89704eeddc0SDimitry Andric   case SkipPast::None:
89804eeddc0SDimitry Andric     return Loc;
89904eeddc0SDimitry Andric   case SkipPast::Reference:
90004eeddc0SDimitry Andric     // References cannot be chained so we only need to skip past one level of
90104eeddc0SDimitry Andric     // indirection.
90204eeddc0SDimitry Andric     if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc)))
90381ad6265SDimitry Andric       return Val->getReferentLoc();
90404eeddc0SDimitry Andric     return Loc;
90504eeddc0SDimitry Andric   }
90604eeddc0SDimitry Andric   llvm_unreachable("bad SkipPast kind");
90704eeddc0SDimitry Andric }
90804eeddc0SDimitry Andric 
90904eeddc0SDimitry Andric const StorageLocation &Environment::skip(const StorageLocation &Loc,
91004eeddc0SDimitry Andric                                          SkipPast SP) const {
91104eeddc0SDimitry Andric   return skip(*const_cast<StorageLocation *>(&Loc), SP);
91204eeddc0SDimitry Andric }
91304eeddc0SDimitry Andric 
914*06c3fb27SDimitry Andric void Environment::addToFlowCondition(const Formula &Val) {
915*06c3fb27SDimitry Andric   DACtx->addFlowConditionConstraint(FlowConditionToken, Val);
91681ad6265SDimitry Andric }
91781ad6265SDimitry Andric 
918*06c3fb27SDimitry Andric bool Environment::flowConditionImplies(const Formula &Val) const {
919*06c3fb27SDimitry Andric   return DACtx->flowConditionImplies(FlowConditionToken, Val);
92081ad6265SDimitry Andric }
92181ad6265SDimitry Andric 
922bdd1243dSDimitry Andric void Environment::dump(raw_ostream &OS) const {
923bdd1243dSDimitry Andric   // FIXME: add printing for remaining fields and allow caller to decide what
924bdd1243dSDimitry Andric   // fields are printed.
925bdd1243dSDimitry Andric   OS << "DeclToLoc:\n";
926bdd1243dSDimitry Andric   for (auto [D, L] : DeclToLoc)
927*06c3fb27SDimitry Andric     OS << "  [" << D->getNameAsString() << ", " << L << "]\n";
928bdd1243dSDimitry Andric 
929bdd1243dSDimitry Andric   OS << "ExprToLoc:\n";
930bdd1243dSDimitry Andric   for (auto [E, L] : ExprToLoc)
931bdd1243dSDimitry Andric     OS << "  [" << E << ", " << L << "]\n";
932bdd1243dSDimitry Andric 
933bdd1243dSDimitry Andric   OS << "LocToVal:\n";
934bdd1243dSDimitry Andric   for (auto [L, V] : LocToVal) {
935bdd1243dSDimitry Andric     OS << "  [" << L << ", " << V << ": " << *V << "]\n";
936bdd1243dSDimitry Andric   }
937bdd1243dSDimitry Andric 
938bdd1243dSDimitry Andric   OS << "FlowConditionToken:\n";
939*06c3fb27SDimitry Andric   DACtx->dumpFlowCondition(FlowConditionToken, OS);
940fcaf7f86SDimitry Andric }
941fcaf7f86SDimitry Andric 
942bdd1243dSDimitry Andric void Environment::dump() const {
943bdd1243dSDimitry Andric   dump(llvm::dbgs());
944bdd1243dSDimitry Andric }
945bdd1243dSDimitry Andric 
946*06c3fb27SDimitry Andric AggregateStorageLocation *
947*06c3fb27SDimitry Andric getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
948*06c3fb27SDimitry Andric                           const Environment &Env) {
949*06c3fb27SDimitry Andric   Expr *ImplicitObject = MCE.getImplicitObjectArgument();
950*06c3fb27SDimitry Andric   if (ImplicitObject == nullptr)
951*06c3fb27SDimitry Andric     return nullptr;
952*06c3fb27SDimitry Andric   StorageLocation *Loc =
953*06c3fb27SDimitry Andric       Env.getStorageLocation(*ImplicitObject, SkipPast::Reference);
954*06c3fb27SDimitry Andric   if (Loc == nullptr)
955*06c3fb27SDimitry Andric     return nullptr;
956*06c3fb27SDimitry Andric   if (ImplicitObject->getType()->isPointerType()) {
957*06c3fb27SDimitry Andric     if (auto *Val = cast_or_null<PointerValue>(Env.getValue(*Loc)))
958*06c3fb27SDimitry Andric       return &cast<AggregateStorageLocation>(Val->getPointeeLoc());
959*06c3fb27SDimitry Andric     return nullptr;
960*06c3fb27SDimitry Andric   }
961*06c3fb27SDimitry Andric   return cast<AggregateStorageLocation>(Loc);
962*06c3fb27SDimitry Andric }
963*06c3fb27SDimitry Andric 
964*06c3fb27SDimitry Andric AggregateStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
965*06c3fb27SDimitry Andric                                                 const Environment &Env) {
966*06c3fb27SDimitry Andric   Expr *Base = ME.getBase();
967*06c3fb27SDimitry Andric   if (Base == nullptr)
968*06c3fb27SDimitry Andric     return nullptr;
969*06c3fb27SDimitry Andric   StorageLocation *Loc = Env.getStorageLocation(*Base, SkipPast::Reference);
970*06c3fb27SDimitry Andric   if (Loc == nullptr)
971*06c3fb27SDimitry Andric     return nullptr;
972*06c3fb27SDimitry Andric   if (ME.isArrow()) {
973*06c3fb27SDimitry Andric     if (auto *Val = cast_or_null<PointerValue>(Env.getValue(*Loc)))
974*06c3fb27SDimitry Andric       return &cast<AggregateStorageLocation>(Val->getPointeeLoc());
975*06c3fb27SDimitry Andric     return nullptr;
976*06c3fb27SDimitry Andric   }
977*06c3fb27SDimitry Andric   return cast<AggregateStorageLocation>(Loc);
978*06c3fb27SDimitry Andric }
979*06c3fb27SDimitry Andric 
980*06c3fb27SDimitry Andric std::vector<FieldDecl *> getFieldsForInitListExpr(const RecordDecl *RD) {
981*06c3fb27SDimitry Andric   // Unnamed bitfields are only used for padding and do not appear in
982*06c3fb27SDimitry Andric   // `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s
983*06c3fb27SDimitry Andric   // field list, and we thus need to remove them before mapping inits to
984*06c3fb27SDimitry Andric   // fields to avoid mapping inits to the wrongs fields.
985*06c3fb27SDimitry Andric   std::vector<FieldDecl *> Fields;
986*06c3fb27SDimitry Andric   llvm::copy_if(
987*06c3fb27SDimitry Andric       RD->fields(), std::back_inserter(Fields),
988*06c3fb27SDimitry Andric       [](const FieldDecl *Field) { return !Field->isUnnamedBitfield(); });
989*06c3fb27SDimitry Andric   return Fields;
990*06c3fb27SDimitry Andric }
991*06c3fb27SDimitry Andric 
992*06c3fb27SDimitry Andric StructValue &refreshStructValue(AggregateStorageLocation &Loc,
993*06c3fb27SDimitry Andric                                 Environment &Env) {
994*06c3fb27SDimitry Andric   auto &NewVal = Env.create<StructValue>(Loc);
995*06c3fb27SDimitry Andric   Env.setValue(Loc, NewVal);
996*06c3fb27SDimitry Andric   return NewVal;
997*06c3fb27SDimitry Andric }
998*06c3fb27SDimitry Andric 
999*06c3fb27SDimitry Andric StructValue &refreshStructValue(const Expr &Expr, Environment &Env) {
1000*06c3fb27SDimitry Andric   assert(Expr.getType()->isRecordType());
1001*06c3fb27SDimitry Andric 
1002*06c3fb27SDimitry Andric   if (Expr.isPRValue()) {
1003*06c3fb27SDimitry Andric     if (auto *ExistingVal =
1004*06c3fb27SDimitry Andric             cast_or_null<StructValue>(Env.getValueStrict(Expr))) {
1005*06c3fb27SDimitry Andric       auto &NewVal = Env.create<StructValue>(ExistingVal->getAggregateLoc());
1006*06c3fb27SDimitry Andric       Env.setValueStrict(Expr, NewVal);
1007*06c3fb27SDimitry Andric       return NewVal;
1008*06c3fb27SDimitry Andric     }
1009*06c3fb27SDimitry Andric 
1010*06c3fb27SDimitry Andric     auto &NewVal = *cast<StructValue>(Env.createValue(Expr.getType()));
1011*06c3fb27SDimitry Andric     Env.setValueStrict(Expr, NewVal);
1012*06c3fb27SDimitry Andric     return NewVal;
1013*06c3fb27SDimitry Andric   }
1014*06c3fb27SDimitry Andric 
1015*06c3fb27SDimitry Andric   if (auto *Loc = cast_or_null<AggregateStorageLocation>(
1016*06c3fb27SDimitry Andric           Env.getStorageLocationStrict(Expr))) {
1017*06c3fb27SDimitry Andric     auto &NewVal = Env.create<StructValue>(*Loc);
1018*06c3fb27SDimitry Andric     Env.setValue(*Loc, NewVal);
1019*06c3fb27SDimitry Andric     return NewVal;
1020*06c3fb27SDimitry Andric   }
1021*06c3fb27SDimitry Andric 
1022*06c3fb27SDimitry Andric   auto &NewVal = *cast<StructValue>(Env.createValue(Expr.getType()));
1023*06c3fb27SDimitry Andric   Env.setStorageLocationStrict(Expr, NewVal.getAggregateLoc());
1024*06c3fb27SDimitry Andric   return NewVal;
1025*06c3fb27SDimitry Andric }
1026*06c3fb27SDimitry Andric 
102704eeddc0SDimitry Andric } // namespace dataflow
102804eeddc0SDimitry Andric } // namespace clang
1029