xref: /llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (revision 01db10365e935ccca9dc2ed449b23319e170eea0)
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     return &IndVal1->getPointeeLoc() == &IndVal2->getPointeeLoc();
63   }
64 
65   return Model.compareEquivalent(Type, *Val1, Env1, *Val2, Env2);
66 }
67 
68 /// Attempts to merge distinct values `Val1` and `Val1` in `Env1` and `Env2`,
69 /// respectively, of the same type `Type`. Merging generally produces a single
70 /// value that (soundly) approximates the two inputs, although the actual
71 /// meaning depends on `Model`.
72 static Value *mergeDistinctValues(QualType Type, Value *Val1, Environment &Env1,
73                                   Value *Val2, const Environment &Env2,
74                                   Environment::ValueModel &Model) {
75   // Join distinct boolean values preserving information about the constraints
76   // in the respective path conditions. Note: this construction can, in
77   // principle, result in exponential growth in the size of boolean values.
78   // Potential optimizations may be worth considering. For example, represent
79   // the flow condition of each environment using a bool atom and store, in
80   // `DataflowAnalysisContext`, a mapping of bi-conditionals between flow
81   // condition atoms and flow condition constraints. Something like:
82   // \code
83   //   FC1 <=> C1 ^ C2
84   //   FC2 <=> C2 ^ C3 ^ C4
85   //   FC3 <=> (FC1 v FC2) ^ C5
86   // \code
87   // Then, we can track dependencies between flow conditions (e.g. above `FC3`
88   // depends on `FC1` and `FC2`) and modify `flowConditionImplies` to construct
89   // a formula that includes the bi-conditionals for all flow condition atoms in
90   // the transitive set, before invoking the solver.
91   if (auto *Expr1 = dyn_cast<BoolValue>(Val1)) {
92     for (BoolValue *Constraint : Env1.getFlowConditionConstraints()) {
93       Expr1 = &Env1.makeAnd(*Expr1, *Constraint);
94     }
95     auto *Expr2 = cast<BoolValue>(Val2);
96     for (BoolValue *Constraint : Env2.getFlowConditionConstraints()) {
97       Expr2 = &Env1.makeAnd(*Expr2, *Constraint);
98     }
99     return &Env1.makeOr(*Expr1, *Expr2);
100   }
101 
102   // FIXME: Consider destroying `MergedValue` immediately if `ValueModel::merge`
103   // returns false to avoid storing unneeded values in `DACtx`.
104   if (Value *MergedVal = Env1.createValue(Type))
105     if (Model.merge(Type, *Val1, Env1, *Val2, Env2, *MergedVal, Env1))
106       return MergedVal;
107 
108   return nullptr;
109 }
110 
111 /// Initializes a global storage value.
112 static void initGlobalVar(const VarDecl &D, Environment &Env) {
113   if (!D.hasGlobalStorage() ||
114       Env.getStorageLocation(D, SkipPast::None) != nullptr)
115     return;
116 
117   auto &Loc = Env.createStorageLocation(D);
118   Env.setStorageLocation(D, Loc);
119   if (auto *Val = Env.createValue(D.getType()))
120     Env.setValue(Loc, *Val);
121 }
122 
123 /// Initializes a global storage value.
124 static void initGlobalVar(const Decl &D, Environment &Env) {
125   if (auto *V = dyn_cast<VarDecl>(&D))
126     initGlobalVar(*V, Env);
127 }
128 
129 /// Initializes global storage values that are declared or referenced from
130 /// sub-statements of `S`.
131 // FIXME: Add support for resetting globals after function calls to enable
132 // the implementation of sound analyses.
133 static void initGlobalVars(const Stmt &S, Environment &Env) {
134   for (auto *Child : S.children()) {
135     if (Child != nullptr)
136       initGlobalVars(*Child, Env);
137   }
138 
139   if (auto *DS = dyn_cast<DeclStmt>(&S)) {
140     if (DS->isSingleDecl()) {
141       initGlobalVar(*DS->getSingleDecl(), Env);
142     } else {
143       for (auto *D : DS->getDeclGroup())
144         initGlobalVar(*D, Env);
145     }
146   } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) {
147     initGlobalVar(*E->getDecl(), Env);
148   } else if (auto *E = dyn_cast<MemberExpr>(&S)) {
149     initGlobalVar(*E->getMemberDecl(), Env);
150   }
151 }
152 
153 /// Returns constraints that represent the disjunction of `Constraints1` and
154 /// `Constraints2`.
155 ///
156 /// Requirements:
157 ///
158 ///  The elements of `Constraints1` and `Constraints2` must not be null.
159 llvm::DenseSet<BoolValue *>
160 joinConstraints(DataflowAnalysisContext *Context,
161                 const llvm::DenseSet<BoolValue *> &Constraints1,
162                 const llvm::DenseSet<BoolValue *> &Constraints2) {
163   // `(X ^ Y) v (X ^ Z)` is logically equivalent to `X ^ (Y v Z)`. Therefore, to
164   // avoid unnecessarily expanding the resulting set of constraints, we will add
165   // all common constraints of `Constraints1` and `Constraints2` directly and
166   // add a disjunction of the constraints that are not common.
167 
168   llvm::DenseSet<BoolValue *> JoinedConstraints;
169 
170   if (Constraints1.empty() || Constraints2.empty()) {
171     // Disjunction of empty set and non-empty set is represented as empty set.
172     return JoinedConstraints;
173   }
174 
175   BoolValue *Val1 = nullptr;
176   for (BoolValue *Constraint : Constraints1) {
177     if (Constraints2.contains(Constraint)) {
178       // Add common constraints directly to `JoinedConstraints`.
179       JoinedConstraints.insert(Constraint);
180     } else if (Val1 == nullptr) {
181       Val1 = Constraint;
182     } else {
183       Val1 = &Context->getOrCreateConjunctionValue(*Val1, *Constraint);
184     }
185   }
186 
187   BoolValue *Val2 = nullptr;
188   for (BoolValue *Constraint : Constraints2) {
189     // Common constraints are added to `JoinedConstraints` above.
190     if (Constraints1.contains(Constraint)) {
191       continue;
192     }
193     if (Val2 == nullptr) {
194       Val2 = Constraint;
195     } else {
196       Val2 = &Context->getOrCreateConjunctionValue(*Val2, *Constraint);
197     }
198   }
199 
200   // An empty set of constraints (represented as a null value) is interpreted as
201   // `true` and `true v X` is logically equivalent to `true` so we need to add a
202   // constraint only if both `Val1` and `Val2` are not null.
203   if (Val1 != nullptr && Val2 != nullptr)
204     JoinedConstraints.insert(
205         &Context->getOrCreateDisjunctionValue(*Val1, *Val2));
206 
207   return JoinedConstraints;
208 }
209 
210 static void
211 getFieldsFromClassHierarchy(QualType Type, bool IgnorePrivateFields,
212                             llvm::DenseSet<const FieldDecl *> &Fields) {
213   if (Type->isIncompleteType() || Type->isDependentType() ||
214       !Type->isRecordType())
215     return;
216 
217   for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
218     if (IgnorePrivateFields &&
219         (Field->getAccess() == AS_private ||
220          (Field->getAccess() == AS_none && Type->getAsRecordDecl()->isClass())))
221       continue;
222     Fields.insert(Field);
223   }
224   if (auto *CXXRecord = Type->getAsCXXRecordDecl()) {
225     for (const CXXBaseSpecifier &Base : CXXRecord->bases()) {
226       // Ignore private fields (including default access in C++ classes) in
227       // base classes, because they are not visible in derived classes.
228       getFieldsFromClassHierarchy(Base.getType(), /*IgnorePrivateFields=*/true,
229                                   Fields);
230     }
231   }
232 }
233 
234 /// Gets the set of all fields accesible from the type.
235 ///
236 /// FIXME: Does not precisely handle non-virtual diamond inheritance. A single
237 /// field decl will be modeled for all instances of the inherited field.
238 static llvm::DenseSet<const FieldDecl *>
239 getAccessibleObjectFields(QualType Type) {
240   llvm::DenseSet<const FieldDecl *> Fields;
241   // Don't ignore private fields for the class itself, only its super classes.
242   getFieldsFromClassHierarchy(Type, /*IgnorePrivateFields=*/false, Fields);
243   return Fields;
244 }
245 
246 Environment::Environment(DataflowAnalysisContext &DACtx,
247                          const DeclContext &DeclCtx)
248     : Environment(DACtx) {
249   if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) {
250     assert(FuncDecl->getBody() != nullptr);
251     initGlobalVars(*FuncDecl->getBody(), *this);
252     for (const auto *ParamDecl : FuncDecl->parameters()) {
253       assert(ParamDecl != nullptr);
254       auto &ParamLoc = createStorageLocation(*ParamDecl);
255       setStorageLocation(*ParamDecl, ParamLoc);
256       if (Value *ParamVal = createValue(ParamDecl->getType()))
257         setValue(ParamLoc, *ParamVal);
258     }
259   }
260 
261   if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) {
262     if (!MethodDecl->isStatic()) {
263       QualType ThisPointeeType = MethodDecl->getThisObjectType();
264       // FIXME: Add support for union types.
265       if (!ThisPointeeType->isUnionType()) {
266         auto &ThisPointeeLoc = createStorageLocation(ThisPointeeType);
267         DACtx.setThisPointeeStorageLocation(ThisPointeeLoc);
268         if (Value *ThisPointeeVal = createValue(ThisPointeeType))
269           setValue(ThisPointeeLoc, *ThisPointeeVal);
270       }
271     }
272   }
273 }
274 
275 bool Environment::equivalentTo(const Environment &Other,
276                                Environment::ValueModel &Model) const {
277   assert(DACtx == Other.DACtx);
278 
279   if (DeclToLoc != Other.DeclToLoc)
280     return false;
281 
282   if (ExprToLoc != Other.ExprToLoc)
283     return false;
284 
285   if (MemberLocToStruct != Other.MemberLocToStruct)
286     return false;
287 
288   if (LocToVal.size() != Other.LocToVal.size())
289     return false;
290 
291   for (auto &Entry : LocToVal) {
292     const StorageLocation *Loc = Entry.first;
293     assert(Loc != nullptr);
294 
295     Value *Val = Entry.second;
296     assert(Val != nullptr);
297 
298     auto It = Other.LocToVal.find(Loc);
299     if (It == Other.LocToVal.end())
300       return false;
301     assert(It->second != nullptr);
302 
303     if (!equivalentValues(Loc->getType(), Val, *this, It->second, Other, Model))
304       return false;
305   }
306 
307   return true;
308 }
309 
310 LatticeJoinEffect Environment::join(const Environment &Other,
311                                     Environment::ValueModel &Model) {
312   assert(DACtx == Other.DACtx);
313 
314   auto Effect = LatticeJoinEffect::Unchanged;
315 
316   const unsigned DeclToLocSizeBefore = DeclToLoc.size();
317   DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc);
318   if (DeclToLocSizeBefore != DeclToLoc.size())
319     Effect = LatticeJoinEffect::Changed;
320 
321   const unsigned ExprToLocSizeBefore = ExprToLoc.size();
322   ExprToLoc = intersectDenseMaps(ExprToLoc, Other.ExprToLoc);
323   if (ExprToLocSizeBefore != ExprToLoc.size())
324     Effect = LatticeJoinEffect::Changed;
325 
326   const unsigned MemberLocToStructSizeBefore = MemberLocToStruct.size();
327   MemberLocToStruct =
328       intersectDenseMaps(MemberLocToStruct, Other.MemberLocToStruct);
329   if (MemberLocToStructSizeBefore != MemberLocToStruct.size())
330     Effect = LatticeJoinEffect::Changed;
331 
332   // Move `LocToVal` so that `Environment::ValueModel::merge` can safely assign
333   // values to storage locations while this code iterates over the current
334   // assignments.
335   llvm::DenseMap<const StorageLocation *, Value *> OldLocToVal =
336       std::move(LocToVal);
337   for (auto &Entry : OldLocToVal) {
338     const StorageLocation *Loc = Entry.first;
339     assert(Loc != nullptr);
340 
341     Value *Val = Entry.second;
342     assert(Val != nullptr);
343 
344     auto It = Other.LocToVal.find(Loc);
345     if (It == Other.LocToVal.end())
346       continue;
347     assert(It->second != nullptr);
348 
349     if (equivalentValues(Loc->getType(), Val, *this, It->second, Other,
350                          Model)) {
351       LocToVal.insert({Loc, Val});
352       continue;
353     }
354 
355     if (Value *MergedVal = mergeDistinctValues(Loc->getType(), Val, *this,
356                                                It->second, Other, Model))
357       LocToVal.insert({Loc, MergedVal});
358   }
359   if (OldLocToVal.size() != LocToVal.size())
360     Effect = LatticeJoinEffect::Changed;
361 
362   FlowConditionConstraints = joinConstraints(DACtx, FlowConditionConstraints,
363                                              Other.FlowConditionConstraints);
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: "
491                  << Type.getAsString() << "\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