xref: /llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (revision 745a957f9dc562477cbe587fb3fa8305713b51b3)
1 //===-- DataflowEnvironment.cpp ---------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //  This file defines an Environment class that is used by dataflow analyses
10 //  that run over Control-Flow Graphs (CFGs) to keep track of the state of the
11 //  program at given program points.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
16 #include "clang/AST/Decl.h"
17 #include "clang/AST/DeclCXX.h"
18 #include "clang/AST/Type.h"
19 #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
20 #include "clang/Analysis/FlowSensitive/Value.h"
21 #include "llvm/ADT/DenseMap.h"
22 #include "llvm/ADT/DenseSet.h"
23 #include "llvm/ADT/STLExtras.h"
24 #include "llvm/Support/Casting.h"
25 #include "llvm/Support/ErrorHandling.h"
26 #include <cassert>
27 #include <memory>
28 #include <utility>
29 
30 namespace clang {
31 namespace dataflow {
32 
33 // FIXME: convert these to parameters of the analysis or environment. Current
34 // settings have been experimentaly validated, but only for a particular
35 // analysis.
36 static constexpr int MaxCompositeValueDepth = 3;
37 static constexpr int MaxCompositeValueSize = 1000;
38 
39 /// Returns a map consisting of key-value entries that are present in both maps.
40 template <typename K, typename V>
41 llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1,
42                                         const llvm::DenseMap<K, V> &Map2) {
43   llvm::DenseMap<K, V> Result;
44   for (auto &Entry : Map1) {
45     auto It = Map2.find(Entry.first);
46     if (It != Map2.end() && Entry.second == It->second)
47       Result.insert({Entry.first, Entry.second});
48   }
49   return Result;
50 }
51 
52 static bool compareDistinctValues(QualType Type, Value &Val1,
53                                   const Environment &Env1, Value &Val2,
54                                   const Environment &Env2,
55                                   Environment::ValueModel &Model) {
56   // Note: Potentially costly, but, for booleans, we could check whether both
57   // can be proven equivalent in their respective environments.
58 
59   // FIXME: move the reference/pointers logic from `areEquivalentValues` to here
60   // and implement separate, join/widen specific handling for
61   // reference/pointers.
62   switch (Model.compare(Type, Val1, Env1, Val2, Env2)) {
63   case ComparisonResult::Same:
64     return true;
65   case ComparisonResult::Different:
66     return false;
67   case ComparisonResult::Unknown:
68     switch (Val1.getKind()) {
69     case Value::Kind::Integer:
70     case Value::Kind::Reference:
71     case Value::Kind::Pointer:
72     case Value::Kind::Struct:
73       // FIXME: this choice intentionally introduces unsoundness to allow
74       // for convergence. Once we have widening support for the
75       // reference/pointer and struct built-in models, this should be
76       // `false`.
77       return true;
78     default:
79       return false;
80     }
81   }
82   llvm_unreachable("All cases covered in switch");
83 }
84 
85 /// Attempts to merge distinct values `Val1` and `Val2` in `Env1` and `Env2`,
86 /// respectively, of the same type `Type`. Merging generally produces a single
87 /// value that (soundly) approximates the two inputs, although the actual
88 /// meaning depends on `Model`.
89 static Value *mergeDistinctValues(QualType Type, Value &Val1,
90                                   const Environment &Env1, Value &Val2,
91                                   const Environment &Env2,
92                                   Environment &MergedEnv,
93                                   Environment::ValueModel &Model) {
94   // Join distinct boolean values preserving information about the constraints
95   // in the respective path conditions.
96   if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) {
97     // FIXME: Checking both values should be unnecessary, since they should have
98     // a consistent shape.  However, right now we can end up with BoolValue's in
99     // integer-typed variables due to our incorrect handling of
100     // boolean-to-integer casts (we just propagate the BoolValue to the result
101     // of the cast). So, a join can encounter an integer in one branch but a
102     // bool in the other.
103     // For example:
104     // ```
105     // std::optional<bool> o;
106     // int x;
107     // if (o.has_value())
108     //   x = o.value();
109     // ```
110     auto *Expr1 = cast<BoolValue>(&Val1);
111     auto *Expr2 = cast<BoolValue>(&Val2);
112     auto &MergedVal = MergedEnv.makeAtomicBoolValue();
113     MergedEnv.addToFlowCondition(MergedEnv.makeOr(
114         MergedEnv.makeAnd(Env1.getFlowConditionToken(),
115                           MergedEnv.makeIff(MergedVal, *Expr1)),
116         MergedEnv.makeAnd(Env2.getFlowConditionToken(),
117                           MergedEnv.makeIff(MergedVal, *Expr2))));
118     return &MergedVal;
119   }
120 
121   // FIXME: Consider destroying `MergedValue` immediately if `ValueModel::merge`
122   // returns false to avoid storing unneeded values in `DACtx`.
123   // FIXME: Creating the value based on the type alone creates misshapen values
124   // for lvalues, since the type does not reflect the need for `ReferenceValue`.
125   if (Value *MergedVal = MergedEnv.createValue(Type))
126     if (Model.merge(Type, Val1, Env1, Val2, Env2, *MergedVal, MergedEnv))
127       return MergedVal;
128 
129   return nullptr;
130 }
131 
132 // When widening does not change `Current`, return value will equal `&Prev`.
133 static Value &widenDistinctValues(QualType Type, Value &Prev,
134                                   const Environment &PrevEnv, Value &Current,
135                                   Environment &CurrentEnv,
136                                   Environment::ValueModel &Model) {
137   // Boolean-model widening.
138   if (isa<BoolValue>(&Prev)) {
139     assert(isa<BoolValue>(Current));
140     // Widen to Top, because we know they are different values. If previous was
141     // already Top, re-use that to (implicitly) indicate that no change occured.
142     if (isa<TopBoolValue>(Prev))
143       return Prev;
144     return CurrentEnv.makeTopBoolValue();
145   }
146 
147   // FIXME: Add other built-in model widening.
148 
149   // Custom-model widening.
150   if (auto *W = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv))
151     return *W;
152 
153   // Default of widening is a no-op: leave the current value unchanged.
154   return Current;
155 }
156 
157 /// Initializes a global storage value.
158 static void insertIfGlobal(const Decl &D,
159                            llvm::DenseSet<const FieldDecl *> &Fields,
160                            llvm::DenseSet<const VarDecl *> &Vars) {
161   if (auto *V = dyn_cast<VarDecl>(&D))
162     if (V->hasGlobalStorage())
163       Vars.insert(V);
164 }
165 
166 static void getFieldsAndGlobalVars(const Decl &D,
167                                    llvm::DenseSet<const FieldDecl *> &Fields,
168                                    llvm::DenseSet<const VarDecl *> &Vars) {
169   insertIfGlobal(D, Fields, Vars);
170   if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D))
171     for (const auto *B : Decomp->bindings())
172       if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding()))
173         // FIXME: should we be using `E->getFoundDecl()`?
174         if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
175           Fields.insert(FD);
176 }
177 
178 /// Traverses `S` and inserts into `Vars` any global storage values that are
179 /// declared in or referenced from sub-statements.
180 static void getFieldsAndGlobalVars(const Stmt &S,
181                                    llvm::DenseSet<const FieldDecl *> &Fields,
182                                    llvm::DenseSet<const VarDecl *> &Vars) {
183   for (auto *Child : S.children())
184     if (Child != nullptr)
185       getFieldsAndGlobalVars(*Child, Fields, Vars);
186 
187   if (auto *DS = dyn_cast<DeclStmt>(&S)) {
188     if (DS->isSingleDecl())
189       getFieldsAndGlobalVars(*DS->getSingleDecl(), Fields, Vars);
190     else
191       for (auto *D : DS->getDeclGroup())
192           getFieldsAndGlobalVars(*D, Fields, Vars);
193   } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) {
194     insertIfGlobal(*E->getDecl(), Fields, Vars);
195   } else if (auto *E = dyn_cast<MemberExpr>(&S)) {
196     // FIXME: should we be using `E->getFoundDecl()`?
197     const ValueDecl *VD = E->getMemberDecl();
198     insertIfGlobal(*VD, Fields, Vars);
199     if (const auto *FD = dyn_cast<FieldDecl>(VD))
200       Fields.insert(FD);
201   }
202 }
203 
204 // FIXME: Add support for resetting globals after function calls to enable
205 // the implementation of sound analyses.
206 void Environment::initFieldsAndGlobals(const FunctionDecl *FuncDecl) {
207   assert(FuncDecl->getBody() != nullptr);
208 
209   llvm::DenseSet<const FieldDecl *> Fields;
210   llvm::DenseSet<const VarDecl *> Vars;
211 
212   // Look for global variable and field references in the
213   // constructor-initializers.
214   if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FuncDecl)) {
215     for (const auto *Init : CtorDecl->inits()) {
216       if (const auto *M = Init->getAnyMember())
217           Fields.insert(M);
218       const Expr *E = Init->getInit();
219       assert(E != nullptr);
220       getFieldsAndGlobalVars(*E, Fields, Vars);
221     }
222     // Add all fields mentioned in default member initializers.
223     for (const FieldDecl *F : CtorDecl->getParent()->fields())
224       if (const auto *I = F->getInClassInitializer())
225           getFieldsAndGlobalVars(*I, Fields, Vars);
226   }
227   getFieldsAndGlobalVars(*FuncDecl->getBody(), Fields, Vars);
228 
229   // These have to be added before the lines that follow to ensure that
230   // `create*` work correctly for structs.
231   DACtx->addModeledFields(Fields);
232 
233   for (const VarDecl *D : Vars) {
234     if (getStorageLocation(*D, SkipPast::None) != nullptr)
235       continue;
236     auto &Loc = createStorageLocation(*D);
237     setStorageLocation(*D, Loc);
238     if (auto *Val = createValue(D->getType()))
239       setValue(Loc, *Val);
240   }
241 }
242 
243 Environment::Environment(DataflowAnalysisContext &DACtx)
244     : DACtx(&DACtx), FlowConditionToken(&DACtx.makeFlowConditionToken()) {}
245 
246 Environment::Environment(const Environment &Other)
247     : DACtx(Other.DACtx), CallStack(Other.CallStack),
248       ReturnLoc(Other.ReturnLoc), ThisPointeeLoc(Other.ThisPointeeLoc),
249       DeclToLoc(Other.DeclToLoc), ExprToLoc(Other.ExprToLoc),
250       LocToVal(Other.LocToVal), MemberLocToStruct(Other.MemberLocToStruct),
251       FlowConditionToken(&DACtx->forkFlowCondition(*Other.FlowConditionToken)) {
252 }
253 
254 Environment &Environment::operator=(const Environment &Other) {
255   Environment Copy(Other);
256   *this = std::move(Copy);
257   return *this;
258 }
259 
260 Environment::Environment(DataflowAnalysisContext &DACtx,
261                          const DeclContext &DeclCtx)
262     : Environment(DACtx) {
263   CallStack.push_back(&DeclCtx);
264 
265   if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) {
266     assert(FuncDecl->getBody() != nullptr);
267 
268     initFieldsAndGlobals(FuncDecl);
269 
270     for (const auto *ParamDecl : FuncDecl->parameters()) {
271       assert(ParamDecl != nullptr);
272       auto &ParamLoc = createStorageLocation(*ParamDecl);
273       setStorageLocation(*ParamDecl, ParamLoc);
274       if (Value *ParamVal = createValue(ParamDecl->getType()))
275         setValue(ParamLoc, *ParamVal);
276     }
277 
278     QualType ReturnType = FuncDecl->getReturnType();
279     ReturnLoc = &createStorageLocation(ReturnType);
280   }
281 
282   if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) {
283     auto *Parent = MethodDecl->getParent();
284     assert(Parent != nullptr);
285     if (Parent->isLambda())
286       MethodDecl = dyn_cast<CXXMethodDecl>(Parent->getDeclContext());
287 
288     // FIXME: Initialize the ThisPointeeLoc of lambdas too.
289     if (MethodDecl && !MethodDecl->isStatic()) {
290       QualType ThisPointeeType = MethodDecl->getThisObjectType();
291       ThisPointeeLoc = &createStorageLocation(ThisPointeeType);
292       if (Value *ThisPointeeVal = createValue(ThisPointeeType))
293         setValue(*ThisPointeeLoc, *ThisPointeeVal);
294     }
295   }
296 }
297 
298 bool Environment::canDescend(unsigned MaxDepth,
299                              const DeclContext *Callee) const {
300   return CallStack.size() <= MaxDepth && !llvm::is_contained(CallStack, Callee);
301 }
302 
303 Environment Environment::pushCall(const CallExpr *Call) const {
304   Environment Env(*this);
305 
306   // FIXME: Support references here.
307   Env.ReturnLoc = getStorageLocation(*Call, SkipPast::Reference);
308 
309   if (const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(Call)) {
310     if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
311       if (!isa<CXXThisExpr>(Arg))
312         Env.ThisPointeeLoc = getStorageLocation(*Arg, SkipPast::Reference);
313       // Otherwise (when the argument is `this`), retain the current
314       // environment's `ThisPointeeLoc`.
315     }
316   }
317 
318   Env.pushCallInternal(Call->getDirectCallee(),
319                        llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));
320 
321   return Env;
322 }
323 
324 Environment Environment::pushCall(const CXXConstructExpr *Call) const {
325   Environment Env(*this);
326 
327   // FIXME: Support references here.
328   Env.ReturnLoc = getStorageLocation(*Call, SkipPast::Reference);
329 
330   Env.ThisPointeeLoc = Env.ReturnLoc;
331 
332   Env.pushCallInternal(Call->getConstructor(),
333                        llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));
334 
335   return Env;
336 }
337 
338 void Environment::pushCallInternal(const FunctionDecl *FuncDecl,
339                                    ArrayRef<const Expr *> Args) {
340   CallStack.push_back(FuncDecl);
341 
342   initFieldsAndGlobals(FuncDecl);
343 
344   const auto *ParamIt = FuncDecl->param_begin();
345 
346   // FIXME: Parameters don't always map to arguments 1:1; examples include
347   // overloaded operators implemented as member functions, and parameter packs.
348   for (unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) {
349     assert(ParamIt != FuncDecl->param_end());
350 
351     const Expr *Arg = Args[ArgIndex];
352     auto *ArgLoc = getStorageLocation(*Arg, SkipPast::Reference);
353     if (ArgLoc == nullptr)
354       continue;
355 
356     const VarDecl *Param = *ParamIt;
357     auto &Loc = createStorageLocation(*Param);
358     setStorageLocation(*Param, Loc);
359 
360     QualType ParamType = Param->getType();
361     if (ParamType->isReferenceType()) {
362       auto &Val = create<ReferenceValue>(*ArgLoc);
363       setValue(Loc, Val);
364     } else if (auto *ArgVal = getValue(*ArgLoc)) {
365       setValue(Loc, *ArgVal);
366     } else if (Value *Val = createValue(ParamType)) {
367       setValue(Loc, *Val);
368     }
369   }
370 }
371 
372 void Environment::popCall(const Environment &CalleeEnv) {
373   // We ignore `DACtx` because it's already the same in both. We don't want the
374   // callee's `DeclCtx`, `ReturnLoc` or `ThisPointeeLoc`. We don't bring back
375   // `DeclToLoc` and `ExprToLoc` because we want to be able to later analyze the
376   // same callee in a different context, and `setStorageLocation` requires there
377   // to not already be a storage location assigned. Conceptually, these maps
378   // capture information from the local scope, so when popping that scope, we do
379   // not propagate the maps.
380   this->LocToVal = std::move(CalleeEnv.LocToVal);
381   this->MemberLocToStruct = std::move(CalleeEnv.MemberLocToStruct);
382   this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
383 }
384 
385 bool Environment::equivalentTo(const Environment &Other,
386                                Environment::ValueModel &Model) const {
387   assert(DACtx == Other.DACtx);
388 
389   if (ReturnLoc != Other.ReturnLoc)
390     return false;
391 
392   if (ThisPointeeLoc != Other.ThisPointeeLoc)
393     return false;
394 
395   if (DeclToLoc != Other.DeclToLoc)
396     return false;
397 
398   if (ExprToLoc != Other.ExprToLoc)
399     return false;
400 
401   // Compare the contents for the intersection of their domains.
402   for (auto &Entry : LocToVal) {
403     const StorageLocation *Loc = Entry.first;
404     assert(Loc != nullptr);
405 
406     Value *Val = Entry.second;
407     assert(Val != nullptr);
408 
409     auto It = Other.LocToVal.find(Loc);
410     if (It == Other.LocToVal.end())
411       continue;
412     assert(It->second != nullptr);
413 
414     if (!areEquivalentValues(*Val, *It->second) &&
415         !compareDistinctValues(Loc->getType(), *Val, *this, *It->second, Other,
416                                Model))
417       return false;
418   }
419 
420   return true;
421 }
422 
423 LatticeJoinEffect Environment::widen(const Environment &PrevEnv,
424                                      Environment::ValueModel &Model) {
425   assert(DACtx == PrevEnv.DACtx);
426   assert(ReturnLoc == PrevEnv.ReturnLoc);
427   assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc);
428   assert(CallStack == PrevEnv.CallStack);
429 
430   auto Effect = LatticeJoinEffect::Unchanged;
431 
432   // By the API, `PrevEnv` is a previous version of the environment for the same
433   // block, so we have some guarantees about its shape. In particular, it will
434   // be the result of a join or widen operation on previous values for this
435   // block. For `DeclToLoc` and `ExprToLoc`, join guarantees that these maps are
436   // subsets of the maps in `PrevEnv`. So, as long as we maintain this property
437   // here, we don't need change their current values to widen.
438   //
439   // FIXME: `MemberLocToStruct` does not share the above property, because
440   // `join` can cause the map size to increase (when we add fresh data in places
441   // of conflict). Once this issue with join is resolved, re-enable the
442   // assertion below or replace with something that captures the desired
443   // invariant.
444   assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size());
445   assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size());
446   // assert(MemberLocToStruct.size() <= PrevEnv.MemberLocToStruct.size());
447 
448   llvm::DenseMap<const StorageLocation *, Value *> WidenedLocToVal;
449   for (auto &Entry : LocToVal) {
450     const StorageLocation *Loc = Entry.first;
451     assert(Loc != nullptr);
452 
453     Value *Val = Entry.second;
454     assert(Val != nullptr);
455 
456     auto PrevIt = PrevEnv.LocToVal.find(Loc);
457     if (PrevIt == PrevEnv.LocToVal.end())
458       continue;
459     assert(PrevIt->second != nullptr);
460 
461     if (areEquivalentValues(*Val, *PrevIt->second)) {
462       WidenedLocToVal.insert({Loc, Val});
463       continue;
464     }
465 
466     Value &WidenedVal = widenDistinctValues(Loc->getType(), *PrevIt->second,
467                                             PrevEnv, *Val, *this, Model);
468     WidenedLocToVal.insert({Loc, &WidenedVal});
469     if (&WidenedVal != PrevIt->second)
470       Effect = LatticeJoinEffect::Changed;
471   }
472   LocToVal = std::move(WidenedLocToVal);
473   // FIXME: update the equivalence calculation for `MemberLocToStruct`, once we
474   // have a systematic way of soundly comparing this map.
475   if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() ||
476       ExprToLoc.size() != PrevEnv.ExprToLoc.size() ||
477       LocToVal.size() != PrevEnv.LocToVal.size() ||
478       MemberLocToStruct.size() != PrevEnv.MemberLocToStruct.size())
479     Effect = LatticeJoinEffect::Changed;
480 
481   return Effect;
482 }
483 
484 LatticeJoinEffect Environment::join(const Environment &Other,
485                                     Environment::ValueModel &Model) {
486   assert(DACtx == Other.DACtx);
487   assert(ReturnLoc == Other.ReturnLoc);
488   assert(ThisPointeeLoc == Other.ThisPointeeLoc);
489   assert(CallStack == Other.CallStack);
490 
491   auto Effect = LatticeJoinEffect::Unchanged;
492 
493   Environment JoinedEnv(*DACtx);
494 
495   JoinedEnv.CallStack = CallStack;
496   JoinedEnv.ReturnLoc = ReturnLoc;
497   JoinedEnv.ThisPointeeLoc = ThisPointeeLoc;
498 
499   JoinedEnv.DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc);
500   if (DeclToLoc.size() != JoinedEnv.DeclToLoc.size())
501     Effect = LatticeJoinEffect::Changed;
502 
503   JoinedEnv.ExprToLoc = intersectDenseMaps(ExprToLoc, Other.ExprToLoc);
504   if (ExprToLoc.size() != JoinedEnv.ExprToLoc.size())
505     Effect = LatticeJoinEffect::Changed;
506 
507   JoinedEnv.MemberLocToStruct =
508       intersectDenseMaps(MemberLocToStruct, Other.MemberLocToStruct);
509   if (MemberLocToStruct.size() != JoinedEnv.MemberLocToStruct.size())
510     Effect = LatticeJoinEffect::Changed;
511 
512   // FIXME: set `Effect` as needed.
513   // FIXME: update join to detect backedges and simplify the flow condition
514   // accordingly.
515   JoinedEnv.FlowConditionToken = &DACtx->joinFlowConditions(
516       *FlowConditionToken, *Other.FlowConditionToken);
517 
518   for (auto &Entry : LocToVal) {
519     const StorageLocation *Loc = Entry.first;
520     assert(Loc != nullptr);
521 
522     Value *Val = Entry.second;
523     assert(Val != nullptr);
524 
525     auto It = Other.LocToVal.find(Loc);
526     if (It == Other.LocToVal.end())
527       continue;
528     assert(It->second != nullptr);
529 
530     if (areEquivalentValues(*Val, *It->second)) {
531       JoinedEnv.LocToVal.insert({Loc, Val});
532       continue;
533     }
534 
535     if (Value *MergedVal =
536             mergeDistinctValues(Loc->getType(), *Val, *this, *It->second, Other,
537                                 JoinedEnv, Model)) {
538       JoinedEnv.LocToVal.insert({Loc, MergedVal});
539       Effect = LatticeJoinEffect::Changed;
540     }
541   }
542   if (LocToVal.size() != JoinedEnv.LocToVal.size())
543     Effect = LatticeJoinEffect::Changed;
544 
545   *this = std::move(JoinedEnv);
546 
547   return Effect;
548 }
549 
550 StorageLocation &Environment::createStorageLocation(QualType Type) {
551   return DACtx->createStorageLocation(Type);
552 }
553 
554 StorageLocation &Environment::createStorageLocation(const VarDecl &D) {
555   // Evaluated declarations are always assigned the same storage locations to
556   // ensure that the environment stabilizes across loop iterations. Storage
557   // locations for evaluated declarations are stored in the analysis context.
558   return DACtx->getStableStorageLocation(D);
559 }
560 
561 StorageLocation &Environment::createStorageLocation(const Expr &E) {
562   // Evaluated expressions are always assigned the same storage locations to
563   // ensure that the environment stabilizes across loop iterations. Storage
564   // locations for evaluated expressions are stored in the analysis context.
565   return DACtx->getStableStorageLocation(E);
566 }
567 
568 void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
569   assert(!DeclToLoc.contains(&D));
570   DeclToLoc[&D] = &Loc;
571 }
572 
573 StorageLocation *Environment::getStorageLocation(const ValueDecl &D,
574                                                  SkipPast SP) const {
575   auto It = DeclToLoc.find(&D);
576   return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP);
577 }
578 
579 void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
580   const Expr &CanonE = ignoreCFGOmittedNodes(E);
581   assert(!ExprToLoc.contains(&CanonE));
582   ExprToLoc[&CanonE] = &Loc;
583 }
584 
585 StorageLocation *Environment::getStorageLocation(const Expr &E,
586                                                  SkipPast SP) const {
587   // FIXME: Add a test with parens.
588   auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));
589   return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP);
590 }
591 
592 StorageLocation *Environment::getThisPointeeStorageLocation() const {
593   return ThisPointeeLoc;
594 }
595 
596 StorageLocation *Environment::getReturnStorageLocation() const {
597   return ReturnLoc;
598 }
599 
600 PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) {
601   return DACtx->getOrCreateNullPointerValue(PointeeType);
602 }
603 
604 void Environment::setValue(const StorageLocation &Loc, Value &Val) {
605   LocToVal[&Loc] = &Val;
606 
607   if (auto *StructVal = dyn_cast<StructValue>(&Val)) {
608     auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc);
609 
610     const QualType Type = AggregateLoc.getType();
611     assert(Type->isStructureOrClassType() || Type->isUnionType());
612 
613     for (const FieldDecl *Field : DACtx->getReferencedFields(Type)) {
614       assert(Field != nullptr);
615       StorageLocation &FieldLoc = AggregateLoc.getChild(*Field);
616       MemberLocToStruct[&FieldLoc] = std::make_pair(StructVal, Field);
617       if (auto *FieldVal = StructVal->getChild(*Field))
618         setValue(FieldLoc, *FieldVal);
619     }
620   }
621 
622   auto It = MemberLocToStruct.find(&Loc);
623   if (It != MemberLocToStruct.end()) {
624     // `Loc` is the location of a struct member so we need to also update the
625     // value of the member in the corresponding `StructValue`.
626 
627     assert(It->second.first != nullptr);
628     StructValue &StructVal = *It->second.first;
629 
630     assert(It->second.second != nullptr);
631     const ValueDecl &Member = *It->second.second;
632 
633     StructVal.setChild(Member, Val);
634   }
635 }
636 
637 Value *Environment::getValue(const StorageLocation &Loc) const {
638   auto It = LocToVal.find(&Loc);
639   return It == LocToVal.end() ? nullptr : It->second;
640 }
641 
642 Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const {
643   auto *Loc = getStorageLocation(D, SP);
644   if (Loc == nullptr)
645     return nullptr;
646   return getValue(*Loc);
647 }
648 
649 Value *Environment::getValue(const Expr &E, SkipPast SP) const {
650   auto *Loc = getStorageLocation(E, SP);
651   if (Loc == nullptr)
652     return nullptr;
653   return getValue(*Loc);
654 }
655 
656 Value *Environment::createValue(QualType Type) {
657   llvm::DenseSet<QualType> Visited;
658   int CreatedValuesCount = 0;
659   Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0,
660                                                 CreatedValuesCount);
661   if (CreatedValuesCount > MaxCompositeValueSize) {
662     llvm::errs() << "Attempting to initialize a huge value of type: " << Type
663                  << '\n';
664   }
665   return Val;
666 }
667 
668 Value *Environment::createValueUnlessSelfReferential(
669     QualType Type, llvm::DenseSet<QualType> &Visited, int Depth,
670     int &CreatedValuesCount) {
671   assert(!Type.isNull());
672 
673   // Allow unlimited fields at depth 1; only cap at deeper nesting levels.
674   if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) ||
675       Depth > MaxCompositeValueDepth)
676     return nullptr;
677 
678   if (Type->isBooleanType()) {
679     CreatedValuesCount++;
680     return &makeAtomicBoolValue();
681   }
682 
683   if (Type->isIntegerType()) {
684     // FIXME: consider instead `return nullptr`, given that we do nothing useful
685     // with integers, and so distinguishing them serves no purpose, but could
686     // prevent convergence.
687     CreatedValuesCount++;
688     return &create<IntegerValue>();
689   }
690 
691   if (Type->isReferenceType()) {
692     CreatedValuesCount++;
693     QualType PointeeType = Type->castAs<ReferenceType>()->getPointeeType();
694     auto &PointeeLoc = createStorageLocation(PointeeType);
695 
696     if (Visited.insert(PointeeType.getCanonicalType()).second) {
697       Value *PointeeVal = createValueUnlessSelfReferential(
698           PointeeType, Visited, Depth, CreatedValuesCount);
699       Visited.erase(PointeeType.getCanonicalType());
700 
701       if (PointeeVal != nullptr)
702         setValue(PointeeLoc, *PointeeVal);
703     }
704 
705     return &create<ReferenceValue>(PointeeLoc);
706   }
707 
708   if (Type->isPointerType()) {
709     CreatedValuesCount++;
710     QualType PointeeType = Type->castAs<PointerType>()->getPointeeType();
711     auto &PointeeLoc = createStorageLocation(PointeeType);
712 
713     if (Visited.insert(PointeeType.getCanonicalType()).second) {
714       Value *PointeeVal = createValueUnlessSelfReferential(
715           PointeeType, Visited, Depth, CreatedValuesCount);
716       Visited.erase(PointeeType.getCanonicalType());
717 
718       if (PointeeVal != nullptr)
719         setValue(PointeeLoc, *PointeeVal);
720     }
721 
722     return &create<PointerValue>(PointeeLoc);
723   }
724 
725   if (Type->isStructureOrClassType() || Type->isUnionType()) {
726     CreatedValuesCount++;
727     llvm::DenseMap<const ValueDecl *, Value *> FieldValues;
728     for (const FieldDecl *Field : DACtx->getReferencedFields(Type)) {
729       assert(Field != nullptr);
730 
731       QualType FieldType = Field->getType();
732       if (Visited.contains(FieldType.getCanonicalType()))
733         continue;
734 
735       Visited.insert(FieldType.getCanonicalType());
736       if (auto *FieldValue = createValueUnlessSelfReferential(
737               FieldType, Visited, Depth + 1, CreatedValuesCount))
738         FieldValues.insert({Field, FieldValue});
739       Visited.erase(FieldType.getCanonicalType());
740     }
741 
742     return &create<StructValue>(std::move(FieldValues));
743   }
744 
745   return nullptr;
746 }
747 
748 StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const {
749   switch (SP) {
750   case SkipPast::None:
751     return Loc;
752   case SkipPast::Reference:
753     // References cannot be chained so we only need to skip past one level of
754     // indirection.
755     if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc)))
756       return Val->getReferentLoc();
757     return Loc;
758   case SkipPast::ReferenceThenPointer:
759     StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference);
760     if (auto *Val = dyn_cast_or_null<PointerValue>(getValue(LocPastRef)))
761       return Val->getPointeeLoc();
762     return LocPastRef;
763   }
764   llvm_unreachable("bad SkipPast kind");
765 }
766 
767 const StorageLocation &Environment::skip(const StorageLocation &Loc,
768                                          SkipPast SP) const {
769   return skip(*const_cast<StorageLocation *>(&Loc), SP);
770 }
771 
772 void Environment::addToFlowCondition(BoolValue &Val) {
773   DACtx->addFlowConditionConstraint(*FlowConditionToken, Val);
774 }
775 
776 bool Environment::flowConditionImplies(BoolValue &Val) const {
777   return DACtx->flowConditionImplies(*FlowConditionToken, Val);
778 }
779 
780 void Environment::dump(raw_ostream &OS) const {
781   // FIXME: add printing for remaining fields and allow caller to decide what
782   // fields are printed.
783   OS << "DeclToLoc:\n";
784   for (auto [D, L] : DeclToLoc)
785     OS << "  [" << D->getName() << ", " << L << "]\n";
786 
787   OS << "ExprToLoc:\n";
788   for (auto [E, L] : ExprToLoc)
789     OS << "  [" << E << ", " << L << "]\n";
790 
791   OS << "LocToVal:\n";
792   for (auto [L, V] : LocToVal) {
793     OS << "  [" << L << ", " << V << ": " << *V << "]\n";
794   }
795 
796   OS << "FlowConditionToken:\n";
797   DACtx->dumpFlowCondition(*FlowConditionToken, OS);
798 }
799 
800 void Environment::dump() const {
801   dump(llvm::dbgs());
802 }
803 
804 } // namespace dataflow
805 } // namespace clang
806