xref: /freebsd-src/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (revision 1fd87a682ad7442327078e1eeb63edc4258f9815)
104eeddc0SDimitry Andric //===-- DataflowEnvironment.cpp ---------------------------------*- C++ -*-===//
204eeddc0SDimitry Andric //
304eeddc0SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
404eeddc0SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
504eeddc0SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
604eeddc0SDimitry Andric //
704eeddc0SDimitry Andric //===----------------------------------------------------------------------===//
804eeddc0SDimitry Andric //
904eeddc0SDimitry Andric //  This file defines an Environment class that is used by dataflow analyses
1004eeddc0SDimitry Andric //  that run over Control-Flow Graphs (CFGs) to keep track of the state of the
1104eeddc0SDimitry Andric //  program at given program points.
1204eeddc0SDimitry Andric //
1304eeddc0SDimitry Andric //===----------------------------------------------------------------------===//
1404eeddc0SDimitry Andric 
1504eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
1604eeddc0SDimitry Andric #include "clang/AST/Decl.h"
1704eeddc0SDimitry Andric #include "clang/AST/DeclCXX.h"
1804eeddc0SDimitry Andric #include "clang/AST/Type.h"
1904eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
2004eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/StorageLocation.h"
2104eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h"
2204eeddc0SDimitry Andric #include "llvm/ADT/DenseMap.h"
2304eeddc0SDimitry Andric #include "llvm/ADT/DenseSet.h"
2404eeddc0SDimitry Andric #include "llvm/Support/ErrorHandling.h"
2504eeddc0SDimitry Andric #include <memory>
2604eeddc0SDimitry Andric #include <utility>
2704eeddc0SDimitry Andric 
2804eeddc0SDimitry Andric namespace clang {
2904eeddc0SDimitry Andric namespace dataflow {
3004eeddc0SDimitry Andric 
3104eeddc0SDimitry Andric /// Returns a map consisting of key-value entries that are present in both maps.
3204eeddc0SDimitry Andric template <typename K, typename V>
3304eeddc0SDimitry Andric llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1,
3404eeddc0SDimitry Andric                                         const llvm::DenseMap<K, V> &Map2) {
3504eeddc0SDimitry Andric   llvm::DenseMap<K, V> Result;
3604eeddc0SDimitry Andric   for (auto &Entry : Map1) {
3704eeddc0SDimitry Andric     auto It = Map2.find(Entry.first);
3804eeddc0SDimitry Andric     if (It != Map2.end() && Entry.second == It->second)
3904eeddc0SDimitry Andric       Result.insert({Entry.first, Entry.second});
4004eeddc0SDimitry Andric   }
4104eeddc0SDimitry Andric   return Result;
4204eeddc0SDimitry Andric }
4304eeddc0SDimitry Andric 
44*1fd87a68SDimitry Andric /// Returns true if and only if `Val1` is equivalent to `Val2`.
45*1fd87a68SDimitry Andric static bool equivalentValues(QualType Type, Value *Val1, Value *Val2,
46*1fd87a68SDimitry Andric                              Environment::ValueModel &Model) {
47*1fd87a68SDimitry Andric   if (Val1 == Val2)
48*1fd87a68SDimitry Andric     return true;
49*1fd87a68SDimitry Andric 
50*1fd87a68SDimitry Andric   if (auto *IndVal1 = dyn_cast<IndirectionValue>(Val1)) {
51*1fd87a68SDimitry Andric     auto *IndVal2 = cast<IndirectionValue>(Val2);
52*1fd87a68SDimitry Andric     assert(IndVal1->getKind() == IndVal2->getKind());
53*1fd87a68SDimitry Andric     return &IndVal1->getPointeeLoc() == &IndVal2->getPointeeLoc();
54*1fd87a68SDimitry Andric   }
55*1fd87a68SDimitry Andric 
56*1fd87a68SDimitry Andric   return Model.compareEquivalent(Type, *Val1, *Val2);
57*1fd87a68SDimitry Andric }
58*1fd87a68SDimitry Andric 
5904eeddc0SDimitry Andric Environment::Environment(DataflowAnalysisContext &DACtx,
6004eeddc0SDimitry Andric                          const DeclContext &DeclCtx)
6104eeddc0SDimitry Andric     : Environment(DACtx) {
6204eeddc0SDimitry Andric   if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) {
6304eeddc0SDimitry Andric     for (const auto *ParamDecl : FuncDecl->parameters()) {
6404eeddc0SDimitry Andric       assert(ParamDecl != nullptr);
6504eeddc0SDimitry Andric       auto &ParamLoc = createStorageLocation(*ParamDecl);
6604eeddc0SDimitry Andric       setStorageLocation(*ParamDecl, ParamLoc);
6704eeddc0SDimitry Andric       if (Value *ParamVal = createValue(ParamDecl->getType()))
6804eeddc0SDimitry Andric         setValue(ParamLoc, *ParamVal);
6904eeddc0SDimitry Andric     }
7004eeddc0SDimitry Andric   }
7104eeddc0SDimitry Andric 
7204eeddc0SDimitry Andric   if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) {
7304eeddc0SDimitry Andric     if (!MethodDecl->isStatic()) {
7404eeddc0SDimitry Andric       QualType ThisPointeeType = MethodDecl->getThisObjectType();
7504eeddc0SDimitry Andric       // FIXME: Add support for union types.
7604eeddc0SDimitry Andric       if (!ThisPointeeType->isUnionType()) {
7704eeddc0SDimitry Andric         auto &ThisPointeeLoc = createStorageLocation(ThisPointeeType);
7804eeddc0SDimitry Andric         DACtx.setThisPointeeStorageLocation(ThisPointeeLoc);
7904eeddc0SDimitry Andric         if (Value *ThisPointeeVal = createValue(ThisPointeeType))
8004eeddc0SDimitry Andric           setValue(ThisPointeeLoc, *ThisPointeeVal);
8104eeddc0SDimitry Andric       }
8204eeddc0SDimitry Andric     }
8304eeddc0SDimitry Andric   }
8404eeddc0SDimitry Andric }
8504eeddc0SDimitry Andric 
86*1fd87a68SDimitry Andric bool Environment::equivalentTo(const Environment &Other,
87*1fd87a68SDimitry Andric                                Environment::ValueModel &Model) const {
8804eeddc0SDimitry Andric   assert(DACtx == Other.DACtx);
89*1fd87a68SDimitry Andric 
90*1fd87a68SDimitry Andric   if (DeclToLoc != Other.DeclToLoc)
91*1fd87a68SDimitry Andric     return false;
92*1fd87a68SDimitry Andric 
93*1fd87a68SDimitry Andric   if (ExprToLoc != Other.ExprToLoc)
94*1fd87a68SDimitry Andric     return false;
95*1fd87a68SDimitry Andric 
96*1fd87a68SDimitry Andric   if (LocToVal.size() != Other.LocToVal.size())
97*1fd87a68SDimitry Andric     return false;
98*1fd87a68SDimitry Andric 
99*1fd87a68SDimitry Andric   for (auto &Entry : LocToVal) {
100*1fd87a68SDimitry Andric     const StorageLocation *Loc = Entry.first;
101*1fd87a68SDimitry Andric     assert(Loc != nullptr);
102*1fd87a68SDimitry Andric 
103*1fd87a68SDimitry Andric     Value *Val = Entry.second;
104*1fd87a68SDimitry Andric     assert(Val != nullptr);
105*1fd87a68SDimitry Andric 
106*1fd87a68SDimitry Andric     auto It = Other.LocToVal.find(Loc);
107*1fd87a68SDimitry Andric     if (It == Other.LocToVal.end())
108*1fd87a68SDimitry Andric       return false;
109*1fd87a68SDimitry Andric     assert(It->second != nullptr);
110*1fd87a68SDimitry Andric 
111*1fd87a68SDimitry Andric     if (!equivalentValues(Loc->getType(), Val, It->second, Model))
112*1fd87a68SDimitry Andric       return false;
113*1fd87a68SDimitry Andric   }
114*1fd87a68SDimitry Andric 
115*1fd87a68SDimitry Andric   return true;
11604eeddc0SDimitry Andric }
11704eeddc0SDimitry Andric 
11804eeddc0SDimitry Andric LatticeJoinEffect Environment::join(const Environment &Other,
119*1fd87a68SDimitry Andric                                     Environment::ValueModel &Model) {
12004eeddc0SDimitry Andric   assert(DACtx == Other.DACtx);
12104eeddc0SDimitry Andric 
12204eeddc0SDimitry Andric   auto Effect = LatticeJoinEffect::Unchanged;
12304eeddc0SDimitry Andric 
12404eeddc0SDimitry Andric   const unsigned DeclToLocSizeBefore = DeclToLoc.size();
12504eeddc0SDimitry Andric   DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc);
12604eeddc0SDimitry Andric   if (DeclToLocSizeBefore != DeclToLoc.size())
12704eeddc0SDimitry Andric     Effect = LatticeJoinEffect::Changed;
12804eeddc0SDimitry Andric 
12904eeddc0SDimitry Andric   const unsigned ExprToLocSizeBefore = ExprToLoc.size();
13004eeddc0SDimitry Andric   ExprToLoc = intersectDenseMaps(ExprToLoc, Other.ExprToLoc);
13104eeddc0SDimitry Andric   if (ExprToLocSizeBefore != ExprToLoc.size())
13204eeddc0SDimitry Andric     Effect = LatticeJoinEffect::Changed;
13304eeddc0SDimitry Andric 
134*1fd87a68SDimitry Andric   // Move `LocToVal` so that `Environment::ValueModel::merge` can safely assign
135*1fd87a68SDimitry Andric   // values to storage locations while this code iterates over the current
136*1fd87a68SDimitry Andric   // assignments.
137*1fd87a68SDimitry Andric   llvm::DenseMap<const StorageLocation *, Value *> OldLocToVal =
138*1fd87a68SDimitry Andric       std::move(LocToVal);
139*1fd87a68SDimitry Andric   for (auto &Entry : OldLocToVal) {
14004eeddc0SDimitry Andric     const StorageLocation *Loc = Entry.first;
14104eeddc0SDimitry Andric     assert(Loc != nullptr);
14204eeddc0SDimitry Andric 
14304eeddc0SDimitry Andric     Value *Val = Entry.second;
14404eeddc0SDimitry Andric     assert(Val != nullptr);
14504eeddc0SDimitry Andric 
14604eeddc0SDimitry Andric     auto It = Other.LocToVal.find(Loc);
14704eeddc0SDimitry Andric     if (It == Other.LocToVal.end())
14804eeddc0SDimitry Andric       continue;
14904eeddc0SDimitry Andric     assert(It->second != nullptr);
15004eeddc0SDimitry Andric 
151*1fd87a68SDimitry Andric     if (equivalentValues(Loc->getType(), Val, It->second, Model)) {
152*1fd87a68SDimitry Andric       LocToVal.insert({Loc, Val});
15304eeddc0SDimitry Andric       continue;
15404eeddc0SDimitry Andric     }
15504eeddc0SDimitry Andric 
156*1fd87a68SDimitry Andric     // FIXME: Consider destroying `MergedValue` immediately if
157*1fd87a68SDimitry Andric     // `ValueModel::merge` returns false to avoid storing unneeded values in
158*1fd87a68SDimitry Andric     // `DACtx`.
15904eeddc0SDimitry Andric     if (Value *MergedVal = createValue(Loc->getType()))
160*1fd87a68SDimitry Andric       if (Model.merge(Loc->getType(), *Val, *It->second, *MergedVal, *this))
161*1fd87a68SDimitry Andric         LocToVal.insert({Loc, MergedVal});
16204eeddc0SDimitry Andric   }
163*1fd87a68SDimitry Andric   if (OldLocToVal.size() != LocToVal.size())
16404eeddc0SDimitry Andric     Effect = LatticeJoinEffect::Changed;
16504eeddc0SDimitry Andric 
16604eeddc0SDimitry Andric   return Effect;
16704eeddc0SDimitry Andric }
16804eeddc0SDimitry Andric 
16904eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(QualType Type) {
17004eeddc0SDimitry Andric   assert(!Type.isNull());
17104eeddc0SDimitry Andric   if (Type->isStructureOrClassType() || Type->isUnionType()) {
17204eeddc0SDimitry Andric     // FIXME: Explore options to avoid eager initialization of fields as some of
17304eeddc0SDimitry Andric     // them might not be needed for a particular analysis.
17404eeddc0SDimitry Andric     llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
17504eeddc0SDimitry Andric     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
17604eeddc0SDimitry Andric       FieldLocs.insert({Field, &createStorageLocation(Field->getType())});
17704eeddc0SDimitry Andric     }
17804eeddc0SDimitry Andric     return takeOwnership(
17904eeddc0SDimitry Andric         std::make_unique<AggregateStorageLocation>(Type, std::move(FieldLocs)));
18004eeddc0SDimitry Andric   }
18104eeddc0SDimitry Andric   return takeOwnership(std::make_unique<ScalarStorageLocation>(Type));
18204eeddc0SDimitry Andric }
18304eeddc0SDimitry Andric 
18404eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const VarDecl &D) {
18504eeddc0SDimitry Andric   // Evaluated declarations are always assigned the same storage locations to
18604eeddc0SDimitry Andric   // ensure that the environment stabilizes across loop iterations. Storage
18704eeddc0SDimitry Andric   // locations for evaluated declarations are stored in the analysis context.
18804eeddc0SDimitry Andric   if (auto *Loc = DACtx->getStorageLocation(D))
18904eeddc0SDimitry Andric     return *Loc;
19004eeddc0SDimitry Andric   auto &Loc = createStorageLocation(D.getType());
19104eeddc0SDimitry Andric   DACtx->setStorageLocation(D, Loc);
19204eeddc0SDimitry Andric   return Loc;
19304eeddc0SDimitry Andric }
19404eeddc0SDimitry Andric 
19504eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const Expr &E) {
19604eeddc0SDimitry Andric   // Evaluated expressions are always assigned the same storage locations to
19704eeddc0SDimitry Andric   // ensure that the environment stabilizes across loop iterations. Storage
19804eeddc0SDimitry Andric   // locations for evaluated expressions are stored in the analysis context.
19904eeddc0SDimitry Andric   if (auto *Loc = DACtx->getStorageLocation(E))
20004eeddc0SDimitry Andric     return *Loc;
20104eeddc0SDimitry Andric   auto &Loc = createStorageLocation(E.getType());
20204eeddc0SDimitry Andric   DACtx->setStorageLocation(E, Loc);
20304eeddc0SDimitry Andric   return Loc;
20404eeddc0SDimitry Andric }
20504eeddc0SDimitry Andric 
20604eeddc0SDimitry Andric void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
20704eeddc0SDimitry Andric   assert(DeclToLoc.find(&D) == DeclToLoc.end());
20804eeddc0SDimitry Andric   DeclToLoc[&D] = &Loc;
20904eeddc0SDimitry Andric }
21004eeddc0SDimitry Andric 
21104eeddc0SDimitry Andric StorageLocation *Environment::getStorageLocation(const ValueDecl &D,
21204eeddc0SDimitry Andric                                                  SkipPast SP) const {
21304eeddc0SDimitry Andric   auto It = DeclToLoc.find(&D);
21404eeddc0SDimitry Andric   return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP);
21504eeddc0SDimitry Andric }
21604eeddc0SDimitry Andric 
21704eeddc0SDimitry Andric void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
21804eeddc0SDimitry Andric   assert(ExprToLoc.find(&E) == ExprToLoc.end());
21904eeddc0SDimitry Andric   ExprToLoc[&E] = &Loc;
22004eeddc0SDimitry Andric }
22104eeddc0SDimitry Andric 
22204eeddc0SDimitry Andric StorageLocation *Environment::getStorageLocation(const Expr &E,
22304eeddc0SDimitry Andric                                                  SkipPast SP) const {
22404eeddc0SDimitry Andric   auto It = ExprToLoc.find(&E);
22504eeddc0SDimitry Andric   return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP);
22604eeddc0SDimitry Andric }
22704eeddc0SDimitry Andric 
22804eeddc0SDimitry Andric StorageLocation *Environment::getThisPointeeStorageLocation() const {
22904eeddc0SDimitry Andric   return DACtx->getThisPointeeStorageLocation();
23004eeddc0SDimitry Andric }
23104eeddc0SDimitry Andric 
23204eeddc0SDimitry Andric void Environment::setValue(const StorageLocation &Loc, Value &Val) {
23304eeddc0SDimitry Andric   LocToVal[&Loc] = &Val;
23404eeddc0SDimitry Andric 
23504eeddc0SDimitry Andric   if (auto *StructVal = dyn_cast<StructValue>(&Val)) {
23604eeddc0SDimitry Andric     auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc);
23704eeddc0SDimitry Andric 
23804eeddc0SDimitry Andric     const QualType Type = AggregateLoc.getType();
23904eeddc0SDimitry Andric     assert(Type->isStructureOrClassType());
24004eeddc0SDimitry Andric 
24104eeddc0SDimitry Andric     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
24204eeddc0SDimitry Andric       assert(Field != nullptr);
24304eeddc0SDimitry Andric       setValue(AggregateLoc.getChild(*Field), StructVal->getChild(*Field));
24404eeddc0SDimitry Andric     }
24504eeddc0SDimitry Andric   }
24604eeddc0SDimitry Andric }
24704eeddc0SDimitry Andric 
24804eeddc0SDimitry Andric Value *Environment::getValue(const StorageLocation &Loc) const {
24904eeddc0SDimitry Andric   auto It = LocToVal.find(&Loc);
25004eeddc0SDimitry Andric   return It == LocToVal.end() ? nullptr : It->second;
25104eeddc0SDimitry Andric }
25204eeddc0SDimitry Andric 
25304eeddc0SDimitry Andric Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const {
25404eeddc0SDimitry Andric   auto *Loc = getStorageLocation(D, SP);
25504eeddc0SDimitry Andric   if (Loc == nullptr)
25604eeddc0SDimitry Andric     return nullptr;
25704eeddc0SDimitry Andric   return getValue(*Loc);
25804eeddc0SDimitry Andric }
25904eeddc0SDimitry Andric 
26004eeddc0SDimitry Andric Value *Environment::getValue(const Expr &E, SkipPast SP) const {
26104eeddc0SDimitry Andric   auto *Loc = getStorageLocation(E, SP);
26204eeddc0SDimitry Andric   if (Loc == nullptr)
26304eeddc0SDimitry Andric     return nullptr;
26404eeddc0SDimitry Andric   return getValue(*Loc);
26504eeddc0SDimitry Andric }
26604eeddc0SDimitry Andric 
26704eeddc0SDimitry Andric Value *Environment::createValue(QualType Type) {
26804eeddc0SDimitry Andric   llvm::DenseSet<QualType> Visited;
26904eeddc0SDimitry Andric   return createValueUnlessSelfReferential(Type, Visited);
27004eeddc0SDimitry Andric }
27104eeddc0SDimitry Andric 
27204eeddc0SDimitry Andric Value *Environment::createValueUnlessSelfReferential(
27304eeddc0SDimitry Andric     QualType Type, llvm::DenseSet<QualType> &Visited) {
27404eeddc0SDimitry Andric   assert(!Type.isNull());
27504eeddc0SDimitry Andric 
27604eeddc0SDimitry Andric   if (Type->isIntegerType()) {
27704eeddc0SDimitry Andric     return &takeOwnership(std::make_unique<IntegerValue>());
27804eeddc0SDimitry Andric   }
27904eeddc0SDimitry Andric 
28004eeddc0SDimitry Andric   if (Type->isReferenceType()) {
28104eeddc0SDimitry Andric     QualType PointeeType = Type->getAs<ReferenceType>()->getPointeeType();
28204eeddc0SDimitry Andric     auto &PointeeLoc = createStorageLocation(PointeeType);
28304eeddc0SDimitry Andric 
28404eeddc0SDimitry Andric     if (!Visited.contains(PointeeType.getCanonicalType())) {
28504eeddc0SDimitry Andric       Visited.insert(PointeeType.getCanonicalType());
28604eeddc0SDimitry Andric       Value *PointeeVal =
28704eeddc0SDimitry Andric           createValueUnlessSelfReferential(PointeeType, Visited);
28804eeddc0SDimitry Andric       Visited.erase(PointeeType.getCanonicalType());
28904eeddc0SDimitry Andric 
29004eeddc0SDimitry Andric       if (PointeeVal != nullptr)
29104eeddc0SDimitry Andric         setValue(PointeeLoc, *PointeeVal);
29204eeddc0SDimitry Andric     }
29304eeddc0SDimitry Andric 
29404eeddc0SDimitry Andric     return &takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc));
29504eeddc0SDimitry Andric   }
29604eeddc0SDimitry Andric 
29704eeddc0SDimitry Andric   if (Type->isPointerType()) {
29804eeddc0SDimitry Andric     QualType PointeeType = Type->getAs<PointerType>()->getPointeeType();
29904eeddc0SDimitry Andric     auto &PointeeLoc = createStorageLocation(PointeeType);
30004eeddc0SDimitry Andric 
30104eeddc0SDimitry Andric     if (!Visited.contains(PointeeType.getCanonicalType())) {
30204eeddc0SDimitry Andric       Visited.insert(PointeeType.getCanonicalType());
30304eeddc0SDimitry Andric       Value *PointeeVal =
30404eeddc0SDimitry Andric           createValueUnlessSelfReferential(PointeeType, Visited);
30504eeddc0SDimitry Andric       Visited.erase(PointeeType.getCanonicalType());
30604eeddc0SDimitry Andric 
30704eeddc0SDimitry Andric       if (PointeeVal != nullptr)
30804eeddc0SDimitry Andric         setValue(PointeeLoc, *PointeeVal);
30904eeddc0SDimitry Andric     }
31004eeddc0SDimitry Andric 
31104eeddc0SDimitry Andric     return &takeOwnership(std::make_unique<PointerValue>(PointeeLoc));
31204eeddc0SDimitry Andric   }
31304eeddc0SDimitry Andric 
31404eeddc0SDimitry Andric   if (Type->isStructureOrClassType()) {
31504eeddc0SDimitry Andric     // FIXME: Initialize only fields that are accessed in the context that is
31604eeddc0SDimitry Andric     // being analyzed.
31704eeddc0SDimitry Andric     llvm::DenseMap<const ValueDecl *, Value *> FieldValues;
31804eeddc0SDimitry Andric     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
31904eeddc0SDimitry Andric       assert(Field != nullptr);
32004eeddc0SDimitry Andric 
32104eeddc0SDimitry Andric       QualType FieldType = Field->getType();
32204eeddc0SDimitry Andric       if (Visited.contains(FieldType.getCanonicalType()))
32304eeddc0SDimitry Andric         continue;
32404eeddc0SDimitry Andric 
32504eeddc0SDimitry Andric       Visited.insert(FieldType.getCanonicalType());
32604eeddc0SDimitry Andric       FieldValues.insert(
32704eeddc0SDimitry Andric           {Field, createValueUnlessSelfReferential(FieldType, Visited)});
32804eeddc0SDimitry Andric       Visited.erase(FieldType.getCanonicalType());
32904eeddc0SDimitry Andric     }
33004eeddc0SDimitry Andric 
33104eeddc0SDimitry Andric     return &takeOwnership(
33204eeddc0SDimitry Andric         std::make_unique<StructValue>(std::move(FieldValues)));
33304eeddc0SDimitry Andric   }
33404eeddc0SDimitry Andric 
33504eeddc0SDimitry Andric   return nullptr;
33604eeddc0SDimitry Andric }
33704eeddc0SDimitry Andric 
33804eeddc0SDimitry Andric StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const {
33904eeddc0SDimitry Andric   switch (SP) {
34004eeddc0SDimitry Andric   case SkipPast::None:
34104eeddc0SDimitry Andric     return Loc;
34204eeddc0SDimitry Andric   case SkipPast::Reference:
34304eeddc0SDimitry Andric     // References cannot be chained so we only need to skip past one level of
34404eeddc0SDimitry Andric     // indirection.
34504eeddc0SDimitry Andric     if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc)))
34604eeddc0SDimitry Andric       return Val->getPointeeLoc();
34704eeddc0SDimitry Andric     return Loc;
34804eeddc0SDimitry Andric   case SkipPast::ReferenceThenPointer:
34904eeddc0SDimitry Andric     StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference);
35004eeddc0SDimitry Andric     if (auto *Val = dyn_cast_or_null<PointerValue>(getValue(LocPastRef)))
35104eeddc0SDimitry Andric       return Val->getPointeeLoc();
35204eeddc0SDimitry Andric     return LocPastRef;
35304eeddc0SDimitry Andric   }
35404eeddc0SDimitry Andric   llvm_unreachable("bad SkipPast kind");
35504eeddc0SDimitry Andric }
35604eeddc0SDimitry Andric 
35704eeddc0SDimitry Andric const StorageLocation &Environment::skip(const StorageLocation &Loc,
35804eeddc0SDimitry Andric                                          SkipPast SP) const {
35904eeddc0SDimitry Andric   return skip(*const_cast<StorageLocation *>(&Loc), SP);
36004eeddc0SDimitry Andric }
36104eeddc0SDimitry Andric 
36204eeddc0SDimitry Andric } // namespace dataflow
36304eeddc0SDimitry Andric } // namespace clang
364