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 |