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