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