Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 1 | //===-- DataflowEnvironment.h -----------------------------------*- 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 | #ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H |
||
16 | #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H |
||
17 | |||
18 | #include "clang/AST/Decl.h" |
||
19 | #include "clang/AST/DeclBase.h" |
||
20 | #include "clang/AST/Expr.h" |
||
21 | #include "clang/AST/Type.h" |
||
22 | #include "clang/Analysis/FlowSensitive/ControlFlowContext.h" |
||
23 | #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" |
||
24 | #include "clang/Analysis/FlowSensitive/DataflowLattice.h" |
||
25 | #include "clang/Analysis/FlowSensitive/StorageLocation.h" |
||
26 | #include "clang/Analysis/FlowSensitive/Value.h" |
||
27 | #include "llvm/ADT/DenseMap.h" |
||
28 | #include "llvm/ADT/DenseSet.h" |
||
29 | #include "llvm/Support/ErrorHandling.h" |
||
30 | #include <memory> |
||
31 | #include <type_traits> |
||
32 | #include <utility> |
||
33 | |||
34 | namespace clang { |
||
35 | namespace dataflow { |
||
36 | |||
37 | /// Indicates what kind of indirections should be skipped past when retrieving |
||
38 | /// storage locations or values. |
||
39 | /// |
||
40 | /// FIXME: Consider renaming this or replacing it with a more appropriate model. |
||
41 | /// See the discussion in https://reviews.llvm.org/D116596 for context. |
||
42 | enum class SkipPast { |
||
43 | /// No indirections should be skipped past. |
||
44 | None, |
||
45 | /// An optional reference should be skipped past. |
||
46 | Reference, |
||
47 | /// An optional reference should be skipped past, then an optional pointer |
||
48 | /// should be skipped past. |
||
49 | ReferenceThenPointer, |
||
50 | }; |
||
51 | |||
52 | /// Indicates the result of a tentative comparison. |
||
53 | enum class ComparisonResult { |
||
54 | Same, |
||
55 | Different, |
||
56 | Unknown, |
||
57 | }; |
||
58 | |||
59 | /// Holds the state of the program (store and heap) at a given program point. |
||
60 | /// |
||
61 | /// WARNING: Symbolic values that are created by the environment for static |
||
62 | /// local and global variables are not currently invalidated on function calls. |
||
63 | /// This is unsound and should be taken into account when designing dataflow |
||
64 | /// analyses. |
||
65 | class Environment { |
||
66 | public: |
||
67 | /// Supplements `Environment` with non-standard comparison and join |
||
68 | /// operations. |
||
69 | class ValueModel { |
||
70 | public: |
||
71 | virtual ~ValueModel() = default; |
||
72 | |||
73 | /// Returns: |
||
74 | /// `Same`: `Val1` is equivalent to `Val2`, according to the model. |
||
75 | /// `Different`: `Val1` is distinct from `Val2`, according to the model. |
||
76 | /// `Unknown`: The model can't determine a relationship between `Val1` and |
||
77 | /// `Val2`. |
||
78 | /// |
||
79 | /// Requirements: |
||
80 | /// |
||
81 | /// `Val1` and `Val2` must be distinct. |
||
82 | /// |
||
83 | /// `Val1` and `Val2` must model values of type `Type`. |
||
84 | /// |
||
85 | /// `Val1` and `Val2` must be assigned to the same storage location in |
||
86 | /// `Env1` and `Env2` respectively. |
||
87 | virtual ComparisonResult compare(QualType Type, const Value &Val1, |
||
88 | const Environment &Env1, const Value &Val2, |
||
89 | const Environment &Env2) { |
||
90 | // FIXME: Consider adding QualType to StructValue and removing the Type |
||
91 | // argument here. |
||
92 | return ComparisonResult::Unknown; |
||
93 | } |
||
94 | |||
95 | /// Modifies `MergedVal` to approximate both `Val1` and `Val2`. This could |
||
96 | /// be a strict lattice join or a more general widening operation. |
||
97 | /// |
||
98 | /// If this function returns true, `MergedVal` will be assigned to a storage |
||
99 | /// location of type `Type` in `MergedEnv`. |
||
100 | /// |
||
101 | /// `Env1` and `Env2` can be used to query child values and path condition |
||
102 | /// implications of `Val1` and `Val2` respectively. |
||
103 | /// |
||
104 | /// Requirements: |
||
105 | /// |
||
106 | /// `Val1` and `Val2` must be distinct. |
||
107 | /// |
||
108 | /// `Val1`, `Val2`, and `MergedVal` must model values of type `Type`. |
||
109 | /// |
||
110 | /// `Val1` and `Val2` must be assigned to the same storage location in |
||
111 | /// `Env1` and `Env2` respectively. |
||
112 | virtual bool merge(QualType Type, const Value &Val1, |
||
113 | const Environment &Env1, const Value &Val2, |
||
114 | const Environment &Env2, Value &MergedVal, |
||
115 | Environment &MergedEnv) { |
||
116 | return true; |
||
117 | } |
||
118 | |||
119 | /// This function may widen the current value -- replace it with an |
||
120 | /// approximation that can reach a fixed point more quickly than iterated |
||
121 | /// application of the transfer function alone. The previous value is |
||
122 | /// provided to inform the choice of widened value. The function must also |
||
123 | /// serve as a comparison operation, by indicating whether the widened value |
||
124 | /// is equivalent to the previous value. |
||
125 | /// |
||
126 | /// Returns either: |
||
127 | /// |
||
128 | /// `nullptr`, if this value is not of interest to the model, or |
||
129 | /// |
||
130 | /// `&Prev`, if the widened value is equivalent to `Prev`, or |
||
131 | /// |
||
132 | /// A non-null value that approximates `Current`. `Prev` is available to |
||
133 | /// inform the chosen approximation. |
||
134 | /// |
||
135 | /// `PrevEnv` and `CurrentEnv` can be used to query child values and path |
||
136 | /// condition implications of `Prev` and `Current`, respectively. |
||
137 | /// |
||
138 | /// Requirements: |
||
139 | /// |
||
140 | /// `Prev` and `Current` must model values of type `Type`. |
||
141 | /// |
||
142 | /// `Prev` and `Current` must be assigned to the same storage location in |
||
143 | /// `PrevEnv` and `CurrentEnv`, respectively. |
||
144 | virtual Value *widen(QualType Type, Value &Prev, const Environment &PrevEnv, |
||
145 | Value &Current, Environment &CurrentEnv) { |
||
146 | // The default implementation reduces to just comparison, since comparison |
||
147 | // is required by the API, even if no widening is performed. |
||
148 | switch (compare(Type, Prev, PrevEnv, Current, CurrentEnv)) { |
||
149 | case ComparisonResult::Same: |
||
150 | return &Prev; |
||
151 | case ComparisonResult::Different: |
||
152 | return &Current; |
||
153 | case ComparisonResult::Unknown: |
||
154 | return nullptr; |
||
155 | } |
||
156 | llvm_unreachable("all cases in switch covered"); |
||
157 | } |
||
158 | }; |
||
159 | |||
160 | /// Creates an environment that uses `DACtx` to store objects that encompass |
||
161 | /// the state of a program. |
||
162 | explicit Environment(DataflowAnalysisContext &DACtx); |
||
163 | |||
164 | Environment(const Environment &Other); |
||
165 | Environment &operator=(const Environment &Other); |
||
166 | |||
167 | Environment(Environment &&Other) = default; |
||
168 | Environment &operator=(Environment &&Other) = default; |
||
169 | |||
170 | /// Creates an environment that uses `DACtx` to store objects that encompass |
||
171 | /// the state of a program. |
||
172 | /// |
||
173 | /// If `DeclCtx` is a function, initializes the environment with symbolic |
||
174 | /// representations of the function parameters. |
||
175 | /// |
||
176 | /// If `DeclCtx` is a non-static member function, initializes the environment |
||
177 | /// with a symbolic representation of the `this` pointee. |
||
178 | Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx); |
||
179 | |||
180 | const DataflowAnalysisContext::Options &getAnalysisOptions() { |
||
181 | return DACtx->getOptions(); |
||
182 | } |
||
183 | |||
184 | /// Creates and returns an environment to use for an inline analysis of the |
||
185 | /// callee. Uses the storage location from each argument in the `Call` as the |
||
186 | /// storage location for the corresponding parameter in the callee. |
||
187 | /// |
||
188 | /// Requirements: |
||
189 | /// |
||
190 | /// The callee of `Call` must be a `FunctionDecl`. |
||
191 | /// |
||
192 | /// The body of the callee must not reference globals. |
||
193 | /// |
||
194 | /// The arguments of `Call` must map 1:1 to the callee's parameters. |
||
195 | Environment pushCall(const CallExpr *Call) const; |
||
196 | Environment pushCall(const CXXConstructExpr *Call) const; |
||
197 | |||
198 | /// Moves gathered information back into `this` from a `CalleeEnv` created via |
||
199 | /// `pushCall`. |
||
200 | void popCall(const Environment &CalleeEnv); |
||
201 | |||
202 | /// Returns true if and only if the environment is equivalent to `Other`, i.e |
||
203 | /// the two environments: |
||
204 | /// - have the same mappings from declarations to storage locations, |
||
205 | /// - have the same mappings from expressions to storage locations, |
||
206 | /// - have the same or equivalent (according to `Model`) values assigned to |
||
207 | /// the same storage locations. |
||
208 | /// |
||
209 | /// Requirements: |
||
210 | /// |
||
211 | /// `Other` and `this` must use the same `DataflowAnalysisContext`. |
||
212 | bool equivalentTo(const Environment &Other, |
||
213 | Environment::ValueModel &Model) const; |
||
214 | |||
215 | /// Joins the environment with `Other` by taking the intersection of storage |
||
216 | /// locations and values that are stored in them. Distinct values that are |
||
217 | /// assigned to the same storage locations in the environment and `Other` are |
||
218 | /// merged using `Model`. |
||
219 | /// |
||
220 | /// Requirements: |
||
221 | /// |
||
222 | /// `Other` and `this` must use the same `DataflowAnalysisContext`. |
||
223 | LatticeJoinEffect join(const Environment &Other, |
||
224 | Environment::ValueModel &Model); |
||
225 | |||
226 | |||
227 | /// Widens the environment point-wise, using `PrevEnv` as needed to inform the |
||
228 | /// approximation. |
||
229 | /// |
||
230 | /// Requirements: |
||
231 | /// |
||
232 | /// `PrevEnv` must be the immediate previous version of the environment. |
||
233 | /// `PrevEnv` and `this` must use the same `DataflowAnalysisContext`. |
||
234 | LatticeJoinEffect widen(const Environment &PrevEnv, |
||
235 | Environment::ValueModel &Model); |
||
236 | |||
237 | // FIXME: Rename `createOrGetStorageLocation` to `getOrCreateStorageLocation`, |
||
238 | // `getStableStorageLocation`, or something more appropriate. |
||
239 | |||
240 | /// Creates a storage location appropriate for `Type`. Does not assign a value |
||
241 | /// to the returned storage location in the environment. |
||
242 | /// |
||
243 | /// Requirements: |
||
244 | /// |
||
245 | /// `Type` must not be null. |
||
246 | StorageLocation &createStorageLocation(QualType Type); |
||
247 | |||
248 | /// Creates a storage location for `D`. Does not assign the returned storage |
||
249 | /// location to `D` in the environment. Does not assign a value to the |
||
250 | /// returned storage location in the environment. |
||
251 | StorageLocation &createStorageLocation(const VarDecl &D); |
||
252 | |||
253 | /// Creates a storage location for `E`. Does not assign the returned storage |
||
254 | /// location to `E` in the environment. Does not assign a value to the |
||
255 | /// returned storage location in the environment. |
||
256 | StorageLocation &createStorageLocation(const Expr &E); |
||
257 | |||
258 | /// Assigns `Loc` as the storage location of `D` in the environment. |
||
259 | /// |
||
260 | /// Requirements: |
||
261 | /// |
||
262 | /// `D` must not be assigned a storage location in the environment. |
||
263 | void setStorageLocation(const ValueDecl &D, StorageLocation &Loc); |
||
264 | |||
265 | /// Returns the storage location assigned to `D` in the environment, applying |
||
266 | /// the `SP` policy for skipping past indirections, or null if `D` isn't |
||
267 | /// assigned a storage location in the environment. |
||
268 | StorageLocation *getStorageLocation(const ValueDecl &D, SkipPast SP) const; |
||
269 | |||
270 | /// Assigns `Loc` as the storage location of `E` in the environment. |
||
271 | /// |
||
272 | /// Requirements: |
||
273 | /// |
||
274 | /// `E` must not be assigned a storage location in the environment. |
||
275 | void setStorageLocation(const Expr &E, StorageLocation &Loc); |
||
276 | |||
277 | /// Returns the storage location assigned to `E` in the environment, applying |
||
278 | /// the `SP` policy for skipping past indirections, or null if `E` isn't |
||
279 | /// assigned a storage location in the environment. |
||
280 | StorageLocation *getStorageLocation(const Expr &E, SkipPast SP) const; |
||
281 | |||
282 | /// Returns the storage location assigned to the `this` pointee in the |
||
283 | /// environment or null if the `this` pointee has no assigned storage location |
||
284 | /// in the environment. |
||
285 | StorageLocation *getThisPointeeStorageLocation() const; |
||
286 | |||
287 | /// Returns the storage location of the return value or null, if unset. |
||
288 | StorageLocation *getReturnStorageLocation() const; |
||
289 | |||
290 | /// Returns a pointer value that represents a null pointer. Calls with |
||
291 | /// `PointeeType` that are canonically equivalent will return the same result. |
||
292 | PointerValue &getOrCreateNullPointerValue(QualType PointeeType); |
||
293 | |||
294 | /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise |
||
295 | /// return null. If `Type` is a pointer or reference type, creates all the |
||
296 | /// necessary storage locations and values for indirections until it finds a |
||
297 | /// non-pointer/non-reference type. |
||
298 | /// |
||
299 | /// Requirements: |
||
300 | /// |
||
301 | /// `Type` must not be null. |
||
302 | Value *createValue(QualType Type); |
||
303 | |||
304 | /// Assigns `Val` as the value of `Loc` in the environment. |
||
305 | void setValue(const StorageLocation &Loc, Value &Val); |
||
306 | |||
307 | /// Returns the value assigned to `Loc` in the environment or null if `Loc` |
||
308 | /// isn't assigned a value in the environment. |
||
309 | Value *getValue(const StorageLocation &Loc) const; |
||
310 | |||
311 | /// Equivalent to `getValue(getStorageLocation(D, SP), SkipPast::None)` if `D` |
||
312 | /// is assigned a storage location in the environment, otherwise returns null. |
||
313 | Value *getValue(const ValueDecl &D, SkipPast SP) const; |
||
314 | |||
315 | /// Equivalent to `getValue(getStorageLocation(E, SP), SkipPast::None)` if `E` |
||
316 | /// is assigned a storage location in the environment, otherwise returns null. |
||
317 | Value *getValue(const Expr &E, SkipPast SP) const; |
||
318 | |||
319 | /// Transfers ownership of `Loc` to the analysis context and returns a |
||
320 | /// reference to it. |
||
321 | /// |
||
322 | /// Requirements: |
||
323 | /// |
||
324 | /// `Loc` must not be null. |
||
325 | template <typename T> |
||
326 | std::enable_if_t<std::is_base_of<StorageLocation, T>::value, T &> |
||
327 | takeOwnership(std::unique_ptr<T> Loc) { |
||
328 | return DACtx->takeOwnership(std::move(Loc)); |
||
329 | } |
||
330 | |||
331 | /// Transfers ownership of `Val` to the analysis context and returns a |
||
332 | /// reference to it. |
||
333 | /// |
||
334 | /// Requirements: |
||
335 | /// |
||
336 | /// `Val` must not be null. |
||
337 | template <typename T> |
||
338 | std::enable_if_t<std::is_base_of<Value, T>::value, T &> |
||
339 | takeOwnership(std::unique_ptr<T> Val) { |
||
340 | return DACtx->takeOwnership(std::move(Val)); |
||
341 | } |
||
342 | |||
343 | /// Returns a symbolic boolean value that models a boolean literal equal to |
||
344 | /// `Value` |
||
345 | AtomicBoolValue &getBoolLiteralValue(bool Value) const { |
||
346 | return DACtx->getBoolLiteralValue(Value); |
||
347 | } |
||
348 | |||
349 | /// Returns an atomic boolean value. |
||
350 | BoolValue &makeAtomicBoolValue() const { |
||
351 | return DACtx->createAtomicBoolValue(); |
||
352 | } |
||
353 | |||
354 | /// Returns a unique instance of boolean Top. |
||
355 | BoolValue &makeTopBoolValue() const { |
||
356 | return DACtx->createTopBoolValue(); |
||
357 | } |
||
358 | |||
359 | /// Returns a boolean value that represents the conjunction of `LHS` and |
||
360 | /// `RHS`. Subsequent calls with the same arguments, regardless of their |
||
361 | /// order, will return the same result. If the given boolean values represent |
||
362 | /// the same value, the result will be the value itself. |
||
363 | BoolValue &makeAnd(BoolValue &LHS, BoolValue &RHS) const { |
||
364 | return DACtx->getOrCreateConjunction(LHS, RHS); |
||
365 | } |
||
366 | |||
367 | /// Returns a boolean value that represents the disjunction of `LHS` and |
||
368 | /// `RHS`. Subsequent calls with the same arguments, regardless of their |
||
369 | /// order, will return the same result. If the given boolean values represent |
||
370 | /// the same value, the result will be the value itself. |
||
371 | BoolValue &makeOr(BoolValue &LHS, BoolValue &RHS) const { |
||
372 | return DACtx->getOrCreateDisjunction(LHS, RHS); |
||
373 | } |
||
374 | |||
375 | /// Returns a boolean value that represents the negation of `Val`. Subsequent |
||
376 | /// calls with the same argument will return the same result. |
||
377 | BoolValue &makeNot(BoolValue &Val) const { |
||
378 | return DACtx->getOrCreateNegation(Val); |
||
379 | } |
||
380 | |||
381 | /// Returns a boolean value represents `LHS` => `RHS`. Subsequent calls with |
||
382 | /// the same arguments, will return the same result. If the given boolean |
||
383 | /// values represent the same value, the result will be a value that |
||
384 | /// represents the true boolean literal. |
||
385 | BoolValue &makeImplication(BoolValue &LHS, BoolValue &RHS) const { |
||
386 | return DACtx->getOrCreateImplication(LHS, RHS); |
||
387 | } |
||
388 | |||
389 | /// Returns a boolean value represents `LHS` <=> `RHS`. Subsequent calls with |
||
390 | /// the same arguments, regardless of their order, will return the same |
||
391 | /// result. If the given boolean values represent the same value, the result |
||
392 | /// will be a value that represents the true boolean literal. |
||
393 | BoolValue &makeIff(BoolValue &LHS, BoolValue &RHS) const { |
||
394 | return DACtx->getOrCreateIff(LHS, RHS); |
||
395 | } |
||
396 | |||
397 | /// Returns the token that identifies the flow condition of the environment. |
||
398 | AtomicBoolValue &getFlowConditionToken() const { return *FlowConditionToken; } |
||
399 | |||
400 | /// Builds and returns the logical formula defining the flow condition |
||
401 | /// identified by `Token`. If a value in the formula is present as a key in |
||
402 | /// `Substitutions`, it will be substituted with the value it maps to. |
||
403 | BoolValue &buildAndSubstituteFlowCondition( |
||
404 | AtomicBoolValue &Token, |
||
405 | llvm::DenseMap<AtomicBoolValue *, BoolValue *> Substitutions) { |
||
406 | return DACtx->buildAndSubstituteFlowCondition(Token, |
||
407 | std::move(Substitutions)); |
||
408 | } |
||
409 | |||
410 | /// Adds `Val` to the set of clauses that constitute the flow condition. |
||
411 | void addToFlowCondition(BoolValue &Val); |
||
412 | |||
413 | /// Returns true if and only if the clauses that constitute the flow condition |
||
414 | /// imply that `Val` is true. |
||
415 | bool flowConditionImplies(BoolValue &Val) const; |
||
416 | |||
417 | /// Returns the `DeclContext` of the block being analysed, if any. Otherwise, |
||
418 | /// returns null. |
||
419 | const DeclContext *getDeclCtx() const { return CallStack.back(); } |
||
420 | |||
421 | /// Returns whether this `Environment` can be extended to analyze the given |
||
422 | /// `Callee` (i.e. if `pushCall` can be used), with recursion disallowed and a |
||
423 | /// given `MaxDepth`. |
||
424 | bool canDescend(unsigned MaxDepth, const DeclContext *Callee) const; |
||
425 | |||
426 | /// Returns the `ControlFlowContext` registered for `F`, if any. Otherwise, |
||
427 | /// returns null. |
||
428 | const ControlFlowContext *getControlFlowContext(const FunctionDecl *F) { |
||
429 | return DACtx->getControlFlowContext(F); |
||
430 | } |
||
431 | |||
432 | LLVM_DUMP_METHOD void dump() const; |
||
433 | LLVM_DUMP_METHOD void dump(raw_ostream &OS) const; |
||
434 | |||
435 | private: |
||
436 | /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise |
||
437 | /// return null. |
||
438 | /// |
||
439 | /// Recursively initializes storage locations and values until it sees a |
||
440 | /// self-referential pointer or reference type. `Visited` is used to track |
||
441 | /// which types appeared in the reference/pointer chain in order to avoid |
||
442 | /// creating a cyclic dependency with self-referential pointers/references. |
||
443 | /// |
||
444 | /// Requirements: |
||
445 | /// |
||
446 | /// `Type` must not be null. |
||
447 | Value *createValueUnlessSelfReferential(QualType Type, |
||
448 | llvm::DenseSet<QualType> &Visited, |
||
449 | int Depth, int &CreatedValuesCount); |
||
450 | |||
451 | StorageLocation &skip(StorageLocation &Loc, SkipPast SP) const; |
||
452 | const StorageLocation &skip(const StorageLocation &Loc, SkipPast SP) const; |
||
453 | |||
454 | /// Shared implementation of `pushCall` overloads. Note that unlike |
||
455 | /// `pushCall`, this member is invoked on the environment of the callee, not |
||
456 | /// of the caller. |
||
457 | void pushCallInternal(const FunctionDecl *FuncDecl, |
||
458 | ArrayRef<const Expr *> Args); |
||
459 | |||
460 | /// Assigns storage locations and values to all variables in `Vars`. |
||
461 | void initVars(llvm::DenseSet<const VarDecl *> Vars); |
||
462 | |||
463 | // `DACtx` is not null and not owned by this object. |
||
464 | DataflowAnalysisContext *DACtx; |
||
465 | |||
466 | |||
467 | // FIXME: move the fields `CallStack`, `ReturnLoc` and `ThisPointeeLoc` into a |
||
468 | // separate call-context object, shared between environments in the same call. |
||
469 | // https://github.com/llvm/llvm-project/issues/59005 |
||
470 | |||
471 | // `DeclContext` of the block being analysed if provided. |
||
472 | std::vector<const DeclContext *> CallStack; |
||
473 | |||
474 | // In a properly initialized `Environment`, `ReturnLoc` should only be null if |
||
475 | // its `DeclContext` could not be cast to a `FunctionDecl`. |
||
476 | StorageLocation *ReturnLoc = nullptr; |
||
477 | // The storage location of the `this` pointee. Should only be null if the |
||
478 | // function being analyzed is only a function and not a method. |
||
479 | StorageLocation *ThisPointeeLoc = nullptr; |
||
480 | |||
481 | // Maps from program declarations and statements to storage locations that are |
||
482 | // assigned to them. Unlike the maps in `DataflowAnalysisContext`, these |
||
483 | // include only storage locations that are in scope for a particular basic |
||
484 | // block. |
||
485 | llvm::DenseMap<const ValueDecl *, StorageLocation *> DeclToLoc; |
||
486 | llvm::DenseMap<const Expr *, StorageLocation *> ExprToLoc; |
||
487 | |||
488 | llvm::DenseMap<const StorageLocation *, Value *> LocToVal; |
||
489 | |||
490 | // Maps locations of struct members to symbolic values of the structs that own |
||
491 | // them and the decls of the struct members. |
||
492 | llvm::DenseMap<const StorageLocation *, |
||
493 | std::pair<StructValue *, const ValueDecl *>> |
||
494 | MemberLocToStruct; |
||
495 | |||
496 | AtomicBoolValue *FlowConditionToken; |
||
497 | }; |
||
498 | |||
499 | } // namespace dataflow |
||
500 | } // namespace clang |
||
501 | |||
502 | #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H |