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