xref: /llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (revision 188d28f73cc7b7891c182a85fdb6e274123b5b69)
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 <memory>
26 #include <utility>
27 
28 namespace clang {
29 namespace dataflow {
30 
31 /// Returns a map consisting of key-value entries that are present in both maps.
32 template <typename K, typename V>
33 llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1,
34                                         const llvm::DenseMap<K, V> &Map2) {
35   llvm::DenseMap<K, V> Result;
36   for (auto &Entry : Map1) {
37     auto It = Map2.find(Entry.first);
38     if (It != Map2.end() && Entry.second == It->second)
39       Result.insert({Entry.first, Entry.second});
40   }
41   return Result;
42 }
43 
44 Environment::Environment(DataflowAnalysisContext &DACtx,
45                          const DeclContext &DeclCtx)
46     : Environment(DACtx) {
47   if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) {
48     for (const auto *ParamDecl : FuncDecl->parameters()) {
49       assert(ParamDecl != nullptr);
50       auto &ParamLoc = createStorageLocation(*ParamDecl);
51       setStorageLocation(*ParamDecl, ParamLoc);
52       if (Value *ParamVal = createValue(ParamDecl->getType()))
53         setValue(ParamLoc, *ParamVal);
54     }
55   }
56 
57   if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) {
58     if (!MethodDecl->isStatic()) {
59       QualType ThisPointeeType = MethodDecl->getThisObjectType();
60       // FIXME: Add support for union types.
61       if (!ThisPointeeType->isUnionType()) {
62         auto &ThisPointeeLoc = createStorageLocation(ThisPointeeType);
63         DACtx.setThisPointeeStorageLocation(ThisPointeeLoc);
64         if (Value *ThisPointeeVal = createValue(ThisPointeeType))
65           setValue(ThisPointeeLoc, *ThisPointeeVal);
66       }
67     }
68   }
69 }
70 
71 bool Environment::operator==(const Environment &Other) const {
72   assert(DACtx == Other.DACtx);
73   return DeclToLoc == Other.DeclToLoc && LocToVal == Other.LocToVal;
74 }
75 
76 LatticeJoinEffect Environment::join(const Environment &Other) {
77   assert(DACtx == Other.DACtx);
78 
79   auto Effect = LatticeJoinEffect::Unchanged;
80 
81   const unsigned DeclToLocSizeBefore = DeclToLoc.size();
82   DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc);
83   if (DeclToLocSizeBefore != DeclToLoc.size())
84     Effect = LatticeJoinEffect::Changed;
85 
86   const unsigned ExprToLocSizeBefore = ExprToLoc.size();
87   ExprToLoc = intersectDenseMaps(ExprToLoc, Other.ExprToLoc);
88   if (ExprToLocSizeBefore != ExprToLoc.size())
89     Effect = LatticeJoinEffect::Changed;
90 
91   // FIXME: Add support for joining distinct values that are assigned to the
92   // same storage locations in `LocToVal` and `Other.LocToVal`.
93   const unsigned LocToValSizeBefore = LocToVal.size();
94   LocToVal = intersectDenseMaps(LocToVal, Other.LocToVal);
95   if (LocToValSizeBefore != LocToVal.size())
96     Effect = LatticeJoinEffect::Changed;
97 
98   return Effect;
99 }
100 
101 StorageLocation &Environment::createStorageLocation(QualType Type) {
102   assert(!Type.isNull());
103   if (Type->isStructureOrClassType() || Type->isUnionType()) {
104     // FIXME: Explore options to avoid eager initialization of fields as some of
105     // them might not be needed for a particular analysis.
106     llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
107     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
108       FieldLocs.insert({Field, &createStorageLocation(Field->getType())});
109     }
110     return takeOwnership(
111         std::make_unique<AggregateStorageLocation>(Type, std::move(FieldLocs)));
112   }
113   return takeOwnership(std::make_unique<ScalarStorageLocation>(Type));
114 }
115 
116 StorageLocation &Environment::createStorageLocation(const VarDecl &D) {
117   // Evaluated declarations are always assigned the same storage locations to
118   // ensure that the environment stabilizes across loop iterations. Storage
119   // locations for evaluated declarations are stored in the analysis context.
120   if (auto *Loc = DACtx->getStorageLocation(D))
121     return *Loc;
122   auto &Loc = createStorageLocation(D.getType());
123   DACtx->setStorageLocation(D, Loc);
124   return Loc;
125 }
126 
127 StorageLocation &Environment::createStorageLocation(const Expr &E) {
128   // Evaluated expressions are always assigned the same storage locations to
129   // ensure that the environment stabilizes across loop iterations. Storage
130   // locations for evaluated expressions are stored in the analysis context.
131   if (auto *Loc = DACtx->getStorageLocation(E))
132     return *Loc;
133   auto &Loc = createStorageLocation(E.getType());
134   DACtx->setStorageLocation(E, Loc);
135   return Loc;
136 }
137 
138 void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
139   assert(DeclToLoc.find(&D) == DeclToLoc.end());
140   DeclToLoc[&D] = &Loc;
141 }
142 
143 StorageLocation *Environment::getStorageLocation(const ValueDecl &D,
144                                                  SkipPast SP) const {
145   auto It = DeclToLoc.find(&D);
146   return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP);
147 }
148 
149 void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
150   assert(ExprToLoc.find(&E) == ExprToLoc.end());
151   ExprToLoc[&E] = &Loc;
152 }
153 
154 StorageLocation *Environment::getStorageLocation(const Expr &E,
155                                                  SkipPast SP) const {
156   auto It = ExprToLoc.find(&E);
157   return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP);
158 }
159 
160 StorageLocation *Environment::getThisPointeeStorageLocation() const {
161   return DACtx->getThisPointeeStorageLocation();
162 }
163 
164 void Environment::setValue(const StorageLocation &Loc, Value &Val) {
165   LocToVal[&Loc] = &Val;
166 
167   if (auto *StructVal = dyn_cast<StructValue>(&Val)) {
168     auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc);
169 
170     const QualType Type = AggregateLoc.getType();
171     assert(Type->isStructureOrClassType());
172 
173     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
174       assert(Field != nullptr);
175       setValue(AggregateLoc.getChild(*Field), StructVal->getChild(*Field));
176     }
177   }
178 }
179 
180 Value *Environment::getValue(const StorageLocation &Loc) const {
181   auto It = LocToVal.find(&Loc);
182   return It == LocToVal.end() ? nullptr : It->second;
183 }
184 
185 Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const {
186   auto *Loc = getStorageLocation(D, SP);
187   if (Loc == nullptr)
188     return nullptr;
189   return getValue(*Loc);
190 }
191 
192 Value *Environment::getValue(const Expr &E, SkipPast SP) const {
193   auto *Loc = getStorageLocation(E, SP);
194   if (Loc == nullptr)
195     return nullptr;
196   return getValue(*Loc);
197 }
198 
199 Value *Environment::createValue(QualType Type) {
200   llvm::DenseSet<QualType> Visited;
201   return createValueUnlessSelfReferential(Type, Visited);
202 }
203 
204 Value *Environment::createValueUnlessSelfReferential(
205     QualType Type, llvm::DenseSet<QualType> &Visited) {
206   assert(!Type.isNull());
207 
208   if (Type->isIntegerType()) {
209     return &takeOwnership(std::make_unique<IntegerValue>());
210   }
211 
212   if (Type->isReferenceType()) {
213     QualType PointeeType = Type->getAs<ReferenceType>()->getPointeeType();
214     auto &PointeeLoc = createStorageLocation(PointeeType);
215 
216     if (!Visited.contains(PointeeType.getCanonicalType())) {
217       Visited.insert(PointeeType.getCanonicalType());
218       Value *PointeeVal =
219           createValueUnlessSelfReferential(PointeeType, Visited);
220       Visited.erase(PointeeType.getCanonicalType());
221 
222       if (PointeeVal != nullptr)
223         setValue(PointeeLoc, *PointeeVal);
224     }
225 
226     return &takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc));
227   }
228 
229   if (Type->isPointerType()) {
230     QualType PointeeType = Type->getAs<PointerType>()->getPointeeType();
231     auto &PointeeLoc = createStorageLocation(PointeeType);
232 
233     if (!Visited.contains(PointeeType.getCanonicalType())) {
234       Visited.insert(PointeeType.getCanonicalType());
235       Value *PointeeVal =
236           createValueUnlessSelfReferential(PointeeType, Visited);
237       Visited.erase(PointeeType.getCanonicalType());
238 
239       if (PointeeVal != nullptr)
240         setValue(PointeeLoc, *PointeeVal);
241     }
242 
243     return &takeOwnership(std::make_unique<PointerValue>(PointeeLoc));
244   }
245 
246   if (Type->isStructureOrClassType()) {
247     // FIXME: Initialize only fields that are accessed in the context that is
248     // being analyzed.
249     llvm::DenseMap<const ValueDecl *, Value *> FieldValues;
250     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
251       assert(Field != nullptr);
252 
253       QualType FieldType = Field->getType();
254       if (Visited.contains(FieldType.getCanonicalType()))
255         continue;
256 
257       Visited.insert(FieldType.getCanonicalType());
258       FieldValues.insert(
259           {Field, createValueUnlessSelfReferential(FieldType, Visited)});
260       Visited.erase(FieldType.getCanonicalType());
261     }
262 
263     return &takeOwnership(
264         std::make_unique<StructValue>(std::move(FieldValues)));
265   }
266 
267   return nullptr;
268 }
269 
270 StorageLocation &
271 Environment::takeOwnership(std::unique_ptr<StorageLocation> Loc) {
272   return DACtx->takeOwnership(std::move(Loc));
273 }
274 
275 Value &Environment::takeOwnership(std::unique_ptr<Value> Val) {
276   return DACtx->takeOwnership(std::move(Val));
277 }
278 
279 StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const {
280   switch (SP) {
281   case SkipPast::None:
282     return Loc;
283   case SkipPast::Reference:
284     // References cannot be chained so we only need to skip past one level of
285     // indirection.
286     if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc)))
287       return Val->getPointeeLoc();
288     return Loc;
289   case SkipPast::ReferenceThenPointer:
290     StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference);
291     if (auto *Val = dyn_cast_or_null<PointerValue>(getValue(LocPastRef)))
292       return Val->getPointeeLoc();
293     return LocPastRef;
294   }
295   llvm_unreachable("bad SkipPast kind");
296 }
297 
298 const StorageLocation &Environment::skip(const StorageLocation &Loc,
299                                          SkipPast SP) const {
300   return skip(*const_cast<StorageLocation *>(&Loc), SP);
301 }
302 
303 } // namespace dataflow
304 } // namespace clang
305