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