xref: /llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (revision 99f7d55eeeecd56566d23ee222e272729e05535c)
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 &Value) {
158   LocToVal[&Loc] = &Value;
159 }
160 
161 Value *Environment::getValue(const StorageLocation &Loc) const {
162   auto It = LocToVal.find(&Loc);
163   return It == LocToVal.end() ? nullptr : It->second;
164 }
165 
166 Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const {
167   auto *Loc = getStorageLocation(D, SP);
168   if (Loc == nullptr)
169     return nullptr;
170   return getValue(*Loc);
171 }
172 
173 Value *Environment::getValue(const Expr &E, SkipPast SP) const {
174   auto *Loc = getStorageLocation(E, SP);
175   if (Loc == nullptr)
176     return nullptr;
177   return getValue(*Loc);
178 }
179 
180 Value *Environment::initValueInStorageLocation(const StorageLocation &Loc,
181                                                QualType Type) {
182   llvm::DenseSet<QualType> Visited;
183   return initValueInStorageLocationUnlessSelfReferential(Loc, Type, Visited);
184 }
185 
186 Value *Environment::initValueInStorageLocationUnlessSelfReferential(
187     const StorageLocation &Loc, QualType Type,
188     llvm::DenseSet<QualType> &Visited) {
189   assert(!Type.isNull());
190 
191   if (Type->isIntegerType()) {
192     auto &Val = takeOwnership(std::make_unique<IntegerValue>());
193     setValue(Loc, Val);
194     return &Val;
195   }
196 
197   if (Type->isReferenceType()) {
198     QualType PointeeType = Type->getAs<ReferenceType>()->getPointeeType();
199     auto &PointeeLoc = createStorageLocation(PointeeType);
200 
201     if (!Visited.contains(PointeeType.getCanonicalType())) {
202       Visited.insert(PointeeType.getCanonicalType());
203       initValueInStorageLocationUnlessSelfReferential(PointeeLoc, PointeeType,
204                                                       Visited);
205       Visited.erase(PointeeType.getCanonicalType());
206     }
207 
208     auto &Val = takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc));
209     setValue(Loc, Val);
210     return &Val;
211   }
212 
213   if (Type->isPointerType()) {
214     QualType PointeeType = Type->getAs<PointerType>()->getPointeeType();
215     auto &PointeeLoc = createStorageLocation(PointeeType);
216 
217     if (!Visited.contains(PointeeType.getCanonicalType())) {
218       Visited.insert(PointeeType.getCanonicalType());
219       initValueInStorageLocationUnlessSelfReferential(PointeeLoc, PointeeType,
220                                                       Visited);
221       Visited.erase(PointeeType.getCanonicalType());
222     }
223 
224     auto &Val = takeOwnership(std::make_unique<PointerValue>(PointeeLoc));
225     setValue(Loc, Val);
226     return &Val;
227   }
228 
229   if (Type->isStructureOrClassType()) {
230     auto *AggregateLoc = cast<AggregateStorageLocation>(&Loc);
231 
232     // FIXME: Initialize only fields that are accessed in the context that is
233     // being analyzed.
234     llvm::DenseMap<const ValueDecl *, Value *> FieldValues;
235     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
236       assert(Field != nullptr);
237 
238       QualType FieldType = Field->getType();
239       if (Visited.contains(FieldType.getCanonicalType()))
240         continue;
241 
242       Visited.insert(FieldType.getCanonicalType());
243       FieldValues.insert(
244           {Field, initValueInStorageLocationUnlessSelfReferential(
245                       AggregateLoc->getChild(*Field), FieldType, Visited)});
246       Visited.erase(FieldType.getCanonicalType());
247     }
248 
249     auto &Val =
250         takeOwnership(std::make_unique<StructValue>(std::move(FieldValues)));
251     setValue(Loc, Val);
252     return &Val;
253   }
254 
255   return nullptr;
256 }
257 
258 StorageLocation &
259 Environment::takeOwnership(std::unique_ptr<StorageLocation> Loc) {
260   return DACtx->takeOwnership(std::move(Loc));
261 }
262 
263 Value &Environment::takeOwnership(std::unique_ptr<Value> Val) {
264   return DACtx->takeOwnership(std::move(Val));
265 }
266 
267 StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const {
268   switch (SP) {
269   case SkipPast::None:
270     return Loc;
271   case SkipPast::Reference:
272     // References cannot be chained so we only need to skip past one level of
273     // indirection.
274     if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc)))
275       return Val->getPointeeLoc();
276     return Loc;
277   case SkipPast::ReferenceThenPointer:
278     StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference);
279     if (auto *Val = dyn_cast_or_null<PointerValue>(getValue(LocPastRef)))
280       return Val->getPointeeLoc();
281     return LocPastRef;
282   }
283   llvm_unreachable("bad SkipPast kind");
284 }
285 
286 const StorageLocation &Environment::skip(const StorageLocation &Loc,
287                                          SkipPast SP) const {
288   return skip(*const_cast<StorageLocation *>(&Loc), SP);
289 }
290 
291 } // namespace dataflow
292 } // namespace clang
293