xref: /freebsd-src/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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*bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h"
2481ad6265SDimitry Andric #include "llvm/Support/Casting.h"
2504eeddc0SDimitry Andric #include "llvm/Support/ErrorHandling.h"
2681ad6265SDimitry Andric #include <cassert>
2704eeddc0SDimitry Andric #include <memory>
2804eeddc0SDimitry Andric #include <utility>
2904eeddc0SDimitry Andric 
3004eeddc0SDimitry Andric namespace clang {
3104eeddc0SDimitry Andric namespace dataflow {
3204eeddc0SDimitry Andric 
3381ad6265SDimitry Andric // FIXME: convert these to parameters of the analysis or environment. Current
3481ad6265SDimitry Andric // settings have been experimentaly validated, but only for a particular
3581ad6265SDimitry Andric // analysis.
3681ad6265SDimitry Andric static constexpr int MaxCompositeValueDepth = 3;
3781ad6265SDimitry Andric static constexpr int MaxCompositeValueSize = 1000;
3881ad6265SDimitry Andric 
3904eeddc0SDimitry Andric /// Returns a map consisting of key-value entries that are present in both maps.
4004eeddc0SDimitry Andric template <typename K, typename V>
4104eeddc0SDimitry Andric llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1,
4204eeddc0SDimitry Andric                                         const llvm::DenseMap<K, V> &Map2) {
4304eeddc0SDimitry Andric   llvm::DenseMap<K, V> Result;
4404eeddc0SDimitry Andric   for (auto &Entry : Map1) {
4504eeddc0SDimitry Andric     auto It = Map2.find(Entry.first);
4604eeddc0SDimitry Andric     if (It != Map2.end() && Entry.second == It->second)
4704eeddc0SDimitry Andric       Result.insert({Entry.first, Entry.second});
4804eeddc0SDimitry Andric   }
4904eeddc0SDimitry Andric   return Result;
5004eeddc0SDimitry Andric }
5104eeddc0SDimitry Andric 
52*bdd1243dSDimitry Andric static bool compareDistinctValues(QualType Type, Value &Val1,
53*bdd1243dSDimitry Andric                                   const Environment &Env1, Value &Val2,
5481ad6265SDimitry Andric                                   const Environment &Env2,
5581ad6265SDimitry Andric                                   Environment::ValueModel &Model) {
56*bdd1243dSDimitry Andric   // Note: Potentially costly, but, for booleans, we could check whether both
57*bdd1243dSDimitry Andric   // can be proven equivalent in their respective environments.
58*bdd1243dSDimitry Andric 
59*bdd1243dSDimitry Andric   // FIXME: move the reference/pointers logic from `areEquivalentValues` to here
60*bdd1243dSDimitry Andric   // and implement separate, join/widen specific handling for
61*bdd1243dSDimitry Andric   // reference/pointers.
62*bdd1243dSDimitry Andric   switch (Model.compare(Type, Val1, Env1, Val2, Env2)) {
63*bdd1243dSDimitry Andric   case ComparisonResult::Same:
64*bdd1243dSDimitry Andric     return true;
65*bdd1243dSDimitry Andric   case ComparisonResult::Different:
66*bdd1243dSDimitry Andric     return false;
67*bdd1243dSDimitry Andric   case ComparisonResult::Unknown:
68*bdd1243dSDimitry Andric     switch (Val1.getKind()) {
69*bdd1243dSDimitry Andric     case Value::Kind::Integer:
70*bdd1243dSDimitry Andric     case Value::Kind::Reference:
71*bdd1243dSDimitry Andric     case Value::Kind::Pointer:
72*bdd1243dSDimitry Andric     case Value::Kind::Struct:
73*bdd1243dSDimitry Andric       // FIXME: this choice intentionally introduces unsoundness to allow
74*bdd1243dSDimitry Andric       // for convergence. Once we have widening support for the
75*bdd1243dSDimitry Andric       // reference/pointer and struct built-in models, this should be
76*bdd1243dSDimitry Andric       // `false`.
77*bdd1243dSDimitry Andric       return true;
78*bdd1243dSDimitry Andric     default:
79*bdd1243dSDimitry Andric       return false;
80*bdd1243dSDimitry Andric     }
81*bdd1243dSDimitry Andric   }
82*bdd1243dSDimitry Andric   llvm_unreachable("All cases covered in switch");
8381ad6265SDimitry Andric }
8481ad6265SDimitry Andric 
8581ad6265SDimitry Andric /// Attempts to merge distinct values `Val1` and `Val2` in `Env1` and `Env2`,
8681ad6265SDimitry Andric /// respectively, of the same type `Type`. Merging generally produces a single
8781ad6265SDimitry Andric /// value that (soundly) approximates the two inputs, although the actual
8881ad6265SDimitry Andric /// meaning depends on `Model`.
89*bdd1243dSDimitry Andric static Value *mergeDistinctValues(QualType Type, Value &Val1,
90*bdd1243dSDimitry Andric                                   const Environment &Env1, Value &Val2,
9181ad6265SDimitry Andric                                   const Environment &Env2,
9281ad6265SDimitry Andric                                   Environment &MergedEnv,
9381ad6265SDimitry Andric                                   Environment::ValueModel &Model) {
9481ad6265SDimitry Andric   // Join distinct boolean values preserving information about the constraints
9581ad6265SDimitry Andric   // in the respective path conditions.
96*bdd1243dSDimitry Andric   if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) {
97*bdd1243dSDimitry Andric     // FIXME: Checking both values should be unnecessary, since they should have
98*bdd1243dSDimitry Andric     // a consistent shape.  However, right now we can end up with BoolValue's in
99*bdd1243dSDimitry Andric     // integer-typed variables due to our incorrect handling of
100*bdd1243dSDimitry Andric     // boolean-to-integer casts (we just propagate the BoolValue to the result
101*bdd1243dSDimitry Andric     // of the cast). So, a join can encounter an integer in one branch but a
102*bdd1243dSDimitry Andric     // bool in the other.
103*bdd1243dSDimitry Andric     // For example:
104*bdd1243dSDimitry Andric     // ```
105*bdd1243dSDimitry Andric     // std::optional<bool> o;
106*bdd1243dSDimitry Andric     // int x;
107*bdd1243dSDimitry Andric     // if (o.has_value())
108*bdd1243dSDimitry Andric     //   x = o.value();
109*bdd1243dSDimitry Andric     // ```
110*bdd1243dSDimitry Andric     auto *Expr1 = cast<BoolValue>(&Val1);
111*bdd1243dSDimitry Andric     auto *Expr2 = cast<BoolValue>(&Val2);
11281ad6265SDimitry Andric     auto &MergedVal = MergedEnv.makeAtomicBoolValue();
11381ad6265SDimitry Andric     MergedEnv.addToFlowCondition(MergedEnv.makeOr(
11481ad6265SDimitry Andric         MergedEnv.makeAnd(Env1.getFlowConditionToken(),
11581ad6265SDimitry Andric                           MergedEnv.makeIff(MergedVal, *Expr1)),
11681ad6265SDimitry Andric         MergedEnv.makeAnd(Env2.getFlowConditionToken(),
11781ad6265SDimitry Andric                           MergedEnv.makeIff(MergedVal, *Expr2))));
11881ad6265SDimitry Andric     return &MergedVal;
11981ad6265SDimitry Andric   }
12081ad6265SDimitry Andric 
12181ad6265SDimitry Andric   // FIXME: Consider destroying `MergedValue` immediately if `ValueModel::merge`
12281ad6265SDimitry Andric   // returns false to avoid storing unneeded values in `DACtx`.
123*bdd1243dSDimitry Andric   // FIXME: Creating the value based on the type alone creates misshapen values
124*bdd1243dSDimitry Andric   // for lvalues, since the type does not reflect the need for `ReferenceValue`.
12581ad6265SDimitry Andric   if (Value *MergedVal = MergedEnv.createValue(Type))
126*bdd1243dSDimitry Andric     if (Model.merge(Type, Val1, Env1, Val2, Env2, *MergedVal, MergedEnv))
12781ad6265SDimitry Andric       return MergedVal;
12881ad6265SDimitry Andric 
12981ad6265SDimitry Andric   return nullptr;
13081ad6265SDimitry Andric }
13181ad6265SDimitry Andric 
132*bdd1243dSDimitry Andric // When widening does not change `Current`, return value will equal `&Prev`.
133*bdd1243dSDimitry Andric static Value &widenDistinctValues(QualType Type, Value &Prev,
134*bdd1243dSDimitry Andric                                   const Environment &PrevEnv, Value &Current,
135*bdd1243dSDimitry Andric                                   Environment &CurrentEnv,
136*bdd1243dSDimitry Andric                                   Environment::ValueModel &Model) {
137*bdd1243dSDimitry Andric   // Boolean-model widening.
138*bdd1243dSDimitry Andric   if (isa<BoolValue>(&Prev)) {
139*bdd1243dSDimitry Andric     assert(isa<BoolValue>(Current));
140*bdd1243dSDimitry Andric     // Widen to Top, because we know they are different values. If previous was
141*bdd1243dSDimitry Andric     // already Top, re-use that to (implicitly) indicate that no change occured.
142*bdd1243dSDimitry Andric     if (isa<TopBoolValue>(Prev))
143*bdd1243dSDimitry Andric       return Prev;
144*bdd1243dSDimitry Andric     return CurrentEnv.makeTopBoolValue();
145*bdd1243dSDimitry Andric   }
14681ad6265SDimitry Andric 
147*bdd1243dSDimitry Andric   // FIXME: Add other built-in model widening.
148*bdd1243dSDimitry Andric 
149*bdd1243dSDimitry Andric   // Custom-model widening.
150*bdd1243dSDimitry Andric   if (auto *W = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv))
151*bdd1243dSDimitry Andric     return *W;
152*bdd1243dSDimitry Andric 
153*bdd1243dSDimitry Andric   // Default of widening is a no-op: leave the current value unchanged.
154*bdd1243dSDimitry Andric   return Current;
15581ad6265SDimitry Andric }
15681ad6265SDimitry Andric 
15781ad6265SDimitry Andric /// Initializes a global storage value.
158*bdd1243dSDimitry Andric static void insertIfGlobal(const Decl &D,
159*bdd1243dSDimitry Andric                            llvm::DenseSet<const FieldDecl *> &Fields,
160*bdd1243dSDimitry Andric                            llvm::DenseSet<const VarDecl *> &Vars) {
16181ad6265SDimitry Andric   if (auto *V = dyn_cast<VarDecl>(&D))
162*bdd1243dSDimitry Andric     if (V->hasGlobalStorage())
163*bdd1243dSDimitry Andric       Vars.insert(V);
16481ad6265SDimitry Andric }
16581ad6265SDimitry Andric 
166*bdd1243dSDimitry Andric static void getFieldsAndGlobalVars(const Decl &D,
167*bdd1243dSDimitry Andric                                    llvm::DenseSet<const FieldDecl *> &Fields,
168*bdd1243dSDimitry Andric                                    llvm::DenseSet<const VarDecl *> &Vars) {
169*bdd1243dSDimitry Andric   insertIfGlobal(D, Fields, Vars);
170*bdd1243dSDimitry Andric   if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D))
171*bdd1243dSDimitry Andric     for (const auto *B : Decomp->bindings())
172*bdd1243dSDimitry Andric       if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding()))
173*bdd1243dSDimitry Andric         // FIXME: should we be using `E->getFoundDecl()`?
174*bdd1243dSDimitry Andric         if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
175*bdd1243dSDimitry Andric           Fields.insert(FD);
17681ad6265SDimitry Andric }
17781ad6265SDimitry Andric 
178*bdd1243dSDimitry Andric /// Traverses `S` and inserts into `Vars` any global storage values that are
179*bdd1243dSDimitry Andric /// declared in or referenced from sub-statements.
180*bdd1243dSDimitry Andric static void getFieldsAndGlobalVars(const Stmt &S,
181*bdd1243dSDimitry Andric                                    llvm::DenseSet<const FieldDecl *> &Fields,
182*bdd1243dSDimitry Andric                                    llvm::DenseSet<const VarDecl *> &Vars) {
183*bdd1243dSDimitry Andric   for (auto *Child : S.children())
184*bdd1243dSDimitry Andric     if (Child != nullptr)
185*bdd1243dSDimitry Andric       getFieldsAndGlobalVars(*Child, Fields, Vars);
186*bdd1243dSDimitry Andric 
18781ad6265SDimitry Andric   if (auto *DS = dyn_cast<DeclStmt>(&S)) {
188*bdd1243dSDimitry Andric     if (DS->isSingleDecl())
189*bdd1243dSDimitry Andric       getFieldsAndGlobalVars(*DS->getSingleDecl(), Fields, Vars);
190*bdd1243dSDimitry Andric     else
19181ad6265SDimitry Andric       for (auto *D : DS->getDeclGroup())
192*bdd1243dSDimitry Andric           getFieldsAndGlobalVars(*D, Fields, Vars);
19381ad6265SDimitry Andric   } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) {
194*bdd1243dSDimitry Andric     insertIfGlobal(*E->getDecl(), Fields, Vars);
19581ad6265SDimitry Andric   } else if (auto *E = dyn_cast<MemberExpr>(&S)) {
196*bdd1243dSDimitry Andric     // FIXME: should we be using `E->getFoundDecl()`?
197*bdd1243dSDimitry Andric     const ValueDecl *VD = E->getMemberDecl();
198*bdd1243dSDimitry Andric     insertIfGlobal(*VD, Fields, Vars);
199*bdd1243dSDimitry Andric     if (const auto *FD = dyn_cast<FieldDecl>(VD))
200*bdd1243dSDimitry Andric       Fields.insert(FD);
201*bdd1243dSDimitry Andric   }
202*bdd1243dSDimitry Andric }
203*bdd1243dSDimitry Andric 
204*bdd1243dSDimitry Andric // FIXME: Add support for resetting globals after function calls to enable
205*bdd1243dSDimitry Andric // the implementation of sound analyses.
206*bdd1243dSDimitry Andric void Environment::initVars(llvm::DenseSet<const VarDecl *> Vars) {
207*bdd1243dSDimitry Andric   for (const VarDecl *D : Vars) {
208*bdd1243dSDimitry Andric     if (getStorageLocation(*D, SkipPast::None) != nullptr)
209*bdd1243dSDimitry Andric       continue;
210*bdd1243dSDimitry Andric     auto &Loc = createStorageLocation(*D);
211*bdd1243dSDimitry Andric     setStorageLocation(*D, Loc);
212*bdd1243dSDimitry Andric     if (auto *Val = createValue(D->getType()))
213*bdd1243dSDimitry Andric       setValue(Loc, *Val);
21481ad6265SDimitry Andric   }
21581ad6265SDimitry Andric }
21681ad6265SDimitry Andric 
21781ad6265SDimitry Andric Environment::Environment(DataflowAnalysisContext &DACtx)
21881ad6265SDimitry Andric     : DACtx(&DACtx), FlowConditionToken(&DACtx.makeFlowConditionToken()) {}
21981ad6265SDimitry Andric 
22081ad6265SDimitry Andric Environment::Environment(const Environment &Other)
221*bdd1243dSDimitry Andric     : DACtx(Other.DACtx), CallStack(Other.CallStack),
222*bdd1243dSDimitry Andric       ReturnLoc(Other.ReturnLoc), ThisPointeeLoc(Other.ThisPointeeLoc),
223*bdd1243dSDimitry Andric       DeclToLoc(Other.DeclToLoc), ExprToLoc(Other.ExprToLoc),
224*bdd1243dSDimitry Andric       LocToVal(Other.LocToVal), MemberLocToStruct(Other.MemberLocToStruct),
22581ad6265SDimitry Andric       FlowConditionToken(&DACtx->forkFlowCondition(*Other.FlowConditionToken)) {
22681ad6265SDimitry Andric }
22781ad6265SDimitry Andric 
22881ad6265SDimitry Andric Environment &Environment::operator=(const Environment &Other) {
22981ad6265SDimitry Andric   Environment Copy(Other);
23081ad6265SDimitry Andric   *this = std::move(Copy);
23181ad6265SDimitry Andric   return *this;
2321fd87a68SDimitry Andric }
2331fd87a68SDimitry Andric 
23404eeddc0SDimitry Andric Environment::Environment(DataflowAnalysisContext &DACtx,
23504eeddc0SDimitry Andric                          const DeclContext &DeclCtx)
23604eeddc0SDimitry Andric     : Environment(DACtx) {
237*bdd1243dSDimitry Andric   CallStack.push_back(&DeclCtx);
238*bdd1243dSDimitry Andric 
23904eeddc0SDimitry Andric   if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) {
24081ad6265SDimitry Andric     assert(FuncDecl->getBody() != nullptr);
241*bdd1243dSDimitry Andric 
242*bdd1243dSDimitry Andric     llvm::DenseSet<const FieldDecl *> Fields;
243*bdd1243dSDimitry Andric     llvm::DenseSet<const VarDecl *> Vars;
244*bdd1243dSDimitry Andric 
245*bdd1243dSDimitry Andric     // Look for global variable references in the constructor-initializers.
246*bdd1243dSDimitry Andric     if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(&DeclCtx)) {
247*bdd1243dSDimitry Andric       for (const auto *Init : CtorDecl->inits()) {
248*bdd1243dSDimitry Andric         if (const auto *M = Init->getAnyMember())
249*bdd1243dSDimitry Andric           Fields.insert(M);
250*bdd1243dSDimitry Andric         const Expr *E = Init->getInit();
251*bdd1243dSDimitry Andric         assert(E != nullptr);
252*bdd1243dSDimitry Andric         getFieldsAndGlobalVars(*E, Fields, Vars);
253*bdd1243dSDimitry Andric       }
254*bdd1243dSDimitry Andric     }
255*bdd1243dSDimitry Andric     getFieldsAndGlobalVars(*FuncDecl->getBody(), Fields, Vars);
256*bdd1243dSDimitry Andric 
257*bdd1243dSDimitry Andric     // These have to be added before the lines that follow to ensure that
258*bdd1243dSDimitry Andric     // `create*` work correctly for structs.
259*bdd1243dSDimitry Andric     DACtx.addModeledFields(Fields);
260*bdd1243dSDimitry Andric 
261*bdd1243dSDimitry Andric     initVars(Vars);
262*bdd1243dSDimitry Andric 
26304eeddc0SDimitry Andric     for (const auto *ParamDecl : FuncDecl->parameters()) {
26404eeddc0SDimitry Andric       assert(ParamDecl != nullptr);
26504eeddc0SDimitry Andric       auto &ParamLoc = createStorageLocation(*ParamDecl);
26604eeddc0SDimitry Andric       setStorageLocation(*ParamDecl, ParamLoc);
26704eeddc0SDimitry Andric       if (Value *ParamVal = createValue(ParamDecl->getType()))
26804eeddc0SDimitry Andric         setValue(ParamLoc, *ParamVal);
26904eeddc0SDimitry Andric     }
270*bdd1243dSDimitry Andric 
271*bdd1243dSDimitry Andric     QualType ReturnType = FuncDecl->getReturnType();
272*bdd1243dSDimitry Andric     ReturnLoc = &createStorageLocation(ReturnType);
27304eeddc0SDimitry Andric   }
27404eeddc0SDimitry Andric 
27504eeddc0SDimitry Andric   if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) {
27681ad6265SDimitry Andric     auto *Parent = MethodDecl->getParent();
27781ad6265SDimitry Andric     assert(Parent != nullptr);
27881ad6265SDimitry Andric     if (Parent->isLambda())
27981ad6265SDimitry Andric       MethodDecl = dyn_cast<CXXMethodDecl>(Parent->getDeclContext());
28081ad6265SDimitry Andric 
281*bdd1243dSDimitry Andric     // FIXME: Initialize the ThisPointeeLoc of lambdas too.
28281ad6265SDimitry Andric     if (MethodDecl && !MethodDecl->isStatic()) {
28304eeddc0SDimitry Andric       QualType ThisPointeeType = MethodDecl->getThisObjectType();
284*bdd1243dSDimitry Andric       ThisPointeeLoc = &createStorageLocation(ThisPointeeType);
28504eeddc0SDimitry Andric       if (Value *ThisPointeeVal = createValue(ThisPointeeType))
286*bdd1243dSDimitry Andric         setValue(*ThisPointeeLoc, *ThisPointeeVal);
28704eeddc0SDimitry Andric     }
28804eeddc0SDimitry Andric   }
28904eeddc0SDimitry Andric }
290*bdd1243dSDimitry Andric 
291*bdd1243dSDimitry Andric bool Environment::canDescend(unsigned MaxDepth,
292*bdd1243dSDimitry Andric                              const DeclContext *Callee) const {
293*bdd1243dSDimitry Andric   return CallStack.size() <= MaxDepth && !llvm::is_contained(CallStack, Callee);
29404eeddc0SDimitry Andric }
29504eeddc0SDimitry Andric 
296972a253aSDimitry Andric Environment Environment::pushCall(const CallExpr *Call) const {
297972a253aSDimitry Andric   Environment Env(*this);
298972a253aSDimitry Andric 
299*bdd1243dSDimitry Andric   // FIXME: Support references here.
300*bdd1243dSDimitry Andric   Env.ReturnLoc = getStorageLocation(*Call, SkipPast::Reference);
301972a253aSDimitry Andric 
302*bdd1243dSDimitry Andric   if (const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(Call)) {
303*bdd1243dSDimitry Andric     if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
304*bdd1243dSDimitry Andric       if (!isa<CXXThisExpr>(Arg))
305*bdd1243dSDimitry Andric         Env.ThisPointeeLoc = getStorageLocation(*Arg, SkipPast::Reference);
306*bdd1243dSDimitry Andric       // Otherwise (when the argument is `this`), retain the current
307*bdd1243dSDimitry Andric       // environment's `ThisPointeeLoc`.
308*bdd1243dSDimitry Andric     }
309*bdd1243dSDimitry Andric   }
310972a253aSDimitry Andric 
311*bdd1243dSDimitry Andric   Env.pushCallInternal(Call->getDirectCallee(),
312*bdd1243dSDimitry Andric                        llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));
313*bdd1243dSDimitry Andric 
314*bdd1243dSDimitry Andric   return Env;
315*bdd1243dSDimitry Andric }
316*bdd1243dSDimitry Andric 
317*bdd1243dSDimitry Andric Environment Environment::pushCall(const CXXConstructExpr *Call) const {
318*bdd1243dSDimitry Andric   Environment Env(*this);
319*bdd1243dSDimitry Andric 
320*bdd1243dSDimitry Andric   // FIXME: Support references here.
321*bdd1243dSDimitry Andric   Env.ReturnLoc = getStorageLocation(*Call, SkipPast::Reference);
322*bdd1243dSDimitry Andric 
323*bdd1243dSDimitry Andric   Env.ThisPointeeLoc = Env.ReturnLoc;
324*bdd1243dSDimitry Andric 
325*bdd1243dSDimitry Andric   Env.pushCallInternal(Call->getConstructor(),
326*bdd1243dSDimitry Andric                        llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));
327*bdd1243dSDimitry Andric 
328*bdd1243dSDimitry Andric   return Env;
329*bdd1243dSDimitry Andric }
330*bdd1243dSDimitry Andric 
331*bdd1243dSDimitry Andric void Environment::pushCallInternal(const FunctionDecl *FuncDecl,
332*bdd1243dSDimitry Andric                                    ArrayRef<const Expr *> Args) {
333*bdd1243dSDimitry Andric   CallStack.push_back(FuncDecl);
334*bdd1243dSDimitry Andric 
335*bdd1243dSDimitry Andric   // FIXME: Share this code with the constructor, rather than duplicating it.
336*bdd1243dSDimitry Andric   llvm::DenseSet<const FieldDecl *> Fields;
337*bdd1243dSDimitry Andric   llvm::DenseSet<const VarDecl *> Vars;
338*bdd1243dSDimitry Andric   // Look for global variable references in the constructor-initializers.
339*bdd1243dSDimitry Andric   if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FuncDecl)) {
340*bdd1243dSDimitry Andric     for (const auto *Init : CtorDecl->inits()) {
341*bdd1243dSDimitry Andric       if (const auto *M = Init->getAnyMember())
342*bdd1243dSDimitry Andric         Fields.insert(M);
343*bdd1243dSDimitry Andric       const Expr *E = Init->getInit();
344*bdd1243dSDimitry Andric       assert(E != nullptr);
345*bdd1243dSDimitry Andric       getFieldsAndGlobalVars(*E, Fields, Vars);
346*bdd1243dSDimitry Andric     }
347*bdd1243dSDimitry Andric   }
348*bdd1243dSDimitry Andric   getFieldsAndGlobalVars(*FuncDecl->getBody(), Fields, Vars);
349*bdd1243dSDimitry Andric 
350*bdd1243dSDimitry Andric   // These have to be added before the lines that follow to ensure that
351*bdd1243dSDimitry Andric   // `create*` work correctly for structs.
352*bdd1243dSDimitry Andric   DACtx->addModeledFields(Fields);
353*bdd1243dSDimitry Andric 
354*bdd1243dSDimitry Andric   initVars(Vars);
355*bdd1243dSDimitry Andric 
356*bdd1243dSDimitry Andric   const auto *ParamIt = FuncDecl->param_begin();
357972a253aSDimitry Andric 
358972a253aSDimitry Andric   // FIXME: Parameters don't always map to arguments 1:1; examples include
359972a253aSDimitry Andric   // overloaded operators implemented as member functions, and parameter packs.
360*bdd1243dSDimitry Andric   for (unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) {
361972a253aSDimitry Andric     assert(ParamIt != FuncDecl->param_end());
362972a253aSDimitry Andric 
363*bdd1243dSDimitry Andric     const Expr *Arg = Args[ArgIndex];
364*bdd1243dSDimitry Andric     auto *ArgLoc = getStorageLocation(*Arg, SkipPast::Reference);
365*bdd1243dSDimitry Andric     if (ArgLoc == nullptr)
366*bdd1243dSDimitry Andric       continue;
367*bdd1243dSDimitry Andric 
368972a253aSDimitry Andric     const VarDecl *Param = *ParamIt;
369*bdd1243dSDimitry Andric     auto &Loc = createStorageLocation(*Param);
370*bdd1243dSDimitry Andric     setStorageLocation(*Param, Loc);
371*bdd1243dSDimitry Andric 
372*bdd1243dSDimitry Andric     QualType ParamType = Param->getType();
373*bdd1243dSDimitry Andric     if (ParamType->isReferenceType()) {
374*bdd1243dSDimitry Andric       auto &Val = takeOwnership(std::make_unique<ReferenceValue>(*ArgLoc));
375*bdd1243dSDimitry Andric       setValue(Loc, Val);
376*bdd1243dSDimitry Andric     } else if (auto *ArgVal = getValue(*ArgLoc)) {
377*bdd1243dSDimitry Andric       setValue(Loc, *ArgVal);
378*bdd1243dSDimitry Andric     } else if (Value *Val = createValue(ParamType)) {
379*bdd1243dSDimitry Andric       setValue(Loc, *Val);
380*bdd1243dSDimitry Andric     }
381*bdd1243dSDimitry Andric   }
382972a253aSDimitry Andric }
383972a253aSDimitry Andric 
384*bdd1243dSDimitry Andric void Environment::popCall(const Environment &CalleeEnv) {
385*bdd1243dSDimitry Andric   // We ignore `DACtx` because it's already the same in both. We don't want the
386*bdd1243dSDimitry Andric   // callee's `DeclCtx`, `ReturnLoc` or `ThisPointeeLoc`. We don't bring back
387*bdd1243dSDimitry Andric   // `DeclToLoc` and `ExprToLoc` because we want to be able to later analyze the
388*bdd1243dSDimitry Andric   // same callee in a different context, and `setStorageLocation` requires there
389*bdd1243dSDimitry Andric   // to not already be a storage location assigned. Conceptually, these maps
390*bdd1243dSDimitry Andric   // capture information from the local scope, so when popping that scope, we do
391*bdd1243dSDimitry Andric   // not propagate the maps.
392*bdd1243dSDimitry Andric   this->LocToVal = std::move(CalleeEnv.LocToVal);
393*bdd1243dSDimitry Andric   this->MemberLocToStruct = std::move(CalleeEnv.MemberLocToStruct);
394*bdd1243dSDimitry Andric   this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
395972a253aSDimitry Andric }
396972a253aSDimitry Andric 
3971fd87a68SDimitry Andric bool Environment::equivalentTo(const Environment &Other,
3981fd87a68SDimitry Andric                                Environment::ValueModel &Model) const {
39904eeddc0SDimitry Andric   assert(DACtx == Other.DACtx);
4001fd87a68SDimitry Andric 
401*bdd1243dSDimitry Andric   if (ReturnLoc != Other.ReturnLoc)
402*bdd1243dSDimitry Andric     return false;
403*bdd1243dSDimitry Andric 
404*bdd1243dSDimitry Andric   if (ThisPointeeLoc != Other.ThisPointeeLoc)
405*bdd1243dSDimitry Andric     return false;
406*bdd1243dSDimitry Andric 
4071fd87a68SDimitry Andric   if (DeclToLoc != Other.DeclToLoc)
4081fd87a68SDimitry Andric     return false;
4091fd87a68SDimitry Andric 
4101fd87a68SDimitry Andric   if (ExprToLoc != Other.ExprToLoc)
4111fd87a68SDimitry Andric     return false;
4121fd87a68SDimitry Andric 
41381ad6265SDimitry Andric   // Compare the contents for the intersection of their domains.
4141fd87a68SDimitry Andric   for (auto &Entry : LocToVal) {
4151fd87a68SDimitry Andric     const StorageLocation *Loc = Entry.first;
4161fd87a68SDimitry Andric     assert(Loc != nullptr);
4171fd87a68SDimitry Andric 
4181fd87a68SDimitry Andric     Value *Val = Entry.second;
4191fd87a68SDimitry Andric     assert(Val != nullptr);
4201fd87a68SDimitry Andric 
4211fd87a68SDimitry Andric     auto It = Other.LocToVal.find(Loc);
4221fd87a68SDimitry Andric     if (It == Other.LocToVal.end())
42381ad6265SDimitry Andric       continue;
4241fd87a68SDimitry Andric     assert(It->second != nullptr);
4251fd87a68SDimitry Andric 
426*bdd1243dSDimitry Andric     if (!areEquivalentValues(*Val, *It->second) &&
427*bdd1243dSDimitry Andric         !compareDistinctValues(Loc->getType(), *Val, *this, *It->second, Other,
428*bdd1243dSDimitry Andric                                Model))
4291fd87a68SDimitry Andric       return false;
4301fd87a68SDimitry Andric   }
4311fd87a68SDimitry Andric 
4321fd87a68SDimitry Andric   return true;
43304eeddc0SDimitry Andric }
43404eeddc0SDimitry Andric 
435*bdd1243dSDimitry Andric LatticeJoinEffect Environment::widen(const Environment &PrevEnv,
436*bdd1243dSDimitry Andric                                      Environment::ValueModel &Model) {
437*bdd1243dSDimitry Andric   assert(DACtx == PrevEnv.DACtx);
438*bdd1243dSDimitry Andric   assert(ReturnLoc == PrevEnv.ReturnLoc);
439*bdd1243dSDimitry Andric   assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc);
440*bdd1243dSDimitry Andric   assert(CallStack == PrevEnv.CallStack);
441*bdd1243dSDimitry Andric 
442*bdd1243dSDimitry Andric   auto Effect = LatticeJoinEffect::Unchanged;
443*bdd1243dSDimitry Andric 
444*bdd1243dSDimitry Andric   // By the API, `PrevEnv` is a previous version of the environment for the same
445*bdd1243dSDimitry Andric   // block, so we have some guarantees about its shape. In particular, it will
446*bdd1243dSDimitry Andric   // be the result of a join or widen operation on previous values for this
447*bdd1243dSDimitry Andric   // block. For `DeclToLoc` and `ExprToLoc`, join guarantees that these maps are
448*bdd1243dSDimitry Andric   // subsets of the maps in `PrevEnv`. So, as long as we maintain this property
449*bdd1243dSDimitry Andric   // here, we don't need change their current values to widen.
450*bdd1243dSDimitry Andric   //
451*bdd1243dSDimitry Andric   // FIXME: `MemberLocToStruct` does not share the above property, because
452*bdd1243dSDimitry Andric   // `join` can cause the map size to increase (when we add fresh data in places
453*bdd1243dSDimitry Andric   // of conflict). Once this issue with join is resolved, re-enable the
454*bdd1243dSDimitry Andric   // assertion below or replace with something that captures the desired
455*bdd1243dSDimitry Andric   // invariant.
456*bdd1243dSDimitry Andric   assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size());
457*bdd1243dSDimitry Andric   assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size());
458*bdd1243dSDimitry Andric   // assert(MemberLocToStruct.size() <= PrevEnv.MemberLocToStruct.size());
459*bdd1243dSDimitry Andric 
460*bdd1243dSDimitry Andric   llvm::DenseMap<const StorageLocation *, Value *> WidenedLocToVal;
461*bdd1243dSDimitry Andric   for (auto &Entry : LocToVal) {
462*bdd1243dSDimitry Andric     const StorageLocation *Loc = Entry.first;
463*bdd1243dSDimitry Andric     assert(Loc != nullptr);
464*bdd1243dSDimitry Andric 
465*bdd1243dSDimitry Andric     Value *Val = Entry.second;
466*bdd1243dSDimitry Andric     assert(Val != nullptr);
467*bdd1243dSDimitry Andric 
468*bdd1243dSDimitry Andric     auto PrevIt = PrevEnv.LocToVal.find(Loc);
469*bdd1243dSDimitry Andric     if (PrevIt == PrevEnv.LocToVal.end())
470*bdd1243dSDimitry Andric       continue;
471*bdd1243dSDimitry Andric     assert(PrevIt->second != nullptr);
472*bdd1243dSDimitry Andric 
473*bdd1243dSDimitry Andric     if (areEquivalentValues(*Val, *PrevIt->second)) {
474*bdd1243dSDimitry Andric       WidenedLocToVal.insert({Loc, Val});
475*bdd1243dSDimitry Andric       continue;
476*bdd1243dSDimitry Andric     }
477*bdd1243dSDimitry Andric 
478*bdd1243dSDimitry Andric     Value &WidenedVal = widenDistinctValues(Loc->getType(), *PrevIt->second,
479*bdd1243dSDimitry Andric                                             PrevEnv, *Val, *this, Model);
480*bdd1243dSDimitry Andric     WidenedLocToVal.insert({Loc, &WidenedVal});
481*bdd1243dSDimitry Andric     if (&WidenedVal != PrevIt->second)
482*bdd1243dSDimitry Andric       Effect = LatticeJoinEffect::Changed;
483*bdd1243dSDimitry Andric   }
484*bdd1243dSDimitry Andric   LocToVal = std::move(WidenedLocToVal);
485*bdd1243dSDimitry Andric   // FIXME: update the equivalence calculation for `MemberLocToStruct`, once we
486*bdd1243dSDimitry Andric   // have a systematic way of soundly comparing this map.
487*bdd1243dSDimitry Andric   if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() ||
488*bdd1243dSDimitry Andric       ExprToLoc.size() != PrevEnv.ExprToLoc.size() ||
489*bdd1243dSDimitry Andric       LocToVal.size() != PrevEnv.LocToVal.size() ||
490*bdd1243dSDimitry Andric       MemberLocToStruct.size() != PrevEnv.MemberLocToStruct.size())
491*bdd1243dSDimitry Andric     Effect = LatticeJoinEffect::Changed;
492*bdd1243dSDimitry Andric 
493*bdd1243dSDimitry Andric   return Effect;
494*bdd1243dSDimitry Andric }
495*bdd1243dSDimitry Andric 
49604eeddc0SDimitry Andric LatticeJoinEffect Environment::join(const Environment &Other,
4971fd87a68SDimitry Andric                                     Environment::ValueModel &Model) {
49804eeddc0SDimitry Andric   assert(DACtx == Other.DACtx);
499*bdd1243dSDimitry Andric   assert(ReturnLoc == Other.ReturnLoc);
500*bdd1243dSDimitry Andric   assert(ThisPointeeLoc == Other.ThisPointeeLoc);
501*bdd1243dSDimitry Andric   assert(CallStack == Other.CallStack);
50204eeddc0SDimitry Andric 
50304eeddc0SDimitry Andric   auto Effect = LatticeJoinEffect::Unchanged;
50404eeddc0SDimitry Andric 
50581ad6265SDimitry Andric   Environment JoinedEnv(*DACtx);
50681ad6265SDimitry Andric 
507*bdd1243dSDimitry Andric   JoinedEnv.CallStack = CallStack;
508*bdd1243dSDimitry Andric   JoinedEnv.ReturnLoc = ReturnLoc;
509*bdd1243dSDimitry Andric   JoinedEnv.ThisPointeeLoc = ThisPointeeLoc;
510*bdd1243dSDimitry Andric 
51181ad6265SDimitry Andric   JoinedEnv.DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc);
51281ad6265SDimitry Andric   if (DeclToLoc.size() != JoinedEnv.DeclToLoc.size())
51304eeddc0SDimitry Andric     Effect = LatticeJoinEffect::Changed;
51404eeddc0SDimitry Andric 
51581ad6265SDimitry Andric   JoinedEnv.ExprToLoc = intersectDenseMaps(ExprToLoc, Other.ExprToLoc);
51681ad6265SDimitry Andric   if (ExprToLoc.size() != JoinedEnv.ExprToLoc.size())
51704eeddc0SDimitry Andric     Effect = LatticeJoinEffect::Changed;
51804eeddc0SDimitry Andric 
51981ad6265SDimitry Andric   JoinedEnv.MemberLocToStruct =
52081ad6265SDimitry Andric       intersectDenseMaps(MemberLocToStruct, Other.MemberLocToStruct);
52181ad6265SDimitry Andric   if (MemberLocToStruct.size() != JoinedEnv.MemberLocToStruct.size())
52281ad6265SDimitry Andric     Effect = LatticeJoinEffect::Changed;
52381ad6265SDimitry Andric 
52481ad6265SDimitry Andric   // FIXME: set `Effect` as needed.
525*bdd1243dSDimitry Andric   // FIXME: update join to detect backedges and simplify the flow condition
526*bdd1243dSDimitry Andric   // accordingly.
52781ad6265SDimitry Andric   JoinedEnv.FlowConditionToken = &DACtx->joinFlowConditions(
52881ad6265SDimitry Andric       *FlowConditionToken, *Other.FlowConditionToken);
52981ad6265SDimitry Andric 
53081ad6265SDimitry Andric   for (auto &Entry : LocToVal) {
53104eeddc0SDimitry Andric     const StorageLocation *Loc = Entry.first;
53204eeddc0SDimitry Andric     assert(Loc != nullptr);
53304eeddc0SDimitry Andric 
53404eeddc0SDimitry Andric     Value *Val = Entry.second;
53504eeddc0SDimitry Andric     assert(Val != nullptr);
53604eeddc0SDimitry Andric 
53704eeddc0SDimitry Andric     auto It = Other.LocToVal.find(Loc);
53804eeddc0SDimitry Andric     if (It == Other.LocToVal.end())
53904eeddc0SDimitry Andric       continue;
54004eeddc0SDimitry Andric     assert(It->second != nullptr);
54104eeddc0SDimitry Andric 
542*bdd1243dSDimitry Andric     if (areEquivalentValues(*Val, *It->second)) {
54381ad6265SDimitry Andric       JoinedEnv.LocToVal.insert({Loc, Val});
54404eeddc0SDimitry Andric       continue;
54504eeddc0SDimitry Andric     }
54604eeddc0SDimitry Andric 
547*bdd1243dSDimitry Andric     if (Value *MergedVal =
548*bdd1243dSDimitry Andric             mergeDistinctValues(Loc->getType(), *Val, *this, *It->second, Other,
549*bdd1243dSDimitry Andric                                 JoinedEnv, Model)) {
55081ad6265SDimitry Andric       JoinedEnv.LocToVal.insert({Loc, MergedVal});
551*bdd1243dSDimitry Andric       Effect = LatticeJoinEffect::Changed;
552*bdd1243dSDimitry Andric     }
55304eeddc0SDimitry Andric   }
55481ad6265SDimitry Andric   if (LocToVal.size() != JoinedEnv.LocToVal.size())
55504eeddc0SDimitry Andric     Effect = LatticeJoinEffect::Changed;
55604eeddc0SDimitry Andric 
55781ad6265SDimitry Andric   *this = std::move(JoinedEnv);
55881ad6265SDimitry Andric 
55904eeddc0SDimitry Andric   return Effect;
56004eeddc0SDimitry Andric }
56104eeddc0SDimitry Andric 
56204eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(QualType Type) {
563*bdd1243dSDimitry Andric   return DACtx->createStorageLocation(Type);
56404eeddc0SDimitry Andric }
56504eeddc0SDimitry Andric 
56604eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const VarDecl &D) {
56704eeddc0SDimitry Andric   // Evaluated declarations are always assigned the same storage locations to
56804eeddc0SDimitry Andric   // ensure that the environment stabilizes across loop iterations. Storage
56904eeddc0SDimitry Andric   // locations for evaluated declarations are stored in the analysis context.
57081ad6265SDimitry Andric   return DACtx->getStableStorageLocation(D);
57104eeddc0SDimitry Andric }
57204eeddc0SDimitry Andric 
57304eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const Expr &E) {
57404eeddc0SDimitry Andric   // Evaluated expressions are always assigned the same storage locations to
57504eeddc0SDimitry Andric   // ensure that the environment stabilizes across loop iterations. Storage
57604eeddc0SDimitry Andric   // locations for evaluated expressions are stored in the analysis context.
57781ad6265SDimitry Andric   return DACtx->getStableStorageLocation(E);
57804eeddc0SDimitry Andric }
57904eeddc0SDimitry Andric 
58004eeddc0SDimitry Andric void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
58104eeddc0SDimitry Andric   assert(DeclToLoc.find(&D) == DeclToLoc.end());
58204eeddc0SDimitry Andric   DeclToLoc[&D] = &Loc;
58304eeddc0SDimitry Andric }
58404eeddc0SDimitry Andric 
58504eeddc0SDimitry Andric StorageLocation *Environment::getStorageLocation(const ValueDecl &D,
58604eeddc0SDimitry Andric                                                  SkipPast SP) const {
58704eeddc0SDimitry Andric   auto It = DeclToLoc.find(&D);
58804eeddc0SDimitry Andric   return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP);
58904eeddc0SDimitry Andric }
59004eeddc0SDimitry Andric 
59104eeddc0SDimitry Andric void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
59281ad6265SDimitry Andric   const Expr &CanonE = ignoreCFGOmittedNodes(E);
59381ad6265SDimitry Andric   assert(ExprToLoc.find(&CanonE) == ExprToLoc.end());
59481ad6265SDimitry Andric   ExprToLoc[&CanonE] = &Loc;
59504eeddc0SDimitry Andric }
59604eeddc0SDimitry Andric 
59704eeddc0SDimitry Andric StorageLocation *Environment::getStorageLocation(const Expr &E,
59804eeddc0SDimitry Andric                                                  SkipPast SP) const {
59981ad6265SDimitry Andric   // FIXME: Add a test with parens.
60081ad6265SDimitry Andric   auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));
60104eeddc0SDimitry Andric   return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP);
60204eeddc0SDimitry Andric }
60304eeddc0SDimitry Andric 
60404eeddc0SDimitry Andric StorageLocation *Environment::getThisPointeeStorageLocation() const {
605*bdd1243dSDimitry Andric   return ThisPointeeLoc;
606*bdd1243dSDimitry Andric }
607*bdd1243dSDimitry Andric 
608*bdd1243dSDimitry Andric StorageLocation *Environment::getReturnStorageLocation() const {
609*bdd1243dSDimitry Andric   return ReturnLoc;
61004eeddc0SDimitry Andric }
61104eeddc0SDimitry Andric 
61281ad6265SDimitry Andric PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) {
61381ad6265SDimitry Andric   return DACtx->getOrCreateNullPointerValue(PointeeType);
61481ad6265SDimitry Andric }
61581ad6265SDimitry Andric 
61604eeddc0SDimitry Andric void Environment::setValue(const StorageLocation &Loc, Value &Val) {
61704eeddc0SDimitry Andric   LocToVal[&Loc] = &Val;
61804eeddc0SDimitry Andric 
61904eeddc0SDimitry Andric   if (auto *StructVal = dyn_cast<StructValue>(&Val)) {
62004eeddc0SDimitry Andric     auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc);
62104eeddc0SDimitry Andric 
62204eeddc0SDimitry Andric     const QualType Type = AggregateLoc.getType();
623*bdd1243dSDimitry Andric     assert(Type->isStructureOrClassType() || Type->isUnionType());
62404eeddc0SDimitry Andric 
625*bdd1243dSDimitry Andric     for (const FieldDecl *Field : DACtx->getReferencedFields(Type)) {
62604eeddc0SDimitry Andric       assert(Field != nullptr);
62781ad6265SDimitry Andric       StorageLocation &FieldLoc = AggregateLoc.getChild(*Field);
62881ad6265SDimitry Andric       MemberLocToStruct[&FieldLoc] = std::make_pair(StructVal, Field);
62981ad6265SDimitry Andric       if (auto *FieldVal = StructVal->getChild(*Field))
63081ad6265SDimitry Andric         setValue(FieldLoc, *FieldVal);
63104eeddc0SDimitry Andric     }
63204eeddc0SDimitry Andric   }
63381ad6265SDimitry Andric 
634972a253aSDimitry Andric   auto It = MemberLocToStruct.find(&Loc);
635972a253aSDimitry Andric   if (It != MemberLocToStruct.end()) {
63681ad6265SDimitry Andric     // `Loc` is the location of a struct member so we need to also update the
63781ad6265SDimitry Andric     // value of the member in the corresponding `StructValue`.
63881ad6265SDimitry Andric 
639972a253aSDimitry Andric     assert(It->second.first != nullptr);
640972a253aSDimitry Andric     StructValue &StructVal = *It->second.first;
64181ad6265SDimitry Andric 
642972a253aSDimitry Andric     assert(It->second.second != nullptr);
643972a253aSDimitry Andric     const ValueDecl &Member = *It->second.second;
64481ad6265SDimitry Andric 
64581ad6265SDimitry Andric     StructVal.setChild(Member, Val);
64681ad6265SDimitry Andric   }
64704eeddc0SDimitry Andric }
64804eeddc0SDimitry Andric 
64904eeddc0SDimitry Andric Value *Environment::getValue(const StorageLocation &Loc) const {
65004eeddc0SDimitry Andric   auto It = LocToVal.find(&Loc);
65104eeddc0SDimitry Andric   return It == LocToVal.end() ? nullptr : It->second;
65204eeddc0SDimitry Andric }
65304eeddc0SDimitry Andric 
65404eeddc0SDimitry Andric Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const {
65504eeddc0SDimitry Andric   auto *Loc = getStorageLocation(D, SP);
65604eeddc0SDimitry Andric   if (Loc == nullptr)
65704eeddc0SDimitry Andric     return nullptr;
65804eeddc0SDimitry Andric   return getValue(*Loc);
65904eeddc0SDimitry Andric }
66004eeddc0SDimitry Andric 
66104eeddc0SDimitry Andric Value *Environment::getValue(const Expr &E, SkipPast SP) const {
66204eeddc0SDimitry Andric   auto *Loc = getStorageLocation(E, SP);
66304eeddc0SDimitry Andric   if (Loc == nullptr)
66404eeddc0SDimitry Andric     return nullptr;
66504eeddc0SDimitry Andric   return getValue(*Loc);
66604eeddc0SDimitry Andric }
66704eeddc0SDimitry Andric 
66804eeddc0SDimitry Andric Value *Environment::createValue(QualType Type) {
66904eeddc0SDimitry Andric   llvm::DenseSet<QualType> Visited;
67081ad6265SDimitry Andric   int CreatedValuesCount = 0;
67181ad6265SDimitry Andric   Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0,
67281ad6265SDimitry Andric                                                 CreatedValuesCount);
67381ad6265SDimitry Andric   if (CreatedValuesCount > MaxCompositeValueSize) {
67481ad6265SDimitry Andric     llvm::errs() << "Attempting to initialize a huge value of type: " << Type
67581ad6265SDimitry Andric                  << '\n';
67681ad6265SDimitry Andric   }
67781ad6265SDimitry Andric   return Val;
67804eeddc0SDimitry Andric }
67904eeddc0SDimitry Andric 
68004eeddc0SDimitry Andric Value *Environment::createValueUnlessSelfReferential(
68181ad6265SDimitry Andric     QualType Type, llvm::DenseSet<QualType> &Visited, int Depth,
68281ad6265SDimitry Andric     int &CreatedValuesCount) {
68304eeddc0SDimitry Andric   assert(!Type.isNull());
68404eeddc0SDimitry Andric 
68581ad6265SDimitry Andric   // Allow unlimited fields at depth 1; only cap at deeper nesting levels.
68681ad6265SDimitry Andric   if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) ||
68781ad6265SDimitry Andric       Depth > MaxCompositeValueDepth)
68881ad6265SDimitry Andric     return nullptr;
68981ad6265SDimitry Andric 
69081ad6265SDimitry Andric   if (Type->isBooleanType()) {
69181ad6265SDimitry Andric     CreatedValuesCount++;
69281ad6265SDimitry Andric     return &makeAtomicBoolValue();
69381ad6265SDimitry Andric   }
69481ad6265SDimitry Andric 
69504eeddc0SDimitry Andric   if (Type->isIntegerType()) {
696*bdd1243dSDimitry Andric     // FIXME: consider instead `return nullptr`, given that we do nothing useful
697*bdd1243dSDimitry Andric     // with integers, and so distinguishing them serves no purpose, but could
698*bdd1243dSDimitry Andric     // prevent convergence.
69981ad6265SDimitry Andric     CreatedValuesCount++;
70004eeddc0SDimitry Andric     return &takeOwnership(std::make_unique<IntegerValue>());
70104eeddc0SDimitry Andric   }
70204eeddc0SDimitry Andric 
70304eeddc0SDimitry Andric   if (Type->isReferenceType()) {
70481ad6265SDimitry Andric     CreatedValuesCount++;
70581ad6265SDimitry Andric     QualType PointeeType = Type->castAs<ReferenceType>()->getPointeeType();
70604eeddc0SDimitry Andric     auto &PointeeLoc = createStorageLocation(PointeeType);
70704eeddc0SDimitry Andric 
70881ad6265SDimitry Andric     if (Visited.insert(PointeeType.getCanonicalType()).second) {
70981ad6265SDimitry Andric       Value *PointeeVal = createValueUnlessSelfReferential(
71081ad6265SDimitry Andric           PointeeType, Visited, Depth, CreatedValuesCount);
71104eeddc0SDimitry Andric       Visited.erase(PointeeType.getCanonicalType());
71204eeddc0SDimitry Andric 
71304eeddc0SDimitry Andric       if (PointeeVal != nullptr)
71404eeddc0SDimitry Andric         setValue(PointeeLoc, *PointeeVal);
71504eeddc0SDimitry Andric     }
71604eeddc0SDimitry Andric 
71704eeddc0SDimitry Andric     return &takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc));
71804eeddc0SDimitry Andric   }
71904eeddc0SDimitry Andric 
72004eeddc0SDimitry Andric   if (Type->isPointerType()) {
72181ad6265SDimitry Andric     CreatedValuesCount++;
72281ad6265SDimitry Andric     QualType PointeeType = Type->castAs<PointerType>()->getPointeeType();
72304eeddc0SDimitry Andric     auto &PointeeLoc = createStorageLocation(PointeeType);
72404eeddc0SDimitry Andric 
72581ad6265SDimitry Andric     if (Visited.insert(PointeeType.getCanonicalType()).second) {
72681ad6265SDimitry Andric       Value *PointeeVal = createValueUnlessSelfReferential(
72781ad6265SDimitry Andric           PointeeType, Visited, Depth, CreatedValuesCount);
72804eeddc0SDimitry Andric       Visited.erase(PointeeType.getCanonicalType());
72904eeddc0SDimitry Andric 
73004eeddc0SDimitry Andric       if (PointeeVal != nullptr)
73104eeddc0SDimitry Andric         setValue(PointeeLoc, *PointeeVal);
73204eeddc0SDimitry Andric     }
73304eeddc0SDimitry Andric 
73404eeddc0SDimitry Andric     return &takeOwnership(std::make_unique<PointerValue>(PointeeLoc));
73504eeddc0SDimitry Andric   }
73604eeddc0SDimitry Andric 
737*bdd1243dSDimitry Andric   if (Type->isStructureOrClassType() || Type->isUnionType()) {
73881ad6265SDimitry Andric     CreatedValuesCount++;
73904eeddc0SDimitry Andric     llvm::DenseMap<const ValueDecl *, Value *> FieldValues;
740*bdd1243dSDimitry Andric     for (const FieldDecl *Field : DACtx->getReferencedFields(Type)) {
74104eeddc0SDimitry Andric       assert(Field != nullptr);
74204eeddc0SDimitry Andric 
74304eeddc0SDimitry Andric       QualType FieldType = Field->getType();
74404eeddc0SDimitry Andric       if (Visited.contains(FieldType.getCanonicalType()))
74504eeddc0SDimitry Andric         continue;
74604eeddc0SDimitry Andric 
74704eeddc0SDimitry Andric       Visited.insert(FieldType.getCanonicalType());
74881ad6265SDimitry Andric       if (auto *FieldValue = createValueUnlessSelfReferential(
74981ad6265SDimitry Andric               FieldType, Visited, Depth + 1, CreatedValuesCount))
75081ad6265SDimitry Andric         FieldValues.insert({Field, FieldValue});
75104eeddc0SDimitry Andric       Visited.erase(FieldType.getCanonicalType());
75204eeddc0SDimitry Andric     }
75304eeddc0SDimitry Andric 
75404eeddc0SDimitry Andric     return &takeOwnership(
75504eeddc0SDimitry Andric         std::make_unique<StructValue>(std::move(FieldValues)));
75604eeddc0SDimitry Andric   }
75704eeddc0SDimitry Andric 
75804eeddc0SDimitry Andric   return nullptr;
75904eeddc0SDimitry Andric }
76004eeddc0SDimitry Andric 
76104eeddc0SDimitry Andric StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const {
76204eeddc0SDimitry Andric   switch (SP) {
76304eeddc0SDimitry Andric   case SkipPast::None:
76404eeddc0SDimitry Andric     return Loc;
76504eeddc0SDimitry Andric   case SkipPast::Reference:
76604eeddc0SDimitry Andric     // References cannot be chained so we only need to skip past one level of
76704eeddc0SDimitry Andric     // indirection.
76804eeddc0SDimitry Andric     if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc)))
76981ad6265SDimitry Andric       return Val->getReferentLoc();
77004eeddc0SDimitry Andric     return Loc;
77104eeddc0SDimitry Andric   case SkipPast::ReferenceThenPointer:
77204eeddc0SDimitry Andric     StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference);
77304eeddc0SDimitry Andric     if (auto *Val = dyn_cast_or_null<PointerValue>(getValue(LocPastRef)))
77404eeddc0SDimitry Andric       return Val->getPointeeLoc();
77504eeddc0SDimitry Andric     return LocPastRef;
77604eeddc0SDimitry Andric   }
77704eeddc0SDimitry Andric   llvm_unreachable("bad SkipPast kind");
77804eeddc0SDimitry Andric }
77904eeddc0SDimitry Andric 
78004eeddc0SDimitry Andric const StorageLocation &Environment::skip(const StorageLocation &Loc,
78104eeddc0SDimitry Andric                                          SkipPast SP) const {
78204eeddc0SDimitry Andric   return skip(*const_cast<StorageLocation *>(&Loc), SP);
78304eeddc0SDimitry Andric }
78404eeddc0SDimitry Andric 
78581ad6265SDimitry Andric void Environment::addToFlowCondition(BoolValue &Val) {
78681ad6265SDimitry Andric   DACtx->addFlowConditionConstraint(*FlowConditionToken, Val);
78781ad6265SDimitry Andric }
78881ad6265SDimitry Andric 
78981ad6265SDimitry Andric bool Environment::flowConditionImplies(BoolValue &Val) const {
79081ad6265SDimitry Andric   return DACtx->flowConditionImplies(*FlowConditionToken, Val);
79181ad6265SDimitry Andric }
79281ad6265SDimitry Andric 
793*bdd1243dSDimitry Andric void Environment::dump(raw_ostream &OS) const {
794*bdd1243dSDimitry Andric   // FIXME: add printing for remaining fields and allow caller to decide what
795*bdd1243dSDimitry Andric   // fields are printed.
796*bdd1243dSDimitry Andric   OS << "DeclToLoc:\n";
797*bdd1243dSDimitry Andric   for (auto [D, L] : DeclToLoc)
798*bdd1243dSDimitry Andric     OS << "  [" << D->getName() << ", " << L << "]\n";
799*bdd1243dSDimitry Andric 
800*bdd1243dSDimitry Andric   OS << "ExprToLoc:\n";
801*bdd1243dSDimitry Andric   for (auto [E, L] : ExprToLoc)
802*bdd1243dSDimitry Andric     OS << "  [" << E << ", " << L << "]\n";
803*bdd1243dSDimitry Andric 
804*bdd1243dSDimitry Andric   OS << "LocToVal:\n";
805*bdd1243dSDimitry Andric   for (auto [L, V] : LocToVal) {
806*bdd1243dSDimitry Andric     OS << "  [" << L << ", " << V << ": " << *V << "]\n";
807*bdd1243dSDimitry Andric   }
808*bdd1243dSDimitry Andric 
809*bdd1243dSDimitry Andric   OS << "FlowConditionToken:\n";
810fcaf7f86SDimitry Andric   DACtx->dumpFlowCondition(*FlowConditionToken);
811fcaf7f86SDimitry Andric }
812fcaf7f86SDimitry Andric 
813*bdd1243dSDimitry Andric void Environment::dump() const {
814*bdd1243dSDimitry Andric   dump(llvm::dbgs());
815*bdd1243dSDimitry Andric }
816*bdd1243dSDimitry Andric 
81704eeddc0SDimitry Andric } // namespace dataflow
81804eeddc0SDimitry Andric } // namespace clang
819