xref: /llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (revision 6c81b57237164319b5429ee33957004aa21db2fa)
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/StorageLocation.h"
21 #include "clang/Analysis/FlowSensitive/Value.h"
22 #include "llvm/ADT/DenseMap.h"
23 #include "llvm/ADT/DenseSet.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 /// Returns true if and only if `Val1` is equivalent to `Val2`.
53 static bool equivalentValues(QualType Type, Value *Val1,
54                              const Environment &Env1, Value *Val2,
55                              const Environment &Env2,
56                              Environment::ValueModel &Model) {
57   if (Val1 == Val2)
58     return true;
59 
60   if (auto *IndVal1 = dyn_cast<IndirectionValue>(Val1)) {
61     auto *IndVal2 = cast<IndirectionValue>(Val2);
62     assert(IndVal1->getKind() == IndVal2->getKind());
63     if (&IndVal1->getPointeeLoc() == &IndVal2->getPointeeLoc())
64       return true;
65   }
66 
67   return Model.compareEquivalent(Type, *Val1, Env1, *Val2, Env2);
68 }
69 
70 /// Attempts to merge distinct values `Val1` and `Val2` in `Env1` and `Env2`,
71 /// respectively, of the same type `Type`. Merging generally produces a single
72 /// value that (soundly) approximates the two inputs, although the actual
73 /// meaning depends on `Model`.
74 static Value *mergeDistinctValues(QualType Type, Value *Val1,
75                                   const Environment &Env1, Value *Val2,
76                                   const Environment &Env2,
77                                   Environment &MergedEnv,
78                                   Environment::ValueModel &Model) {
79   // Join distinct boolean values preserving information about the constraints
80   // in the respective path conditions. Note: this construction can, in
81   // principle, result in exponential growth in the size of boolean values.
82   // Potential optimizations may be worth considering. For example, represent
83   // the flow condition of each environment using a bool atom and store, in
84   // `DataflowAnalysisContext`, a mapping of bi-conditionals between flow
85   // condition atoms and flow condition constraints. Something like:
86   // \code
87   //   FC1 <=> C1 ^ C2
88   //   FC2 <=> C2 ^ C3 ^ C4
89   //   FC3 <=> (FC1 v FC2) ^ C5
90   // \code
91   // Then, we can track dependencies between flow conditions (e.g. above `FC3`
92   // depends on `FC1` and `FC2`) and modify `flowConditionImplies` to construct
93   // a formula that includes the bi-conditionals for all flow condition atoms in
94   // the transitive set, before invoking the solver.
95   //
96   // FIXME: Does not work for backedges, since the two (or more) paths will not
97   // have mutually exclusive conditions.
98   if (auto *Expr1 = dyn_cast<BoolValue>(Val1)) {
99     for (BoolValue *Constraint : Env1.getFlowConditionConstraints()) {
100       Expr1 = &MergedEnv.makeAnd(*Expr1, *Constraint);
101     }
102     auto *Expr2 = cast<BoolValue>(Val2);
103     for (BoolValue *Constraint : Env2.getFlowConditionConstraints()) {
104       Expr2 = &MergedEnv.makeAnd(*Expr2, *Constraint);
105     }
106     return &MergedEnv.makeOr(*Expr1, *Expr2);
107   }
108 
109   // FIXME: add unit tests that cover this statement.
110   if (auto *IndVal1 = dyn_cast<IndirectionValue>(Val1)) {
111     auto *IndVal2 = cast<IndirectionValue>(Val2);
112     assert(IndVal1->getKind() == IndVal2->getKind());
113     if (&IndVal1->getPointeeLoc() == &IndVal2->getPointeeLoc()) {
114       return Val1;
115     }
116   }
117 
118   // FIXME: Consider destroying `MergedValue` immediately if `ValueModel::merge`
119   // returns false to avoid storing unneeded values in `DACtx`.
120   if (Value *MergedVal = MergedEnv.createValue(Type))
121     if (Model.merge(Type, *Val1, Env1, *Val2, Env2, *MergedVal, MergedEnv))
122       return MergedVal;
123 
124   return nullptr;
125 }
126 
127 /// Initializes a global storage value.
128 static void initGlobalVar(const VarDecl &D, Environment &Env) {
129   if (!D.hasGlobalStorage() ||
130       Env.getStorageLocation(D, SkipPast::None) != nullptr)
131     return;
132 
133   auto &Loc = Env.createStorageLocation(D);
134   Env.setStorageLocation(D, Loc);
135   if (auto *Val = Env.createValue(D.getType()))
136     Env.setValue(Loc, *Val);
137 }
138 
139 /// Initializes a global storage value.
140 static void initGlobalVar(const Decl &D, Environment &Env) {
141   if (auto *V = dyn_cast<VarDecl>(&D))
142     initGlobalVar(*V, Env);
143 }
144 
145 /// Initializes global storage values that are declared or referenced from
146 /// sub-statements of `S`.
147 // FIXME: Add support for resetting globals after function calls to enable
148 // the implementation of sound analyses.
149 static void initGlobalVars(const Stmt &S, Environment &Env) {
150   for (auto *Child : S.children()) {
151     if (Child != nullptr)
152       initGlobalVars(*Child, Env);
153   }
154 
155   if (auto *DS = dyn_cast<DeclStmt>(&S)) {
156     if (DS->isSingleDecl()) {
157       initGlobalVar(*DS->getSingleDecl(), Env);
158     } else {
159       for (auto *D : DS->getDeclGroup())
160         initGlobalVar(*D, Env);
161     }
162   } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) {
163     initGlobalVar(*E->getDecl(), Env);
164   } else if (auto *E = dyn_cast<MemberExpr>(&S)) {
165     initGlobalVar(*E->getMemberDecl(), Env);
166   }
167 }
168 
169 /// Returns constraints that represent the disjunction of `Constraints1` and
170 /// `Constraints2`.
171 ///
172 /// Requirements:
173 ///
174 ///  The elements of `Constraints1` and `Constraints2` must not be null.
175 llvm::DenseSet<BoolValue *>
176 joinConstraints(DataflowAnalysisContext *Context,
177                 const llvm::DenseSet<BoolValue *> &Constraints1,
178                 const llvm::DenseSet<BoolValue *> &Constraints2) {
179   // `(X ^ Y) v (X ^ Z)` is logically equivalent to `X ^ (Y v Z)`. Therefore, to
180   // avoid unnecessarily expanding the resulting set of constraints, we will add
181   // all common constraints of `Constraints1` and `Constraints2` directly and
182   // add a disjunction of the constraints that are not common.
183 
184   llvm::DenseSet<BoolValue *> JoinedConstraints;
185 
186   if (Constraints1.empty() || Constraints2.empty()) {
187     // Disjunction of empty set and non-empty set is represented as empty set.
188     return JoinedConstraints;
189   }
190 
191   BoolValue *Val1 = nullptr;
192   for (BoolValue *Constraint : Constraints1) {
193     if (Constraints2.contains(Constraint)) {
194       // Add common constraints directly to `JoinedConstraints`.
195       JoinedConstraints.insert(Constraint);
196     } else if (Val1 == nullptr) {
197       Val1 = Constraint;
198     } else {
199       Val1 = &Context->getOrCreateConjunctionValue(*Val1, *Constraint);
200     }
201   }
202 
203   BoolValue *Val2 = nullptr;
204   for (BoolValue *Constraint : Constraints2) {
205     // Common constraints are added to `JoinedConstraints` above.
206     if (Constraints1.contains(Constraint)) {
207       continue;
208     }
209     if (Val2 == nullptr) {
210       Val2 = Constraint;
211     } else {
212       Val2 = &Context->getOrCreateConjunctionValue(*Val2, *Constraint);
213     }
214   }
215 
216   // An empty set of constraints (represented as a null value) is interpreted as
217   // `true` and `true v X` is logically equivalent to `true` so we need to add a
218   // constraint only if both `Val1` and `Val2` are not null.
219   if (Val1 != nullptr && Val2 != nullptr)
220     JoinedConstraints.insert(
221         &Context->getOrCreateDisjunctionValue(*Val1, *Val2));
222 
223   return JoinedConstraints;
224 }
225 
226 static void
227 getFieldsFromClassHierarchy(QualType Type, bool IgnorePrivateFields,
228                             llvm::DenseSet<const FieldDecl *> &Fields) {
229   if (Type->isIncompleteType() || Type->isDependentType() ||
230       !Type->isRecordType())
231     return;
232 
233   for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
234     if (IgnorePrivateFields &&
235         (Field->getAccess() == AS_private ||
236          (Field->getAccess() == AS_none && Type->getAsRecordDecl()->isClass())))
237       continue;
238     Fields.insert(Field);
239   }
240   if (auto *CXXRecord = Type->getAsCXXRecordDecl()) {
241     for (const CXXBaseSpecifier &Base : CXXRecord->bases()) {
242       // Ignore private fields (including default access in C++ classes) in
243       // base classes, because they are not visible in derived classes.
244       getFieldsFromClassHierarchy(Base.getType(), /*IgnorePrivateFields=*/true,
245                                   Fields);
246     }
247   }
248 }
249 
250 /// Gets the set of all fields accesible from the type.
251 ///
252 /// FIXME: Does not precisely handle non-virtual diamond inheritance. A single
253 /// field decl will be modeled for all instances of the inherited field.
254 static llvm::DenseSet<const FieldDecl *>
255 getAccessibleObjectFields(QualType Type) {
256   llvm::DenseSet<const FieldDecl *> Fields;
257   // Don't ignore private fields for the class itself, only its super classes.
258   getFieldsFromClassHierarchy(Type, /*IgnorePrivateFields=*/false, Fields);
259   return Fields;
260 }
261 
262 Environment::Environment(DataflowAnalysisContext &DACtx,
263                          const DeclContext &DeclCtx)
264     : Environment(DACtx) {
265   if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) {
266     assert(FuncDecl->getBody() != nullptr);
267     initGlobalVars(*FuncDecl->getBody(), *this);
268     for (const auto *ParamDecl : FuncDecl->parameters()) {
269       assert(ParamDecl != nullptr);
270       auto &ParamLoc = createStorageLocation(*ParamDecl);
271       setStorageLocation(*ParamDecl, ParamLoc);
272       if (Value *ParamVal = createValue(ParamDecl->getType()))
273         setValue(ParamLoc, *ParamVal);
274     }
275   }
276 
277   if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) {
278     if (!MethodDecl->isStatic()) {
279       QualType ThisPointeeType = MethodDecl->getThisObjectType();
280       // FIXME: Add support for union types.
281       if (!ThisPointeeType->isUnionType()) {
282         auto &ThisPointeeLoc = createStorageLocation(ThisPointeeType);
283         DACtx.setThisPointeeStorageLocation(ThisPointeeLoc);
284         if (Value *ThisPointeeVal = createValue(ThisPointeeType))
285           setValue(ThisPointeeLoc, *ThisPointeeVal);
286       }
287     }
288   }
289 }
290 
291 bool Environment::equivalentTo(const Environment &Other,
292                                Environment::ValueModel &Model) const {
293   assert(DACtx == Other.DACtx);
294 
295   if (DeclToLoc != Other.DeclToLoc)
296     return false;
297 
298   if (ExprToLoc != Other.ExprToLoc)
299     return false;
300 
301   if (MemberLocToStruct != Other.MemberLocToStruct)
302     return false;
303 
304   // Compare the contents for the intersection of their domains.
305   for (auto &Entry : LocToVal) {
306     const StorageLocation *Loc = Entry.first;
307     assert(Loc != nullptr);
308 
309     Value *Val = Entry.second;
310     assert(Val != nullptr);
311 
312     auto It = Other.LocToVal.find(Loc);
313     if (It == Other.LocToVal.end())
314       continue;
315     assert(It->second != nullptr);
316 
317     if (!equivalentValues(Loc->getType(), Val, *this, It->second, Other, Model))
318       return false;
319   }
320 
321   return true;
322 }
323 
324 LatticeJoinEffect Environment::join(const Environment &Other,
325                                     Environment::ValueModel &Model) {
326   assert(DACtx == Other.DACtx);
327 
328   auto Effect = LatticeJoinEffect::Unchanged;
329 
330   Environment JoinedEnv(*DACtx);
331 
332   JoinedEnv.DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc);
333   if (DeclToLoc.size() != JoinedEnv.DeclToLoc.size())
334     Effect = LatticeJoinEffect::Changed;
335 
336   JoinedEnv.ExprToLoc = intersectDenseMaps(ExprToLoc, Other.ExprToLoc);
337   if (ExprToLoc.size() != JoinedEnv.ExprToLoc.size())
338     Effect = LatticeJoinEffect::Changed;
339 
340   JoinedEnv.MemberLocToStruct =
341       intersectDenseMaps(MemberLocToStruct, Other.MemberLocToStruct);
342   if (MemberLocToStruct.size() != JoinedEnv.MemberLocToStruct.size())
343     Effect = LatticeJoinEffect::Changed;
344 
345   // FIXME: set `Effect` as needed.
346   JoinedEnv.FlowConditionConstraints = joinConstraints(
347       DACtx, FlowConditionConstraints, Other.FlowConditionConstraints);
348 
349   for (auto &Entry : LocToVal) {
350     const StorageLocation *Loc = Entry.first;
351     assert(Loc != nullptr);
352 
353     Value *Val = Entry.second;
354     assert(Val != nullptr);
355 
356     auto It = Other.LocToVal.find(Loc);
357     if (It == Other.LocToVal.end())
358       continue;
359     assert(It->second != nullptr);
360 
361     if (Val == It->second) {
362       JoinedEnv.LocToVal.insert({Loc, Val});
363       continue;
364     }
365 
366     if (Value *MergedVal = mergeDistinctValues(
367             Loc->getType(), Val, *this, It->second, Other, JoinedEnv, Model))
368       JoinedEnv.LocToVal.insert({Loc, MergedVal});
369   }
370   if (LocToVal.size() != JoinedEnv.LocToVal.size())
371     Effect = LatticeJoinEffect::Changed;
372 
373   *this = std::move(JoinedEnv);
374 
375   return Effect;
376 }
377 
378 StorageLocation &Environment::createStorageLocation(QualType Type) {
379   assert(!Type.isNull());
380   if (Type->isStructureOrClassType() || Type->isUnionType()) {
381     // FIXME: Explore options to avoid eager initialization of fields as some of
382     // them might not be needed for a particular analysis.
383     llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
384     for (const FieldDecl *Field : getAccessibleObjectFields(Type)) {
385       FieldLocs.insert({Field, &createStorageLocation(Field->getType())});
386     }
387     return takeOwnership(
388         std::make_unique<AggregateStorageLocation>(Type, std::move(FieldLocs)));
389   }
390   return takeOwnership(std::make_unique<ScalarStorageLocation>(Type));
391 }
392 
393 StorageLocation &Environment::createStorageLocation(const VarDecl &D) {
394   // Evaluated declarations are always assigned the same storage locations to
395   // ensure that the environment stabilizes across loop iterations. Storage
396   // locations for evaluated declarations are stored in the analysis context.
397   if (auto *Loc = DACtx->getStorageLocation(D))
398     return *Loc;
399   auto &Loc = createStorageLocation(D.getType());
400   DACtx->setStorageLocation(D, Loc);
401   return Loc;
402 }
403 
404 StorageLocation &Environment::createStorageLocation(const Expr &E) {
405   // Evaluated expressions are always assigned the same storage locations to
406   // ensure that the environment stabilizes across loop iterations. Storage
407   // locations for evaluated expressions are stored in the analysis context.
408   if (auto *Loc = DACtx->getStorageLocation(E))
409     return *Loc;
410   auto &Loc = createStorageLocation(E.getType());
411   DACtx->setStorageLocation(E, Loc);
412   return Loc;
413 }
414 
415 void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
416   assert(DeclToLoc.find(&D) == DeclToLoc.end());
417   DeclToLoc[&D] = &Loc;
418 }
419 
420 StorageLocation *Environment::getStorageLocation(const ValueDecl &D,
421                                                  SkipPast SP) const {
422   auto It = DeclToLoc.find(&D);
423   return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP);
424 }
425 
426 void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
427   assert(ExprToLoc.find(&E) == ExprToLoc.end());
428   ExprToLoc[&E] = &Loc;
429 }
430 
431 StorageLocation *Environment::getStorageLocation(const Expr &E,
432                                                  SkipPast SP) const {
433   // FIXME: Add a test with parens.
434   auto It = ExprToLoc.find(E.IgnoreParens());
435   return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP);
436 }
437 
438 StorageLocation *Environment::getThisPointeeStorageLocation() const {
439   return DACtx->getThisPointeeStorageLocation();
440 }
441 
442 void Environment::setValue(const StorageLocation &Loc, Value &Val) {
443   LocToVal[&Loc] = &Val;
444 
445   if (auto *StructVal = dyn_cast<StructValue>(&Val)) {
446     auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc);
447 
448     const QualType Type = AggregateLoc.getType();
449     assert(Type->isStructureOrClassType());
450 
451     for (const FieldDecl *Field : getAccessibleObjectFields(Type)) {
452       assert(Field != nullptr);
453       StorageLocation &FieldLoc = AggregateLoc.getChild(*Field);
454       MemberLocToStruct[&FieldLoc] = std::make_pair(StructVal, Field);
455       if (auto *FieldVal = StructVal->getChild(*Field))
456         setValue(FieldLoc, *FieldVal);
457     }
458   }
459 
460   auto IT = MemberLocToStruct.find(&Loc);
461   if (IT != MemberLocToStruct.end()) {
462     // `Loc` is the location of a struct member so we need to also update the
463     // value of the member in the corresponding `StructValue`.
464 
465     assert(IT->second.first != nullptr);
466     StructValue &StructVal = *IT->second.first;
467 
468     assert(IT->second.second != nullptr);
469     const ValueDecl &Member = *IT->second.second;
470 
471     StructVal.setChild(Member, Val);
472   }
473 }
474 
475 Value *Environment::getValue(const StorageLocation &Loc) const {
476   auto It = LocToVal.find(&Loc);
477   return It == LocToVal.end() ? nullptr : It->second;
478 }
479 
480 Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const {
481   auto *Loc = getStorageLocation(D, SP);
482   if (Loc == nullptr)
483     return nullptr;
484   return getValue(*Loc);
485 }
486 
487 Value *Environment::getValue(const Expr &E, SkipPast SP) const {
488   auto *Loc = getStorageLocation(E, SP);
489   if (Loc == nullptr)
490     return nullptr;
491   return getValue(*Loc);
492 }
493 
494 Value *Environment::createValue(QualType Type) {
495   llvm::DenseSet<QualType> Visited;
496   int CreatedValuesCount = 0;
497   Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0,
498                                                 CreatedValuesCount);
499   if (CreatedValuesCount > MaxCompositeValueSize) {
500     llvm::errs() << "Attempting to initialize a huge value of type: " << Type
501                  << '\n';
502   }
503   return Val;
504 }
505 
506 Value *Environment::createValueUnlessSelfReferential(
507     QualType Type, llvm::DenseSet<QualType> &Visited, int Depth,
508     int &CreatedValuesCount) {
509   assert(!Type.isNull());
510 
511   // Allow unlimited fields at depth 1; only cap at deeper nesting levels.
512   if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) ||
513       Depth > MaxCompositeValueDepth)
514     return nullptr;
515 
516   if (Type->isBooleanType()) {
517     CreatedValuesCount++;
518     return &makeAtomicBoolValue();
519   }
520 
521   if (Type->isIntegerType()) {
522     CreatedValuesCount++;
523     return &takeOwnership(std::make_unique<IntegerValue>());
524   }
525 
526   if (Type->isReferenceType()) {
527     CreatedValuesCount++;
528     QualType PointeeType = Type->castAs<ReferenceType>()->getPointeeType();
529     auto &PointeeLoc = createStorageLocation(PointeeType);
530 
531     if (!Visited.contains(PointeeType.getCanonicalType())) {
532       Visited.insert(PointeeType.getCanonicalType());
533       Value *PointeeVal = createValueUnlessSelfReferential(
534           PointeeType, Visited, Depth, CreatedValuesCount);
535       Visited.erase(PointeeType.getCanonicalType());
536 
537       if (PointeeVal != nullptr)
538         setValue(PointeeLoc, *PointeeVal);
539     }
540 
541     return &takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc));
542   }
543 
544   if (Type->isPointerType()) {
545     CreatedValuesCount++;
546     QualType PointeeType = Type->castAs<PointerType>()->getPointeeType();
547     auto &PointeeLoc = createStorageLocation(PointeeType);
548 
549     if (!Visited.contains(PointeeType.getCanonicalType())) {
550       Visited.insert(PointeeType.getCanonicalType());
551       Value *PointeeVal = createValueUnlessSelfReferential(
552           PointeeType, Visited, Depth, CreatedValuesCount);
553       Visited.erase(PointeeType.getCanonicalType());
554 
555       if (PointeeVal != nullptr)
556         setValue(PointeeLoc, *PointeeVal);
557     }
558 
559     return &takeOwnership(std::make_unique<PointerValue>(PointeeLoc));
560   }
561 
562   if (Type->isStructureOrClassType()) {
563     CreatedValuesCount++;
564     // FIXME: Initialize only fields that are accessed in the context that is
565     // being analyzed.
566     llvm::DenseMap<const ValueDecl *, Value *> FieldValues;
567     for (const FieldDecl *Field : getAccessibleObjectFields(Type)) {
568       assert(Field != nullptr);
569 
570       QualType FieldType = Field->getType();
571       if (Visited.contains(FieldType.getCanonicalType()))
572         continue;
573 
574       Visited.insert(FieldType.getCanonicalType());
575       if (auto *FieldValue = createValueUnlessSelfReferential(
576               FieldType, Visited, Depth + 1, CreatedValuesCount))
577         FieldValues.insert({Field, FieldValue});
578       Visited.erase(FieldType.getCanonicalType());
579     }
580 
581     return &takeOwnership(
582         std::make_unique<StructValue>(std::move(FieldValues)));
583   }
584 
585   return nullptr;
586 }
587 
588 StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const {
589   switch (SP) {
590   case SkipPast::None:
591     return Loc;
592   case SkipPast::Reference:
593     // References cannot be chained so we only need to skip past one level of
594     // indirection.
595     if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc)))
596       return Val->getPointeeLoc();
597     return Loc;
598   case SkipPast::ReferenceThenPointer:
599     StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference);
600     if (auto *Val = dyn_cast_or_null<PointerValue>(getValue(LocPastRef)))
601       return Val->getPointeeLoc();
602     return LocPastRef;
603   }
604   llvm_unreachable("bad SkipPast kind");
605 }
606 
607 const StorageLocation &Environment::skip(const StorageLocation &Loc,
608                                          SkipPast SP) const {
609   return skip(*const_cast<StorageLocation *>(&Loc), SP);
610 }
611 
612 void Environment::addToFlowCondition(BoolValue &Val) {
613   FlowConditionConstraints.insert(&Val);
614 }
615 
616 bool Environment::flowConditionImplies(BoolValue &Val) const {
617   // Returns true if and only if truth assignment of the flow condition implies
618   // that `Val` is also true. We prove whether or not this property holds by
619   // reducing the problem to satisfiability checking. In other words, we attempt
620   // to show that assuming `Val` is false makes the constraints induced by the
621   // flow condition unsatisfiable.
622   llvm::DenseSet<BoolValue *> Constraints = {
623       &makeNot(Val), &getBoolLiteralValue(true),
624       &makeNot(getBoolLiteralValue(false))};
625   Constraints.insert(FlowConditionConstraints.begin(),
626                      FlowConditionConstraints.end());
627   return DACtx->getSolver().solve(std::move(Constraints)) ==
628          Solver::Result::Unsatisfiable;
629 }
630 
631 } // namespace dataflow
632 } // namespace clang
633