xref: /llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (revision d3597ec0aaad11a670f45b42428628531d4b2c05)
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                                     Environment::Merger &Merger) {
78   assert(DACtx == Other.DACtx);
79 
80   auto Effect = LatticeJoinEffect::Unchanged;
81 
82   const unsigned DeclToLocSizeBefore = DeclToLoc.size();
83   DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc);
84   if (DeclToLocSizeBefore != DeclToLoc.size())
85     Effect = LatticeJoinEffect::Changed;
86 
87   const unsigned ExprToLocSizeBefore = ExprToLoc.size();
88   ExprToLoc = intersectDenseMaps(ExprToLoc, Other.ExprToLoc);
89   if (ExprToLocSizeBefore != ExprToLoc.size())
90     Effect = LatticeJoinEffect::Changed;
91 
92   llvm::DenseMap<const StorageLocation *, Value *> MergedLocToVal;
93   for (auto &Entry : LocToVal) {
94     const StorageLocation *Loc = Entry.first;
95     assert(Loc != nullptr);
96 
97     Value *Val = Entry.second;
98     assert(Val != nullptr);
99 
100     auto It = Other.LocToVal.find(Loc);
101     if (It == Other.LocToVal.end())
102       continue;
103     assert(It->second != nullptr);
104 
105     if (It->second == Val) {
106       MergedLocToVal.insert({Loc, Val});
107       continue;
108     }
109 
110     // FIXME: Consider destroying `MergedValue` immediately if `Merger::merge`
111     // returns false to avoid storing unneeded values in `DACtx`.
112     if (Value *MergedVal = createValue(Loc->getType()))
113       if (Merger.merge(Loc->getType(), *Val, *It->second, *MergedVal, *this))
114         MergedLocToVal.insert({Loc, MergedVal});
115   }
116   const unsigned LocToValSizeBefore = LocToVal.size();
117   LocToVal = std::move(MergedLocToVal);
118   if (LocToValSizeBefore != LocToVal.size())
119     Effect = LatticeJoinEffect::Changed;
120 
121   return Effect;
122 }
123 
124 StorageLocation &Environment::createStorageLocation(QualType Type) {
125   assert(!Type.isNull());
126   if (Type->isStructureOrClassType() || Type->isUnionType()) {
127     // FIXME: Explore options to avoid eager initialization of fields as some of
128     // them might not be needed for a particular analysis.
129     llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
130     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
131       FieldLocs.insert({Field, &createStorageLocation(Field->getType())});
132     }
133     return takeOwnership(
134         std::make_unique<AggregateStorageLocation>(Type, std::move(FieldLocs)));
135   }
136   return takeOwnership(std::make_unique<ScalarStorageLocation>(Type));
137 }
138 
139 StorageLocation &Environment::createStorageLocation(const VarDecl &D) {
140   // Evaluated declarations are always assigned the same storage locations to
141   // ensure that the environment stabilizes across loop iterations. Storage
142   // locations for evaluated declarations are stored in the analysis context.
143   if (auto *Loc = DACtx->getStorageLocation(D))
144     return *Loc;
145   auto &Loc = createStorageLocation(D.getType());
146   DACtx->setStorageLocation(D, Loc);
147   return Loc;
148 }
149 
150 StorageLocation &Environment::createStorageLocation(const Expr &E) {
151   // Evaluated expressions are always assigned the same storage locations to
152   // ensure that the environment stabilizes across loop iterations. Storage
153   // locations for evaluated expressions are stored in the analysis context.
154   if (auto *Loc = DACtx->getStorageLocation(E))
155     return *Loc;
156   auto &Loc = createStorageLocation(E.getType());
157   DACtx->setStorageLocation(E, Loc);
158   return Loc;
159 }
160 
161 void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
162   assert(DeclToLoc.find(&D) == DeclToLoc.end());
163   DeclToLoc[&D] = &Loc;
164 }
165 
166 StorageLocation *Environment::getStorageLocation(const ValueDecl &D,
167                                                  SkipPast SP) const {
168   auto It = DeclToLoc.find(&D);
169   return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP);
170 }
171 
172 void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
173   assert(ExprToLoc.find(&E) == ExprToLoc.end());
174   ExprToLoc[&E] = &Loc;
175 }
176 
177 StorageLocation *Environment::getStorageLocation(const Expr &E,
178                                                  SkipPast SP) const {
179   auto It = ExprToLoc.find(&E);
180   return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP);
181 }
182 
183 StorageLocation *Environment::getThisPointeeStorageLocation() const {
184   return DACtx->getThisPointeeStorageLocation();
185 }
186 
187 void Environment::setValue(const StorageLocation &Loc, Value &Val) {
188   LocToVal[&Loc] = &Val;
189 
190   if (auto *StructVal = dyn_cast<StructValue>(&Val)) {
191     auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc);
192 
193     const QualType Type = AggregateLoc.getType();
194     assert(Type->isStructureOrClassType());
195 
196     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
197       assert(Field != nullptr);
198       setValue(AggregateLoc.getChild(*Field), StructVal->getChild(*Field));
199     }
200   }
201 }
202 
203 Value *Environment::getValue(const StorageLocation &Loc) const {
204   auto It = LocToVal.find(&Loc);
205   return It == LocToVal.end() ? nullptr : It->second;
206 }
207 
208 Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const {
209   auto *Loc = getStorageLocation(D, SP);
210   if (Loc == nullptr)
211     return nullptr;
212   return getValue(*Loc);
213 }
214 
215 Value *Environment::getValue(const Expr &E, SkipPast SP) const {
216   auto *Loc = getStorageLocation(E, SP);
217   if (Loc == nullptr)
218     return nullptr;
219   return getValue(*Loc);
220 }
221 
222 Value *Environment::createValue(QualType Type) {
223   llvm::DenseSet<QualType> Visited;
224   return createValueUnlessSelfReferential(Type, Visited);
225 }
226 
227 Value *Environment::createValueUnlessSelfReferential(
228     QualType Type, llvm::DenseSet<QualType> &Visited) {
229   assert(!Type.isNull());
230 
231   if (Type->isIntegerType()) {
232     return &takeOwnership(std::make_unique<IntegerValue>());
233   }
234 
235   if (Type->isReferenceType()) {
236     QualType PointeeType = Type->getAs<ReferenceType>()->getPointeeType();
237     auto &PointeeLoc = createStorageLocation(PointeeType);
238 
239     if (!Visited.contains(PointeeType.getCanonicalType())) {
240       Visited.insert(PointeeType.getCanonicalType());
241       Value *PointeeVal =
242           createValueUnlessSelfReferential(PointeeType, Visited);
243       Visited.erase(PointeeType.getCanonicalType());
244 
245       if (PointeeVal != nullptr)
246         setValue(PointeeLoc, *PointeeVal);
247     }
248 
249     return &takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc));
250   }
251 
252   if (Type->isPointerType()) {
253     QualType PointeeType = Type->getAs<PointerType>()->getPointeeType();
254     auto &PointeeLoc = createStorageLocation(PointeeType);
255 
256     if (!Visited.contains(PointeeType.getCanonicalType())) {
257       Visited.insert(PointeeType.getCanonicalType());
258       Value *PointeeVal =
259           createValueUnlessSelfReferential(PointeeType, Visited);
260       Visited.erase(PointeeType.getCanonicalType());
261 
262       if (PointeeVal != nullptr)
263         setValue(PointeeLoc, *PointeeVal);
264     }
265 
266     return &takeOwnership(std::make_unique<PointerValue>(PointeeLoc));
267   }
268 
269   if (Type->isStructureOrClassType()) {
270     // FIXME: Initialize only fields that are accessed in the context that is
271     // being analyzed.
272     llvm::DenseMap<const ValueDecl *, Value *> FieldValues;
273     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
274       assert(Field != nullptr);
275 
276       QualType FieldType = Field->getType();
277       if (Visited.contains(FieldType.getCanonicalType()))
278         continue;
279 
280       Visited.insert(FieldType.getCanonicalType());
281       FieldValues.insert(
282           {Field, createValueUnlessSelfReferential(FieldType, Visited)});
283       Visited.erase(FieldType.getCanonicalType());
284     }
285 
286     return &takeOwnership(
287         std::make_unique<StructValue>(std::move(FieldValues)));
288   }
289 
290   return nullptr;
291 }
292 
293 StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const {
294   switch (SP) {
295   case SkipPast::None:
296     return Loc;
297   case SkipPast::Reference:
298     // References cannot be chained so we only need to skip past one level of
299     // indirection.
300     if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc)))
301       return Val->getPointeeLoc();
302     return Loc;
303   case SkipPast::ReferenceThenPointer:
304     StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference);
305     if (auto *Val = dyn_cast_or_null<PointerValue>(getValue(LocPastRef)))
306       return Val->getPointeeLoc();
307     return LocPastRef;
308   }
309   llvm_unreachable("bad SkipPast kind");
310 }
311 
312 const StorageLocation &Environment::skip(const StorageLocation &Loc,
313                                          SkipPast SP) const {
314   return skip(*const_cast<StorageLocation *>(&Loc), SP);
315 }
316 
317 } // namespace dataflow
318 } // namespace clang
319