xref: /llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (revision 7d941d6d21e91e8466bf200da094d027338b92fa)
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       initValueInStorageLocation(ParamLoc, ParamDecl->getType());
53     }
54   }
55 
56   if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) {
57     if (!MethodDecl->isStatic()) {
58       QualType ThisPointeeType = MethodDecl->getThisObjectType();
59       // FIXME: Add support for union types.
60       if (!ThisPointeeType->isUnionType()) {
61         auto &ThisPointeeLoc = createStorageLocation(ThisPointeeType);
62         DACtx.setThisPointeeStorageLocation(ThisPointeeLoc);
63         initValueInStorageLocation(ThisPointeeLoc, ThisPointeeType);
64       }
65     }
66   }
67 }
68 
69 bool Environment::operator==(const Environment &Other) const {
70   assert(DACtx == Other.DACtx);
71   return DeclToLoc == Other.DeclToLoc && LocToVal == Other.LocToVal;
72 }
73 
74 LatticeJoinEffect Environment::join(const Environment &Other) {
75   assert(DACtx == Other.DACtx);
76 
77   auto Effect = LatticeJoinEffect::Unchanged;
78 
79   const unsigned DeclToLocSizeBefore = DeclToLoc.size();
80   DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc);
81   if (DeclToLocSizeBefore != DeclToLoc.size())
82     Effect = LatticeJoinEffect::Changed;
83 
84   // FIXME: Add support for joining distinct values that are assigned to the
85   // same storage locations in `LocToVal` and `Other.LocToVal`.
86   const unsigned LocToValSizeBefore = LocToVal.size();
87   LocToVal = intersectDenseMaps(LocToVal, Other.LocToVal);
88   if (LocToValSizeBefore != LocToVal.size())
89     Effect = LatticeJoinEffect::Changed;
90 
91   return Effect;
92 }
93 
94 StorageLocation &Environment::createStorageLocation(QualType Type) {
95   assert(!Type.isNull());
96   if (Type->isStructureOrClassType()) {
97     // FIXME: Explore options to avoid eager initialization of fields as some of
98     // them might not be needed for a particular analysis.
99     llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
100     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
101       FieldLocs.insert({Field, &createStorageLocation(Field->getType())});
102     }
103     return takeOwnership(
104         std::make_unique<AggregateStorageLocation>(Type, std::move(FieldLocs)));
105   }
106   return takeOwnership(std::make_unique<ScalarStorageLocation>(Type));
107 }
108 
109 StorageLocation &Environment::createStorageLocation(const VarDecl &D) {
110   // Evaluated declarations are always assigned the same storage locations to
111   // ensure that the environment stabilizes across loop iterations. Storage
112   // locations for evaluated declarations are stored in the analysis context.
113   if (auto *Loc = DACtx->getStorageLocation(D))
114     return *Loc;
115   auto &Loc = createStorageLocation(D.getType());
116   DACtx->setStorageLocation(D, Loc);
117   return Loc;
118 }
119 
120 StorageLocation &Environment::createStorageLocation(const Expr &E) {
121   // Evaluated expressions are always assigned the same storage locations to
122   // ensure that the environment stabilizes across loop iterations. Storage
123   // locations for evaluated expressions are stored in the analysis context.
124   if (auto *Loc = DACtx->getStorageLocation(E))
125     return *Loc;
126   auto &Loc = createStorageLocation(E.getType());
127   DACtx->setStorageLocation(E, Loc);
128   return Loc;
129 }
130 
131 void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
132   assert(DeclToLoc.find(&D) == DeclToLoc.end());
133   DeclToLoc[&D] = &Loc;
134 }
135 
136 StorageLocation *Environment::getStorageLocation(const ValueDecl &D,
137                                                  SkipPast SP) const {
138   auto It = DeclToLoc.find(&D);
139   return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP);
140 }
141 
142 void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
143   assert(ExprToLoc.find(&E) == ExprToLoc.end());
144   ExprToLoc[&E] = &Loc;
145 }
146 
147 StorageLocation *Environment::getStorageLocation(const Expr &E,
148                                                  SkipPast SP) const {
149   auto It = ExprToLoc.find(&E);
150   return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP);
151 }
152 
153 StorageLocation *Environment::getThisPointeeStorageLocation() const {
154   return DACtx->getThisPointeeStorageLocation();
155 }
156 
157 void Environment::setValue(const StorageLocation &Loc, Value &Val) {
158   LocToVal[&Loc] = &Val;
159 
160   if (auto *StructVal = dyn_cast<StructValue>(&Val)) {
161     auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc);
162 
163     const QualType Type = AggregateLoc.getType();
164     assert(Type->isStructureOrClassType());
165 
166     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
167       assert(Field != nullptr);
168       setValue(AggregateLoc.getChild(*Field), StructVal->getChild(*Field));
169     }
170   }
171 }
172 
173 Value *Environment::getValue(const StorageLocation &Loc) const {
174   auto It = LocToVal.find(&Loc);
175   return It == LocToVal.end() ? nullptr : It->second;
176 }
177 
178 Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const {
179   auto *Loc = getStorageLocation(D, SP);
180   if (Loc == nullptr)
181     return nullptr;
182   return getValue(*Loc);
183 }
184 
185 Value *Environment::getValue(const Expr &E, SkipPast SP) const {
186   auto *Loc = getStorageLocation(E, SP);
187   if (Loc == nullptr)
188     return nullptr;
189   return getValue(*Loc);
190 }
191 
192 Value *Environment::initValueInStorageLocation(const StorageLocation &Loc,
193                                                QualType Type) {
194   llvm::DenseSet<QualType> Visited;
195   return initValueInStorageLocationUnlessSelfReferential(Loc, Type, Visited);
196 }
197 
198 Value *Environment::initValueInStorageLocationUnlessSelfReferential(
199     const StorageLocation &Loc, QualType Type,
200     llvm::DenseSet<QualType> &Visited) {
201   assert(!Type.isNull());
202 
203   if (Type->isIntegerType()) {
204     auto &Val = takeOwnership(std::make_unique<IntegerValue>());
205     setValue(Loc, Val);
206     return &Val;
207   }
208 
209   if (Type->isReferenceType()) {
210     QualType PointeeType = Type->getAs<ReferenceType>()->getPointeeType();
211     auto &PointeeLoc = createStorageLocation(PointeeType);
212 
213     if (!Visited.contains(PointeeType.getCanonicalType())) {
214       Visited.insert(PointeeType.getCanonicalType());
215       initValueInStorageLocationUnlessSelfReferential(PointeeLoc, PointeeType,
216                                                       Visited);
217       Visited.erase(PointeeType.getCanonicalType());
218     }
219 
220     auto &Val = takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc));
221     setValue(Loc, Val);
222     return &Val;
223   }
224 
225   if (Type->isPointerType()) {
226     QualType PointeeType = Type->getAs<PointerType>()->getPointeeType();
227     auto &PointeeLoc = createStorageLocation(PointeeType);
228 
229     if (!Visited.contains(PointeeType.getCanonicalType())) {
230       Visited.insert(PointeeType.getCanonicalType());
231       initValueInStorageLocationUnlessSelfReferential(PointeeLoc, PointeeType,
232                                                       Visited);
233       Visited.erase(PointeeType.getCanonicalType());
234     }
235 
236     auto &Val = takeOwnership(std::make_unique<PointerValue>(PointeeLoc));
237     setValue(Loc, Val);
238     return &Val;
239   }
240 
241   if (Type->isStructureOrClassType()) {
242     auto *AggregateLoc = cast<AggregateStorageLocation>(&Loc);
243 
244     // FIXME: Initialize only fields that are accessed in the context that is
245     // being analyzed.
246     llvm::DenseMap<const ValueDecl *, Value *> FieldValues;
247     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
248       assert(Field != nullptr);
249 
250       QualType FieldType = Field->getType();
251       if (Visited.contains(FieldType.getCanonicalType()))
252         continue;
253 
254       Visited.insert(FieldType.getCanonicalType());
255       FieldValues.insert(
256           {Field, initValueInStorageLocationUnlessSelfReferential(
257                       AggregateLoc->getChild(*Field), FieldType, Visited)});
258       Visited.erase(FieldType.getCanonicalType());
259     }
260 
261     auto &Val =
262         takeOwnership(std::make_unique<StructValue>(std::move(FieldValues)));
263     setValue(Loc, Val);
264     return &Val;
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