xref: /freebsd/contrib/llvm-project/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
14824e7fdSDimitry Andric //===-- DataflowEnvironment.h -----------------------------------*- C++ -*-===//
24824e7fdSDimitry Andric //
34824e7fdSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44824e7fdSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
54824e7fdSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64824e7fdSDimitry Andric //
74824e7fdSDimitry Andric //===----------------------------------------------------------------------===//
84824e7fdSDimitry Andric //
94824e7fdSDimitry Andric //  This file defines an Environment class that is used by dataflow analyses
104824e7fdSDimitry Andric //  that run over Control-Flow Graphs (CFGs) to keep track of the state of the
114824e7fdSDimitry Andric //  program at given program points.
124824e7fdSDimitry Andric //
134824e7fdSDimitry Andric //===----------------------------------------------------------------------===//
144824e7fdSDimitry Andric 
154824e7fdSDimitry Andric #ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H
164824e7fdSDimitry Andric #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H
174824e7fdSDimitry Andric 
1804eeddc0SDimitry Andric #include "clang/AST/Decl.h"
1904eeddc0SDimitry Andric #include "clang/AST/DeclBase.h"
2004eeddc0SDimitry Andric #include "clang/AST/Expr.h"
2104eeddc0SDimitry Andric #include "clang/AST/Type.h"
22*0fca6ea1SDimitry Andric #include "clang/Analysis/FlowSensitive/ASTOps.h"
2304eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
240eae32dcSDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
2506c3fb27SDimitry Andric #include "clang/Analysis/FlowSensitive/Formula.h"
2606c3fb27SDimitry Andric #include "clang/Analysis/FlowSensitive/Logger.h"
2704eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/StorageLocation.h"
2804eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h"
2904eeddc0SDimitry Andric #include "llvm/ADT/DenseMap.h"
3004eeddc0SDimitry Andric #include "llvm/ADT/DenseSet.h"
3106c3fb27SDimitry Andric #include "llvm/ADT/MapVector.h"
3206c3fb27SDimitry Andric #include "llvm/Support/Compiler.h"
33bdd1243dSDimitry Andric #include "llvm/Support/ErrorHandling.h"
34*0fca6ea1SDimitry Andric #include <cassert>
3504eeddc0SDimitry Andric #include <memory>
3604eeddc0SDimitry Andric #include <type_traits>
3704eeddc0SDimitry Andric #include <utility>
38*0fca6ea1SDimitry Andric #include <vector>
390eae32dcSDimitry Andric 
404824e7fdSDimitry Andric namespace clang {
414824e7fdSDimitry Andric namespace dataflow {
424824e7fdSDimitry Andric 
43bdd1243dSDimitry Andric /// Indicates the result of a tentative comparison.
44bdd1243dSDimitry Andric enum class ComparisonResult {
45bdd1243dSDimitry Andric   Same,
46bdd1243dSDimitry Andric   Different,
47bdd1243dSDimitry Andric   Unknown,
48bdd1243dSDimitry Andric };
49bdd1243dSDimitry Andric 
50*0fca6ea1SDimitry Andric /// The result of a `widen` operation.
51*0fca6ea1SDimitry Andric struct WidenResult {
52*0fca6ea1SDimitry Andric   /// Non-null pointer to a potentially widened version of the input value.
53*0fca6ea1SDimitry Andric   Value *V;
54*0fca6ea1SDimitry Andric   /// Whether `V` represents a "change" (that is, a different value) with
55*0fca6ea1SDimitry Andric   /// respect to the previous value in the sequence.
56*0fca6ea1SDimitry Andric   LatticeEffect Effect;
57*0fca6ea1SDimitry Andric };
58*0fca6ea1SDimitry Andric 
594824e7fdSDimitry Andric /// Holds the state of the program (store and heap) at a given program point.
6081ad6265SDimitry Andric ///
6181ad6265SDimitry Andric /// WARNING: Symbolic values that are created by the environment for static
6281ad6265SDimitry Andric /// local and global variables are not currently invalidated on function calls.
6381ad6265SDimitry Andric /// This is unsound and should be taken into account when designing dataflow
6481ad6265SDimitry Andric /// analyses.
650eae32dcSDimitry Andric class Environment {
660eae32dcSDimitry Andric public:
671fd87a68SDimitry Andric   /// Supplements `Environment` with non-standard comparison and join
681fd87a68SDimitry Andric   /// operations.
691fd87a68SDimitry Andric   class ValueModel {
7004eeddc0SDimitry Andric   public:
711fd87a68SDimitry Andric     virtual ~ValueModel() = default;
720eae32dcSDimitry Andric 
73bdd1243dSDimitry Andric     /// Returns:
74bdd1243dSDimitry Andric     ///   `Same`: `Val1` is equivalent to `Val2`, according to the model.
75bdd1243dSDimitry Andric     ///   `Different`: `Val1` is distinct from `Val2`, according to the model.
76bdd1243dSDimitry Andric     ///   `Unknown`: The model can't determine a relationship between `Val1` and
77bdd1243dSDimitry Andric     ///    `Val2`.
7804eeddc0SDimitry Andric     ///
7904eeddc0SDimitry Andric     /// Requirements:
8004eeddc0SDimitry Andric     ///
8104eeddc0SDimitry Andric     ///  `Val1` and `Val2` must be distinct.
821fd87a68SDimitry Andric     ///
831fd87a68SDimitry Andric     ///  `Val1` and `Val2` must model values of type `Type`.
8481ad6265SDimitry Andric     ///
8581ad6265SDimitry Andric     ///  `Val1` and `Val2` must be assigned to the same storage location in
8681ad6265SDimitry Andric     ///  `Env1` and `Env2` respectively.
compare(QualType Type,const Value & Val1,const Environment & Env1,const Value & Val2,const Environment & Env2)87bdd1243dSDimitry Andric     virtual ComparisonResult compare(QualType Type, const Value &Val1,
8881ad6265SDimitry Andric                                      const Environment &Env1, const Value &Val2,
8981ad6265SDimitry Andric                                      const Environment &Env2) {
90*0fca6ea1SDimitry Andric       // FIXME: Consider adding `QualType` to `Value` and removing the `Type`
911fd87a68SDimitry Andric       // argument here.
92bdd1243dSDimitry Andric       return ComparisonResult::Unknown;
931fd87a68SDimitry Andric     }
941fd87a68SDimitry Andric 
95*0fca6ea1SDimitry Andric     /// Modifies `JoinedVal` to approximate both `Val1` and `Val2`. This should
96*0fca6ea1SDimitry Andric     /// obey the properties of a lattice join.
9781ad6265SDimitry Andric     ///
9881ad6265SDimitry Andric     /// `Env1` and `Env2` can be used to query child values and path condition
9981ad6265SDimitry Andric     /// implications of `Val1` and `Val2` respectively.
1001fd87a68SDimitry Andric     ///
1011fd87a68SDimitry Andric     /// Requirements:
1021fd87a68SDimitry Andric     ///
1031fd87a68SDimitry Andric     ///  `Val1` and `Val2` must be distinct.
1041fd87a68SDimitry Andric     ///
105*0fca6ea1SDimitry Andric     ///  `Val1`, `Val2`, and `JoinedVal` must model values of type `Type`.
10681ad6265SDimitry Andric     ///
10781ad6265SDimitry Andric     ///  `Val1` and `Val2` must be assigned to the same storage location in
10881ad6265SDimitry Andric     ///  `Env1` and `Env2` respectively.
join(QualType Type,const Value & Val1,const Environment & Env1,const Value & Val2,const Environment & Env2,Value & JoinedVal,Environment & JoinedEnv)109*0fca6ea1SDimitry Andric     virtual void join(QualType Type, const Value &Val1, const Environment &Env1,
110*0fca6ea1SDimitry Andric                       const Value &Val2, const Environment &Env2,
111*0fca6ea1SDimitry Andric                       Value &JoinedVal, Environment &JoinedEnv) {}
112bdd1243dSDimitry Andric 
113bdd1243dSDimitry Andric     /// This function may widen the current value -- replace it with an
114bdd1243dSDimitry Andric     /// approximation that can reach a fixed point more quickly than iterated
115bdd1243dSDimitry Andric     /// application of the transfer function alone. The previous value is
116bdd1243dSDimitry Andric     /// provided to inform the choice of widened value. The function must also
117bdd1243dSDimitry Andric     /// serve as a comparison operation, by indicating whether the widened value
118bdd1243dSDimitry Andric     /// is equivalent to the previous value.
119bdd1243dSDimitry Andric     ///
120*0fca6ea1SDimitry Andric     /// Returns one of the folowing:
121*0fca6ea1SDimitry Andric     /// *  `std::nullopt`, if this value is not of interest to the
122*0fca6ea1SDimitry Andric     ///     model.
123*0fca6ea1SDimitry Andric     /// *  A `WidenResult` with:
124*0fca6ea1SDimitry Andric     ///    *  A non-null `Value *` that points either to `Current` or a widened
125*0fca6ea1SDimitry Andric     ///       version of `Current`. This value must be consistent with
126*0fca6ea1SDimitry Andric     ///       the flow condition of `CurrentEnv`. We particularly caution
127*0fca6ea1SDimitry Andric     ///       against using `Prev`, which is rarely consistent.
128*0fca6ea1SDimitry Andric     ///    *  A `LatticeEffect` indicating whether the value should be
129*0fca6ea1SDimitry Andric     ///       considered a new value (`Changed`) or one *equivalent* (if not
130*0fca6ea1SDimitry Andric     ///       necessarily equal) to `Prev` (`Unchanged`).
131bdd1243dSDimitry Andric     ///
132bdd1243dSDimitry Andric     /// `PrevEnv` and `CurrentEnv` can be used to query child values and path
133bdd1243dSDimitry Andric     /// condition implications of `Prev` and `Current`, respectively.
134bdd1243dSDimitry Andric     ///
135bdd1243dSDimitry Andric     /// Requirements:
136bdd1243dSDimitry Andric     ///
137bdd1243dSDimitry Andric     ///  `Prev` and `Current` must model values of type `Type`.
138bdd1243dSDimitry Andric     ///
139bdd1243dSDimitry Andric     ///  `Prev` and `Current` must be assigned to the same storage location in
140bdd1243dSDimitry Andric     ///  `PrevEnv` and `CurrentEnv`, respectively.
widen(QualType Type,Value & Prev,const Environment & PrevEnv,Value & Current,Environment & CurrentEnv)141*0fca6ea1SDimitry Andric     virtual std::optional<WidenResult> widen(QualType Type, Value &Prev,
142*0fca6ea1SDimitry Andric                                              const Environment &PrevEnv,
143*0fca6ea1SDimitry Andric                                              Value &Current,
144*0fca6ea1SDimitry Andric                                              Environment &CurrentEnv) {
145bdd1243dSDimitry Andric       // The default implementation reduces to just comparison, since comparison
146bdd1243dSDimitry Andric       // is required by the API, even if no widening is performed.
147bdd1243dSDimitry Andric       switch (compare(Type, Prev, PrevEnv, Current, CurrentEnv)) {
148bdd1243dSDimitry Andric       case ComparisonResult::Unknown:
149*0fca6ea1SDimitry Andric         return std::nullopt;
150*0fca6ea1SDimitry Andric       case ComparisonResult::Same:
151*0fca6ea1SDimitry Andric         return WidenResult{&Current, LatticeEffect::Unchanged};
152*0fca6ea1SDimitry Andric       case ComparisonResult::Different:
153*0fca6ea1SDimitry Andric         return WidenResult{&Current, LatticeEffect::Changed};
154bdd1243dSDimitry Andric       }
155bdd1243dSDimitry Andric       llvm_unreachable("all cases in switch covered");
156bdd1243dSDimitry Andric     }
1570eae32dcSDimitry Andric   };
1584824e7fdSDimitry Andric 
15904eeddc0SDimitry Andric   /// Creates an environment that uses `DACtx` to store objects that encompass
16004eeddc0SDimitry Andric   /// the state of a program.
Environment(DataflowAnalysisContext & DACtx)161*0fca6ea1SDimitry Andric   explicit Environment(DataflowAnalysisContext &DACtx)
162*0fca6ea1SDimitry Andric       : DACtx(&DACtx),
163*0fca6ea1SDimitry Andric         FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {}
164*0fca6ea1SDimitry Andric 
165*0fca6ea1SDimitry Andric   /// Creates an environment that uses `DACtx` to store objects that encompass
166*0fca6ea1SDimitry Andric   /// the state of a program, with `S` as the statement to analyze.
Environment(DataflowAnalysisContext & DACtx,Stmt & S)167*0fca6ea1SDimitry Andric   Environment(DataflowAnalysisContext &DACtx, Stmt &S) : Environment(DACtx) {
168*0fca6ea1SDimitry Andric     InitialTargetStmt = &S;
169*0fca6ea1SDimitry Andric   }
170*0fca6ea1SDimitry Andric 
171*0fca6ea1SDimitry Andric   /// Creates an environment that uses `DACtx` to store objects that encompass
172*0fca6ea1SDimitry Andric   /// the state of a program, with `FD` as the function to analyze.
173*0fca6ea1SDimitry Andric   ///
174*0fca6ea1SDimitry Andric   /// Requirements:
175*0fca6ea1SDimitry Andric   ///
176*0fca6ea1SDimitry Andric   ///  The function must have a body, i.e.
177*0fca6ea1SDimitry Andric   ///  `FunctionDecl::doesThisDecalarationHaveABody()` must be true.
Environment(DataflowAnalysisContext & DACtx,const FunctionDecl & FD)178*0fca6ea1SDimitry Andric   Environment(DataflowAnalysisContext &DACtx, const FunctionDecl &FD)
179*0fca6ea1SDimitry Andric       : Environment(DACtx, *FD.getBody()) {
180*0fca6ea1SDimitry Andric     assert(FD.doesThisDeclarationHaveABody());
181*0fca6ea1SDimitry Andric     InitialTargetFunc = &FD;
182*0fca6ea1SDimitry Andric   }
18381ad6265SDimitry Andric 
18406c3fb27SDimitry Andric   // Copy-constructor is private, Environments should not be copied. See fork().
18506c3fb27SDimitry Andric   Environment &operator=(const Environment &Other) = delete;
18681ad6265SDimitry Andric 
18781ad6265SDimitry Andric   Environment(Environment &&Other) = default;
18881ad6265SDimitry Andric   Environment &operator=(Environment &&Other) = default;
18904eeddc0SDimitry Andric 
1905f757f3fSDimitry Andric   /// Assigns storage locations and values to all parameters, captures, global
191*0fca6ea1SDimitry Andric   /// variables, fields and functions referenced in the `Stmt` or `FunctionDecl`
192*0fca6ea1SDimitry Andric   /// passed to the constructor.
1935f757f3fSDimitry Andric   ///
194*0fca6ea1SDimitry Andric   /// If no `Stmt` or `FunctionDecl` was supplied, this function does nothing.
1955f757f3fSDimitry Andric   void initialize();
1965f757f3fSDimitry Andric 
19706c3fb27SDimitry Andric   /// Returns a new environment that is a copy of this one.
19806c3fb27SDimitry Andric   ///
19906c3fb27SDimitry Andric   /// The state of the program is initially the same, but can be mutated without
20006c3fb27SDimitry Andric   /// affecting the original.
20106c3fb27SDimitry Andric   ///
20206c3fb27SDimitry Andric   /// However the original should not be further mutated, as this may interfere
20306c3fb27SDimitry Andric   /// with the fork. (In practice, values are stored independently, but the
20406c3fb27SDimitry Andric   /// forked flow condition references the original).
20506c3fb27SDimitry Andric   Environment fork() const;
206bdd1243dSDimitry Andric 
207972a253aSDimitry Andric   /// Creates and returns an environment to use for an inline analysis of the
208972a253aSDimitry Andric   /// callee. Uses the storage location from each argument in the `Call` as the
209972a253aSDimitry Andric   /// storage location for the corresponding parameter in the callee.
210972a253aSDimitry Andric   ///
211972a253aSDimitry Andric   /// Requirements:
212972a253aSDimitry Andric   ///
213bdd1243dSDimitry Andric   ///  The callee of `Call` must be a `FunctionDecl`.
214972a253aSDimitry Andric   ///
215972a253aSDimitry Andric   ///  The body of the callee must not reference globals.
216972a253aSDimitry Andric   ///
217972a253aSDimitry Andric   ///  The arguments of `Call` must map 1:1 to the callee's parameters.
218972a253aSDimitry Andric   Environment pushCall(const CallExpr *Call) const;
219bdd1243dSDimitry Andric   Environment pushCall(const CXXConstructExpr *Call) const;
220bdd1243dSDimitry Andric 
221bdd1243dSDimitry Andric   /// Moves gathered information back into `this` from a `CalleeEnv` created via
222bdd1243dSDimitry Andric   /// `pushCall`.
22306c3fb27SDimitry Andric   void popCall(const CallExpr *Call, const Environment &CalleeEnv);
22406c3fb27SDimitry Andric   void popCall(const CXXConstructExpr *Call, const Environment &CalleeEnv);
225972a253aSDimitry Andric 
2261fd87a68SDimitry Andric   /// Returns true if and only if the environment is equivalent to `Other`, i.e
2271fd87a68SDimitry Andric   /// the two environments:
2281fd87a68SDimitry Andric   ///  - have the same mappings from declarations to storage locations,
2291fd87a68SDimitry Andric   ///  - have the same mappings from expressions to storage locations,
2301fd87a68SDimitry Andric   ///  - have the same or equivalent (according to `Model`) values assigned to
2311fd87a68SDimitry Andric   ///    the same storage locations.
2321fd87a68SDimitry Andric   ///
2331fd87a68SDimitry Andric   /// Requirements:
2341fd87a68SDimitry Andric   ///
2351fd87a68SDimitry Andric   ///  `Other` and `this` must use the same `DataflowAnalysisContext`.
2361fd87a68SDimitry Andric   bool equivalentTo(const Environment &Other,
2371fd87a68SDimitry Andric                     Environment::ValueModel &Model) const;
23804eeddc0SDimitry Andric 
239*0fca6ea1SDimitry Andric   /// How to treat expression state (`ExprToLoc` and `ExprToVal`) in a join.
240*0fca6ea1SDimitry Andric   /// If the join happens within a full expression, expression state should be
241*0fca6ea1SDimitry Andric   /// kept; otherwise, we can discard it.
242*0fca6ea1SDimitry Andric   enum ExprJoinBehavior {
243*0fca6ea1SDimitry Andric     DiscardExprState,
244*0fca6ea1SDimitry Andric     KeepExprState,
245*0fca6ea1SDimitry Andric   };
246*0fca6ea1SDimitry Andric 
24706c3fb27SDimitry Andric   /// Joins two environments by taking the intersection of storage locations and
24806c3fb27SDimitry Andric   /// values that are stored in them. Distinct values that are assigned to the
24906c3fb27SDimitry Andric   /// same storage locations in `EnvA` and `EnvB` are merged using `Model`.
2501fd87a68SDimitry Andric   ///
2511fd87a68SDimitry Andric   /// Requirements:
2521fd87a68SDimitry Andric   ///
25306c3fb27SDimitry Andric   ///  `EnvA` and `EnvB` must use the same `DataflowAnalysisContext`.
25406c3fb27SDimitry Andric   static Environment join(const Environment &EnvA, const Environment &EnvB,
255*0fca6ea1SDimitry Andric                           Environment::ValueModel &Model,
256*0fca6ea1SDimitry Andric                           ExprJoinBehavior ExprBehavior);
257*0fca6ea1SDimitry Andric 
258*0fca6ea1SDimitry Andric   /// Returns a value that approximates both `Val1` and `Val2`, or null if no
259*0fca6ea1SDimitry Andric   /// such value can be produced.
260*0fca6ea1SDimitry Andric   ///
261*0fca6ea1SDimitry Andric   /// `Env1` and `Env2` can be used to query child values and path condition
262*0fca6ea1SDimitry Andric   /// implications of `Val1` and `Val2` respectively. The joined value will be
263*0fca6ea1SDimitry Andric   /// produced in `JoinedEnv`.
264*0fca6ea1SDimitry Andric   ///
265*0fca6ea1SDimitry Andric   /// Requirements:
266*0fca6ea1SDimitry Andric   ///
267*0fca6ea1SDimitry Andric   ///  `Val1` and `Val2` must model values of type `Type`.
268*0fca6ea1SDimitry Andric   static Value *joinValues(QualType Ty, Value *Val1, const Environment &Env1,
269*0fca6ea1SDimitry Andric                            Value *Val2, const Environment &Env2,
270*0fca6ea1SDimitry Andric                            Environment &JoinedEnv,
2711fd87a68SDimitry Andric                            Environment::ValueModel &Model);
27204eeddc0SDimitry Andric 
273bdd1243dSDimitry Andric   /// Widens the environment point-wise, using `PrevEnv` as needed to inform the
274bdd1243dSDimitry Andric   /// approximation.
275bdd1243dSDimitry Andric   ///
276bdd1243dSDimitry Andric   /// Requirements:
277bdd1243dSDimitry Andric   ///
278bdd1243dSDimitry Andric   ///  `PrevEnv` must be the immediate previous version of the environment.
279bdd1243dSDimitry Andric   ///  `PrevEnv` and `this` must use the same `DataflowAnalysisContext`.
280*0fca6ea1SDimitry Andric   LatticeEffect widen(const Environment &PrevEnv,
281bdd1243dSDimitry Andric                       Environment::ValueModel &Model);
282bdd1243dSDimitry Andric 
28304eeddc0SDimitry Andric   // FIXME: Rename `createOrGetStorageLocation` to `getOrCreateStorageLocation`,
28404eeddc0SDimitry Andric   // `getStableStorageLocation`, or something more appropriate.
28504eeddc0SDimitry Andric 
28604eeddc0SDimitry Andric   /// Creates a storage location appropriate for `Type`. Does not assign a value
28704eeddc0SDimitry Andric   /// to the returned storage location in the environment.
28804eeddc0SDimitry Andric   ///
28904eeddc0SDimitry Andric   /// Requirements:
29004eeddc0SDimitry Andric   ///
29104eeddc0SDimitry Andric   ///  `Type` must not be null.
29204eeddc0SDimitry Andric   StorageLocation &createStorageLocation(QualType Type);
29304eeddc0SDimitry Andric 
29404eeddc0SDimitry Andric   /// Creates a storage location for `D`. Does not assign the returned storage
29504eeddc0SDimitry Andric   /// location to `D` in the environment. Does not assign a value to the
29604eeddc0SDimitry Andric   /// returned storage location in the environment.
2975f757f3fSDimitry Andric   StorageLocation &createStorageLocation(const ValueDecl &D);
29804eeddc0SDimitry Andric 
29904eeddc0SDimitry Andric   /// Creates a storage location for `E`. Does not assign the returned storage
30004eeddc0SDimitry Andric   /// location to `E` in the environment. Does not assign a value to the
30104eeddc0SDimitry Andric   /// returned storage location in the environment.
30204eeddc0SDimitry Andric   StorageLocation &createStorageLocation(const Expr &E);
30304eeddc0SDimitry Andric 
30404eeddc0SDimitry Andric   /// Assigns `Loc` as the storage location of `D` in the environment.
30504eeddc0SDimitry Andric   ///
30604eeddc0SDimitry Andric   /// Requirements:
30704eeddc0SDimitry Andric   ///
30806c3fb27SDimitry Andric   ///  `D` must not already have a storage location in the environment.
30904eeddc0SDimitry Andric   void setStorageLocation(const ValueDecl &D, StorageLocation &Loc);
31004eeddc0SDimitry Andric 
31106c3fb27SDimitry Andric   /// Returns the storage location assigned to `D` in the environment, or null
31206c3fb27SDimitry Andric   /// if `D` isn't assigned a storage location in the environment.
31306c3fb27SDimitry Andric   StorageLocation *getStorageLocation(const ValueDecl &D) const;
31404eeddc0SDimitry Andric 
3155f757f3fSDimitry Andric   /// Removes the location assigned to `D` in the environment (if any).
3165f757f3fSDimitry Andric   void removeDecl(const ValueDecl &D);
31704eeddc0SDimitry Andric 
31806c3fb27SDimitry Andric   /// Assigns `Loc` as the storage location of the glvalue `E` in the
31906c3fb27SDimitry Andric   /// environment.
32006c3fb27SDimitry Andric   ///
32106c3fb27SDimitry Andric   /// Requirements:
32206c3fb27SDimitry Andric   ///
32306c3fb27SDimitry Andric   ///  `E` must not be assigned a storage location in the environment.
32406c3fb27SDimitry Andric   ///  `E` must be a glvalue or a `BuiltinType::BuiltinFn`
3255f757f3fSDimitry Andric   void setStorageLocation(const Expr &E, StorageLocation &Loc);
32604eeddc0SDimitry Andric 
32706c3fb27SDimitry Andric   /// Returns the storage location assigned to the glvalue `E` in the
32806c3fb27SDimitry Andric   /// environment, or null if `E` isn't assigned a storage location in the
32906c3fb27SDimitry Andric   /// environment.
33006c3fb27SDimitry Andric   ///
33106c3fb27SDimitry Andric   /// Requirements:
33206c3fb27SDimitry Andric   ///  `E` must be a glvalue or a `BuiltinType::BuiltinFn`
3335f757f3fSDimitry Andric   StorageLocation *getStorageLocation(const Expr &E) const;
33406c3fb27SDimitry Andric 
335cb14a3feSDimitry Andric   /// Returns the result of casting `getStorageLocation(...)` to a subclass of
336cb14a3feSDimitry Andric   /// `StorageLocation` (using `cast_or_null<T>`).
337cb14a3feSDimitry Andric   /// This assert-fails if the result of `getStorageLocation(...)` is not of
338cb14a3feSDimitry Andric   /// type `T *`; if the storage location is not guaranteed to have type `T *`,
339cb14a3feSDimitry Andric   /// consider using `dyn_cast_or_null<T>(getStorageLocation(...))` instead.
340cb14a3feSDimitry Andric   template <typename T>
341cb14a3feSDimitry Andric   std::enable_if_t<std::is_base_of_v<StorageLocation, T>, T *>
get(const ValueDecl & D)342cb14a3feSDimitry Andric   get(const ValueDecl &D) const {
343cb14a3feSDimitry Andric     return cast_or_null<T>(getStorageLocation(D));
344cb14a3feSDimitry Andric   }
345cb14a3feSDimitry Andric   template <typename T>
346cb14a3feSDimitry Andric   std::enable_if_t<std::is_base_of_v<StorageLocation, T>, T *>
get(const Expr & E)347cb14a3feSDimitry Andric   get(const Expr &E) const {
348cb14a3feSDimitry Andric     return cast_or_null<T>(getStorageLocation(E));
349cb14a3feSDimitry Andric   }
350cb14a3feSDimitry Andric 
35104eeddc0SDimitry Andric   /// Returns the storage location assigned to the `this` pointee in the
35204eeddc0SDimitry Andric   /// environment or null if the `this` pointee has no assigned storage location
35304eeddc0SDimitry Andric   /// in the environment.
getThisPointeeStorageLocation()3545f757f3fSDimitry Andric   RecordStorageLocation *getThisPointeeStorageLocation() const {
3555f757f3fSDimitry Andric     return ThisPointeeLoc;
3565f757f3fSDimitry Andric   }
3575f757f3fSDimitry Andric 
3585f757f3fSDimitry Andric   /// Sets the storage location assigned to the `this` pointee in the
3595f757f3fSDimitry Andric   /// environment.
setThisPointeeStorageLocation(RecordStorageLocation & Loc)3605f757f3fSDimitry Andric   void setThisPointeeStorageLocation(RecordStorageLocation &Loc) {
3615f757f3fSDimitry Andric     ThisPointeeLoc = &Loc;
3625f757f3fSDimitry Andric   }
36304eeddc0SDimitry Andric 
36406c3fb27SDimitry Andric   /// Returns the location of the result object for a record-type prvalue.
36506c3fb27SDimitry Andric   ///
36606c3fb27SDimitry Andric   /// In C++, prvalues of record type serve only a limited purpose: They can
36706c3fb27SDimitry Andric   /// only be used to initialize a result object (e.g. a variable or a
36806c3fb27SDimitry Andric   /// temporary). This function returns the location of that result object.
36906c3fb27SDimitry Andric   ///
37006c3fb27SDimitry Andric   /// When creating a prvalue of record type, we already need the storage
37106c3fb27SDimitry Andric   /// location of the result object to pass in `this`, even though prvalues are
37206c3fb27SDimitry Andric   /// otherwise not associated with storage locations.
37306c3fb27SDimitry Andric   ///
37406c3fb27SDimitry Andric   /// Requirements:
37506c3fb27SDimitry Andric   ///  `E` must be a prvalue of record type.
376cb14a3feSDimitry Andric   RecordStorageLocation &
377cb14a3feSDimitry Andric   getResultObjectLocation(const Expr &RecordPRValue) const;
37806c3fb27SDimitry Andric 
379*0fca6ea1SDimitry Andric   /// Returns the return value of the function currently being analyzed.
380*0fca6ea1SDimitry Andric   /// This can be null if:
38106c3fb27SDimitry Andric   /// - The function has a void return type
38206c3fb27SDimitry Andric   /// - No return value could be determined for the function, for example
38306c3fb27SDimitry Andric   ///   because it calls a function without a body.
38406c3fb27SDimitry Andric   ///
38506c3fb27SDimitry Andric   /// Requirements:
386*0fca6ea1SDimitry Andric   ///  The current analysis target must be a function and must have a
387*0fca6ea1SDimitry Andric   ///  non-reference return type.
getReturnValue()38806c3fb27SDimitry Andric   Value *getReturnValue() const {
38906c3fb27SDimitry Andric     assert(getCurrentFunc() != nullptr &&
39006c3fb27SDimitry Andric            !getCurrentFunc()->getReturnType()->isReferenceType());
39106c3fb27SDimitry Andric     return ReturnVal;
39206c3fb27SDimitry Andric   }
39306c3fb27SDimitry Andric 
394*0fca6ea1SDimitry Andric   /// Returns the storage location for the reference returned by the function
395*0fca6ea1SDimitry Andric   /// currently being analyzed. This can be null if the function doesn't return
396*0fca6ea1SDimitry Andric   /// a single consistent reference.
39706c3fb27SDimitry Andric   ///
39806c3fb27SDimitry Andric   /// Requirements:
399*0fca6ea1SDimitry Andric   ///  The current analysis target must be a function and must have a reference
400*0fca6ea1SDimitry Andric   ///  return type.
getReturnStorageLocation()40106c3fb27SDimitry Andric   StorageLocation *getReturnStorageLocation() const {
40206c3fb27SDimitry Andric     assert(getCurrentFunc() != nullptr &&
40306c3fb27SDimitry Andric            getCurrentFunc()->getReturnType()->isReferenceType());
40406c3fb27SDimitry Andric     return ReturnLoc;
40506c3fb27SDimitry Andric   }
40606c3fb27SDimitry Andric 
407*0fca6ea1SDimitry Andric   /// Sets the return value of the function currently being analyzed.
40806c3fb27SDimitry Andric   ///
40906c3fb27SDimitry Andric   /// Requirements:
410*0fca6ea1SDimitry Andric   ///  The current analysis target must be a function and must have a
411*0fca6ea1SDimitry Andric   ///  non-reference return type.
setReturnValue(Value * Val)41206c3fb27SDimitry Andric   void setReturnValue(Value *Val) {
41306c3fb27SDimitry Andric     assert(getCurrentFunc() != nullptr &&
41406c3fb27SDimitry Andric            !getCurrentFunc()->getReturnType()->isReferenceType());
41506c3fb27SDimitry Andric     ReturnVal = Val;
41606c3fb27SDimitry Andric   }
41706c3fb27SDimitry Andric 
418*0fca6ea1SDimitry Andric   /// Sets the storage location for the reference returned by the function
419*0fca6ea1SDimitry Andric   /// currently being analyzed.
42006c3fb27SDimitry Andric   ///
42106c3fb27SDimitry Andric   /// Requirements:
422*0fca6ea1SDimitry Andric   ///  The current analysis target must be a function and must have a reference
423*0fca6ea1SDimitry Andric   ///  return type.
setReturnStorageLocation(StorageLocation * Loc)42406c3fb27SDimitry Andric   void setReturnStorageLocation(StorageLocation *Loc) {
42506c3fb27SDimitry Andric     assert(getCurrentFunc() != nullptr &&
42606c3fb27SDimitry Andric            getCurrentFunc()->getReturnType()->isReferenceType());
42706c3fb27SDimitry Andric     ReturnLoc = Loc;
42806c3fb27SDimitry Andric   }
429bdd1243dSDimitry Andric 
43081ad6265SDimitry Andric   /// Returns a pointer value that represents a null pointer. Calls with
43181ad6265SDimitry Andric   /// `PointeeType` that are canonically equivalent will return the same result.
43281ad6265SDimitry Andric   PointerValue &getOrCreateNullPointerValue(QualType PointeeType);
43381ad6265SDimitry Andric 
43404eeddc0SDimitry Andric   /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
43506c3fb27SDimitry Andric   /// returns null.
43606c3fb27SDimitry Andric   ///
43706c3fb27SDimitry Andric   /// If `Type` is a pointer or reference type, creates all the necessary
43806c3fb27SDimitry Andric   /// storage locations and values for indirections until it finds a
43904eeddc0SDimitry Andric   /// non-pointer/non-reference type.
44004eeddc0SDimitry Andric   ///
44106c3fb27SDimitry Andric   /// If `Type` is one of the following types, this function will always return
44206c3fb27SDimitry Andric   /// a non-null pointer:
44306c3fb27SDimitry Andric   /// - `bool`
44406c3fb27SDimitry Andric   /// - Any integer type
44506c3fb27SDimitry Andric   ///
44604eeddc0SDimitry Andric   /// Requirements:
44704eeddc0SDimitry Andric   ///
448*0fca6ea1SDimitry Andric   ///  - `Type` must not be null.
449*0fca6ea1SDimitry Andric   ///  - `Type` must not be a reference type or record type.
45004eeddc0SDimitry Andric   Value *createValue(QualType Type);
45104eeddc0SDimitry Andric 
45206c3fb27SDimitry Andric   /// Creates an object (i.e. a storage location with an associated value) of
45306c3fb27SDimitry Andric   /// type `Ty`. If `InitExpr` is non-null and has a value associated with it,
45406c3fb27SDimitry Andric   /// initializes the object with this value. Otherwise, initializes the object
45506c3fb27SDimitry Andric   /// with a value created using `createValue()`.
45606c3fb27SDimitry Andric   StorageLocation &createObject(QualType Ty, const Expr *InitExpr = nullptr) {
45706c3fb27SDimitry Andric     return createObjectInternal(nullptr, Ty, InitExpr);
45806c3fb27SDimitry Andric   }
45906c3fb27SDimitry Andric 
46006c3fb27SDimitry Andric   /// Creates an object for the variable declaration `D`. If `D` has an
46106c3fb27SDimitry Andric   /// initializer and this initializer is associated with a value, initializes
46206c3fb27SDimitry Andric   /// the object with this value.  Otherwise, initializes the object with a
46306c3fb27SDimitry Andric   /// value created using `createValue()`. Uses the storage location returned by
46406c3fb27SDimitry Andric   /// `DataflowAnalysisContext::getStableStorageLocation(D)`.
createObject(const VarDecl & D)46506c3fb27SDimitry Andric   StorageLocation &createObject(const VarDecl &D) {
46606c3fb27SDimitry Andric     return createObjectInternal(&D, D.getType(), D.getInit());
46706c3fb27SDimitry Andric   }
46806c3fb27SDimitry Andric 
46906c3fb27SDimitry Andric   /// Creates an object for the variable declaration `D`. If `InitExpr` is
47006c3fb27SDimitry Andric   /// non-null and has a value associated with it, initializes the object with
47106c3fb27SDimitry Andric   /// this value. Otherwise, initializes the object with a value created using
47206c3fb27SDimitry Andric   /// `createValue()`.  Uses the storage location returned by
47306c3fb27SDimitry Andric   /// `DataflowAnalysisContext::getStableStorageLocation(D)`.
createObject(const ValueDecl & D,const Expr * InitExpr)4745f757f3fSDimitry Andric   StorageLocation &createObject(const ValueDecl &D, const Expr *InitExpr) {
47506c3fb27SDimitry Andric     return createObjectInternal(&D, D.getType(), InitExpr);
47606c3fb27SDimitry Andric   }
47706c3fb27SDimitry Andric 
478*0fca6ea1SDimitry Andric   /// Initializes the fields (including synthetic fields) of `Loc` with values,
479*0fca6ea1SDimitry Andric   /// unless values of the field type are not supported or we hit one of the
480*0fca6ea1SDimitry Andric   /// limits at which we stop producing values.
481*0fca6ea1SDimitry Andric   /// If a field already has a value, that value is preserved.
482*0fca6ea1SDimitry Andric   /// If `Type` is provided, initializes only those fields that are modeled for
483*0fca6ea1SDimitry Andric   /// `Type`; this is intended for use in cases where `Loc` is a derived type
484*0fca6ea1SDimitry Andric   /// and we only want to initialize the fields of a base type.
485*0fca6ea1SDimitry Andric   void initializeFieldsWithValues(RecordStorageLocation &Loc, QualType Type);
initializeFieldsWithValues(RecordStorageLocation & Loc)486*0fca6ea1SDimitry Andric   void initializeFieldsWithValues(RecordStorageLocation &Loc) {
487*0fca6ea1SDimitry Andric     initializeFieldsWithValues(Loc, Loc.getType());
488*0fca6ea1SDimitry Andric   }
489*0fca6ea1SDimitry Andric 
49004eeddc0SDimitry Andric   /// Assigns `Val` as the value of `Loc` in the environment.
491*0fca6ea1SDimitry Andric   ///
492*0fca6ea1SDimitry Andric   /// Requirements:
493*0fca6ea1SDimitry Andric   ///
494*0fca6ea1SDimitry Andric   ///  `Loc` must not be a `RecordStorageLocation`.
49504eeddc0SDimitry Andric   void setValue(const StorageLocation &Loc, Value &Val);
49604eeddc0SDimitry Andric 
49706c3fb27SDimitry Andric   /// Clears any association between `Loc` and a value in the environment.
clearValue(const StorageLocation & Loc)49806c3fb27SDimitry Andric   void clearValue(const StorageLocation &Loc) { LocToVal.erase(&Loc); }
49906c3fb27SDimitry Andric 
50006c3fb27SDimitry Andric   /// Assigns `Val` as the value of the prvalue `E` in the environment.
50106c3fb27SDimitry Andric   ///
50206c3fb27SDimitry Andric   /// Requirements:
50306c3fb27SDimitry Andric   ///
504*0fca6ea1SDimitry Andric   ///  - `E` must be a prvalue.
505*0fca6ea1SDimitry Andric   ///  - `E` must not have record type.
5065f757f3fSDimitry Andric   void setValue(const Expr &E, Value &Val);
50706c3fb27SDimitry Andric 
50804eeddc0SDimitry Andric   /// Returns the value assigned to `Loc` in the environment or null if `Loc`
50904eeddc0SDimitry Andric   /// isn't assigned a value in the environment.
510*0fca6ea1SDimitry Andric   ///
511*0fca6ea1SDimitry Andric   /// Requirements:
512*0fca6ea1SDimitry Andric   ///
513*0fca6ea1SDimitry Andric   ///  `Loc` must not be a `RecordStorageLocation`.
51404eeddc0SDimitry Andric   Value *getValue(const StorageLocation &Loc) const;
51504eeddc0SDimitry Andric 
5165f757f3fSDimitry Andric   /// Equivalent to `getValue(getStorageLocation(D))` if `D` is assigned a
5175f757f3fSDimitry Andric   /// storage location in the environment, otherwise returns null.
518*0fca6ea1SDimitry Andric   ///
519*0fca6ea1SDimitry Andric   /// Requirements:
520*0fca6ea1SDimitry Andric   ///
521*0fca6ea1SDimitry Andric   ///  `D` must not have record type.
52206c3fb27SDimitry Andric   Value *getValue(const ValueDecl &D) const;
52304eeddc0SDimitry Andric 
5245f757f3fSDimitry Andric   /// Equivalent to `getValue(getStorageLocation(E, SP))` if `E` is assigned a
5255f757f3fSDimitry Andric   /// storage location in the environment, otherwise returns null.
5265f757f3fSDimitry Andric   Value *getValue(const Expr &E) const;
52706c3fb27SDimitry Andric 
528cb14a3feSDimitry Andric   /// Returns the result of casting `getValue(...)` to a subclass of `Value`
529cb14a3feSDimitry Andric   /// (using `cast_or_null<T>`).
530cb14a3feSDimitry Andric   /// This assert-fails if the result of `getValue(...)` is not of type `T *`;
531cb14a3feSDimitry Andric   /// if the value is not guaranteed to have type `T *`, consider using
532cb14a3feSDimitry Andric   /// `dyn_cast_or_null<T>(getValue(...))` instead.
533cb14a3feSDimitry Andric   template <typename T>
534cb14a3feSDimitry Andric   std::enable_if_t<std::is_base_of_v<Value, T>, T *>
get(const StorageLocation & Loc)535cb14a3feSDimitry Andric   get(const StorageLocation &Loc) const {
536cb14a3feSDimitry Andric     return cast_or_null<T>(getValue(Loc));
537cb14a3feSDimitry Andric   }
538cb14a3feSDimitry Andric   template <typename T>
539cb14a3feSDimitry Andric   std::enable_if_t<std::is_base_of_v<Value, T>, T *>
get(const ValueDecl & D)540cb14a3feSDimitry Andric   get(const ValueDecl &D) const {
541cb14a3feSDimitry Andric     return cast_or_null<T>(getValue(D));
542cb14a3feSDimitry Andric   }
543cb14a3feSDimitry Andric   template <typename T>
get(const Expr & E)544cb14a3feSDimitry Andric   std::enable_if_t<std::is_base_of_v<Value, T>, T *> get(const Expr &E) const {
545cb14a3feSDimitry Andric     return cast_or_null<T>(getValue(E));
546cb14a3feSDimitry Andric   }
547cb14a3feSDimitry Andric 
54806c3fb27SDimitry Andric   // FIXME: should we deprecate the following & call arena().create() directly?
54906c3fb27SDimitry Andric 
55006c3fb27SDimitry Andric   /// Creates a `T` (some subclass of `Value`), forwarding `args` to the
55106c3fb27SDimitry Andric   /// constructor, and returns a reference to it.
55206c3fb27SDimitry Andric   ///
55306c3fb27SDimitry Andric   /// The analysis context takes ownership of the created object. The object
55406c3fb27SDimitry Andric   /// will be destroyed when the analysis context is destroyed.
55506c3fb27SDimitry Andric   template <typename T, typename... Args>
55606c3fb27SDimitry Andric   std::enable_if_t<std::is_base_of<Value, T>::value, T &>
create(Args &&...args)55706c3fb27SDimitry Andric   create(Args &&...args) {
55806c3fb27SDimitry Andric     return arena().create<T>(std::forward<Args>(args)...);
55904eeddc0SDimitry Andric   }
56004eeddc0SDimitry Andric 
56106c3fb27SDimitry Andric   /// Returns a symbolic integer value that models an integer literal equal to
56206c3fb27SDimitry Andric   /// `Value`
getIntLiteralValue(llvm::APInt Value)56306c3fb27SDimitry Andric   IntegerValue &getIntLiteralValue(llvm::APInt Value) const {
56406c3fb27SDimitry Andric     return arena().makeIntLiteral(Value);
56504eeddc0SDimitry Andric   }
56604eeddc0SDimitry Andric 
56704eeddc0SDimitry Andric   /// Returns a symbolic boolean value that models a boolean literal equal to
56804eeddc0SDimitry Andric   /// `Value`
getBoolLiteralValue(bool Value)5695f757f3fSDimitry Andric   BoolValue &getBoolLiteralValue(bool Value) const {
5705f757f3fSDimitry Andric     return arena().makeBoolValue(arena().makeLiteral(Value));
57104eeddc0SDimitry Andric   }
57204eeddc0SDimitry Andric 
57381ad6265SDimitry Andric   /// Returns an atomic boolean value.
makeAtomicBoolValue()57481ad6265SDimitry Andric   BoolValue &makeAtomicBoolValue() const {
57506c3fb27SDimitry Andric     return arena().makeAtomValue();
57681ad6265SDimitry Andric   }
57781ad6265SDimitry Andric 
578bdd1243dSDimitry Andric   /// Returns a unique instance of boolean Top.
makeTopBoolValue()579bdd1243dSDimitry Andric   BoolValue &makeTopBoolValue() const {
58006c3fb27SDimitry Andric     return arena().makeTopValue();
581bdd1243dSDimitry Andric   }
582bdd1243dSDimitry Andric 
58381ad6265SDimitry Andric   /// Returns a boolean value that represents the conjunction of `LHS` and
58481ad6265SDimitry Andric   /// `RHS`. Subsequent calls with the same arguments, regardless of their
58581ad6265SDimitry Andric   /// order, will return the same result. If the given boolean values represent
58681ad6265SDimitry Andric   /// the same value, the result will be the value itself.
makeAnd(BoolValue & LHS,BoolValue & RHS)58781ad6265SDimitry Andric   BoolValue &makeAnd(BoolValue &LHS, BoolValue &RHS) const {
58806c3fb27SDimitry Andric     return arena().makeBoolValue(
58906c3fb27SDimitry Andric         arena().makeAnd(LHS.formula(), RHS.formula()));
59081ad6265SDimitry Andric   }
59181ad6265SDimitry Andric 
59281ad6265SDimitry Andric   /// Returns a boolean value that represents the disjunction of `LHS` and
59381ad6265SDimitry Andric   /// `RHS`. Subsequent calls with the same arguments, regardless of their
59481ad6265SDimitry Andric   /// order, will return the same result. If the given boolean values represent
59581ad6265SDimitry Andric   /// the same value, the result will be the value itself.
makeOr(BoolValue & LHS,BoolValue & RHS)59681ad6265SDimitry Andric   BoolValue &makeOr(BoolValue &LHS, BoolValue &RHS) const {
59706c3fb27SDimitry Andric     return arena().makeBoolValue(
59806c3fb27SDimitry Andric         arena().makeOr(LHS.formula(), RHS.formula()));
59981ad6265SDimitry Andric   }
60081ad6265SDimitry Andric 
60181ad6265SDimitry Andric   /// Returns a boolean value that represents the negation of `Val`. Subsequent
60281ad6265SDimitry Andric   /// calls with the same argument will return the same result.
makeNot(BoolValue & Val)60381ad6265SDimitry Andric   BoolValue &makeNot(BoolValue &Val) const {
60406c3fb27SDimitry Andric     return arena().makeBoolValue(arena().makeNot(Val.formula()));
60581ad6265SDimitry Andric   }
60681ad6265SDimitry Andric 
60781ad6265SDimitry Andric   /// Returns a boolean value represents `LHS` => `RHS`. Subsequent calls with
60881ad6265SDimitry Andric   /// the same arguments, will return the same result. If the given boolean
60981ad6265SDimitry Andric   /// values represent the same value, the result will be a value that
61081ad6265SDimitry Andric   /// represents the true boolean literal.
makeImplication(BoolValue & LHS,BoolValue & RHS)61181ad6265SDimitry Andric   BoolValue &makeImplication(BoolValue &LHS, BoolValue &RHS) const {
61206c3fb27SDimitry Andric     return arena().makeBoolValue(
61306c3fb27SDimitry Andric         arena().makeImplies(LHS.formula(), RHS.formula()));
61481ad6265SDimitry Andric   }
61581ad6265SDimitry Andric 
61681ad6265SDimitry Andric   /// Returns a boolean value represents `LHS` <=> `RHS`. Subsequent calls with
61781ad6265SDimitry Andric   /// the same arguments, regardless of their order, will return the same
61881ad6265SDimitry Andric   /// result. If the given boolean values represent the same value, the result
61981ad6265SDimitry Andric   /// will be a value that represents the true boolean literal.
makeIff(BoolValue & LHS,BoolValue & RHS)62081ad6265SDimitry Andric   BoolValue &makeIff(BoolValue &LHS, BoolValue &RHS) const {
62106c3fb27SDimitry Andric     return arena().makeBoolValue(
62206c3fb27SDimitry Andric         arena().makeEquals(LHS.formula(), RHS.formula()));
62381ad6265SDimitry Andric   }
62481ad6265SDimitry Andric 
62506c3fb27SDimitry Andric   /// Returns a boolean variable that identifies the flow condition (FC).
62606c3fb27SDimitry Andric   ///
62706c3fb27SDimitry Andric   /// The flow condition is a set of facts that are necessarily true when the
62806c3fb27SDimitry Andric   /// program reaches the current point, expressed as boolean formulas.
62906c3fb27SDimitry Andric   /// The flow condition token is equivalent to the AND of these facts.
63006c3fb27SDimitry Andric   ///
63106c3fb27SDimitry Andric   /// These may e.g. constrain the value of certain variables. A pointer
63206c3fb27SDimitry Andric   /// variable may have a consistent modeled PointerValue throughout, but at a
63306c3fb27SDimitry Andric   /// given point the Environment may tell us that the value must be non-null.
63406c3fb27SDimitry Andric   ///
63506c3fb27SDimitry Andric   /// The FC is necessary but not sufficient for this point to be reachable.
63606c3fb27SDimitry Andric   /// In particular, where the FC token appears in flow conditions of successor
63706c3fb27SDimitry Andric   /// environments, it means "point X may have been reached", not
63806c3fb27SDimitry Andric   /// "point X was reached".
getFlowConditionToken()63906c3fb27SDimitry Andric   Atom getFlowConditionToken() const { return FlowConditionToken; }
64081ad6265SDimitry Andric 
64106c3fb27SDimitry Andric   /// Record a fact that must be true if this point in the program is reached.
6425f757f3fSDimitry Andric   void assume(const Formula &);
64381ad6265SDimitry Andric 
64406c3fb27SDimitry Andric   /// Returns true if the formula is always true when this point is reached.
6455f757f3fSDimitry Andric   /// Returns false if the formula may be false (or the flow condition isn't
6465f757f3fSDimitry Andric   /// sufficiently precise to prove that it is true) or if the solver times out.
6475f757f3fSDimitry Andric   ///
6485f757f3fSDimitry Andric   /// Note that there is an asymmetry between this function and `allows()` in
6495f757f3fSDimitry Andric   /// that they both return false if the solver times out. The assumption is
6505f757f3fSDimitry Andric   /// that if `proves()` or `allows()` returns true, this will result in a
6515f757f3fSDimitry Andric   /// diagnostic, and we want to bias towards false negatives in the case where
6525f757f3fSDimitry Andric   /// the solver times out.
6535f757f3fSDimitry Andric   bool proves(const Formula &) const;
6545f757f3fSDimitry Andric 
6555f757f3fSDimitry Andric   /// Returns true if the formula may be true when this point is reached.
6565f757f3fSDimitry Andric   /// Returns false if the formula is always false when this point is reached
6575f757f3fSDimitry Andric   /// (or the flow condition is overly constraining) or if the solver times out.
6585f757f3fSDimitry Andric   bool allows(const Formula &) const;
65981ad6265SDimitry Andric 
66006c3fb27SDimitry Andric   /// Returns the function currently being analyzed, or null if the code being
66106c3fb27SDimitry Andric   /// analyzed isn't part of a function.
getCurrentFunc()66206c3fb27SDimitry Andric   const FunctionDecl *getCurrentFunc() const {
663*0fca6ea1SDimitry Andric     return CallStack.empty() ? InitialTargetFunc : CallStack.back();
66406c3fb27SDimitry Andric   }
66506c3fb27SDimitry Andric 
666*0fca6ea1SDimitry Andric   /// Returns the size of the call stack, not counting the initial analysis
667*0fca6ea1SDimitry Andric   /// target.
callStackSize()6685f757f3fSDimitry Andric   size_t callStackSize() const { return CallStack.size(); }
6695f757f3fSDimitry Andric 
670bdd1243dSDimitry Andric   /// Returns whether this `Environment` can be extended to analyze the given
671*0fca6ea1SDimitry Andric   /// `Callee` (i.e. if `pushCall` can be used).
672*0fca6ea1SDimitry Andric   /// Recursion is not allowed. `MaxDepth` is the maximum size of the call stack
673*0fca6ea1SDimitry Andric   /// (i.e. the maximum value that `callStackSize()` may assume after the call).
674*0fca6ea1SDimitry Andric   bool canDescend(unsigned MaxDepth, const FunctionDecl *Callee) const;
675bdd1243dSDimitry Andric 
67606c3fb27SDimitry Andric   /// Returns the `DataflowAnalysisContext` used by the environment.
getDataflowAnalysisContext()67706c3fb27SDimitry Andric   DataflowAnalysisContext &getDataflowAnalysisContext() const { return *DACtx; }
67806c3fb27SDimitry Andric 
arena()67906c3fb27SDimitry Andric   Arena &arena() const { return DACtx->arena(); }
680bdd1243dSDimitry Andric 
681fcaf7f86SDimitry Andric   LLVM_DUMP_METHOD void dump() const;
682bdd1243dSDimitry Andric   LLVM_DUMP_METHOD void dump(raw_ostream &OS) const;
683fcaf7f86SDimitry Andric 
68404eeddc0SDimitry Andric private:
685*0fca6ea1SDimitry Andric   using PrValueToResultObject =
686*0fca6ea1SDimitry Andric       llvm::DenseMap<const Expr *, RecordStorageLocation *>;
687*0fca6ea1SDimitry Andric 
68806c3fb27SDimitry Andric   // The copy-constructor is for use in fork() only.
68906c3fb27SDimitry Andric   Environment(const Environment &) = default;
69006c3fb27SDimitry Andric 
69104eeddc0SDimitry Andric   /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
69204eeddc0SDimitry Andric   /// return null.
69304eeddc0SDimitry Andric   ///
69404eeddc0SDimitry Andric   /// Recursively initializes storage locations and values until it sees a
69504eeddc0SDimitry Andric   /// self-referential pointer or reference type. `Visited` is used to track
69604eeddc0SDimitry Andric   /// which types appeared in the reference/pointer chain in order to avoid
69704eeddc0SDimitry Andric   /// creating a cyclic dependency with self-referential pointers/references.
69804eeddc0SDimitry Andric   ///
69904eeddc0SDimitry Andric   /// Requirements:
70004eeddc0SDimitry Andric   ///
70104eeddc0SDimitry Andric   ///  `Type` must not be null.
70204eeddc0SDimitry Andric   Value *createValueUnlessSelfReferential(QualType Type,
70381ad6265SDimitry Andric                                           llvm::DenseSet<QualType> &Visited,
70481ad6265SDimitry Andric                                           int Depth, int &CreatedValuesCount);
70504eeddc0SDimitry Andric 
70606c3fb27SDimitry Andric   /// Creates a storage location for `Ty`. Also creates and associates a value
70706c3fb27SDimitry Andric   /// with the storage location, unless values of this type are not supported or
70806c3fb27SDimitry Andric   /// we hit one of the limits at which we stop producing values (controlled by
70906c3fb27SDimitry Andric   /// `Visited`, `Depth`, and `CreatedValuesCount`).
71006c3fb27SDimitry Andric   StorageLocation &createLocAndMaybeValue(QualType Ty,
71106c3fb27SDimitry Andric                                           llvm::DenseSet<QualType> &Visited,
71206c3fb27SDimitry Andric                                           int Depth, int &CreatedValuesCount);
71306c3fb27SDimitry Andric 
714*0fca6ea1SDimitry Andric   /// Initializes the fields (including synthetic fields) of `Loc` with values,
715*0fca6ea1SDimitry Andric   /// unless values of the field type are not supported or we hit one of the
716*0fca6ea1SDimitry Andric   /// limits at which we stop producing values (controlled by `Visited`,
717*0fca6ea1SDimitry Andric   /// `Depth`, and `CreatedValuesCount`). If `Type` is different from
718*0fca6ea1SDimitry Andric   /// `Loc.getType()`, initializes only those fields that are modeled for
719*0fca6ea1SDimitry Andric   /// `Type`.
720*0fca6ea1SDimitry Andric   void initializeFieldsWithValues(RecordStorageLocation &Loc, QualType Type,
721*0fca6ea1SDimitry Andric                                   llvm::DenseSet<QualType> &Visited, int Depth,
722*0fca6ea1SDimitry Andric                                   int &CreatedValuesCount);
723*0fca6ea1SDimitry Andric 
72406c3fb27SDimitry Andric   /// Shared implementation of `createObject()` overloads.
72506c3fb27SDimitry Andric   /// `D` and `InitExpr` may be null.
7265f757f3fSDimitry Andric   StorageLocation &createObjectInternal(const ValueDecl *D, QualType Ty,
72706c3fb27SDimitry Andric                                         const Expr *InitExpr);
72806c3fb27SDimitry Andric 
729bdd1243dSDimitry Andric   /// Shared implementation of `pushCall` overloads. Note that unlike
730bdd1243dSDimitry Andric   /// `pushCall`, this member is invoked on the environment of the callee, not
731bdd1243dSDimitry Andric   /// of the caller.
732bdd1243dSDimitry Andric   void pushCallInternal(const FunctionDecl *FuncDecl,
733bdd1243dSDimitry Andric                         ArrayRef<const Expr *> Args);
734bdd1243dSDimitry Andric 
73506c3fb27SDimitry Andric   /// Assigns storage locations and values to all global variables, fields
736*0fca6ea1SDimitry Andric   /// and functions in `Referenced`.
737*0fca6ea1SDimitry Andric   void initFieldsGlobalsAndFuncs(const ReferencedDecls &Referenced);
738*0fca6ea1SDimitry Andric 
739*0fca6ea1SDimitry Andric   static PrValueToResultObject
740*0fca6ea1SDimitry Andric   buildResultObjectMap(DataflowAnalysisContext *DACtx,
741*0fca6ea1SDimitry Andric                        const FunctionDecl *FuncDecl,
742*0fca6ea1SDimitry Andric                        RecordStorageLocation *ThisPointeeLoc,
743*0fca6ea1SDimitry Andric                        RecordStorageLocation *LocForRecordReturnVal);
744*0fca6ea1SDimitry Andric 
745*0fca6ea1SDimitry Andric   static PrValueToResultObject
746*0fca6ea1SDimitry Andric   buildResultObjectMap(DataflowAnalysisContext *DACtx, Stmt *S,
747*0fca6ea1SDimitry Andric                        RecordStorageLocation *ThisPointeeLoc,
748*0fca6ea1SDimitry Andric                        RecordStorageLocation *LocForRecordReturnVal);
749bdd1243dSDimitry Andric 
75004eeddc0SDimitry Andric   // `DACtx` is not null and not owned by this object.
75104eeddc0SDimitry Andric   DataflowAnalysisContext *DACtx;
75204eeddc0SDimitry Andric 
753*0fca6ea1SDimitry Andric   // FIXME: move the fields `CallStack`, `ResultObjectMap`, `ReturnVal`,
754*0fca6ea1SDimitry Andric   // `ReturnLoc` and `ThisPointeeLoc` into a separate call-context object,
755*0fca6ea1SDimitry Andric   // shared between environments in the same call.
756bdd1243dSDimitry Andric   // https://github.com/llvm/llvm-project/issues/59005
757bdd1243dSDimitry Andric 
758*0fca6ea1SDimitry Andric   // The stack of functions called from the initial analysis target.
759*0fca6ea1SDimitry Andric   std::vector<const FunctionDecl *> CallStack;
760bdd1243dSDimitry Andric 
761*0fca6ea1SDimitry Andric   // Initial function to analyze, if a function was passed to the constructor.
762*0fca6ea1SDimitry Andric   // Null otherwise.
763*0fca6ea1SDimitry Andric   const FunctionDecl *InitialTargetFunc = nullptr;
764*0fca6ea1SDimitry Andric   // Top-level statement of the initial analysis target.
765*0fca6ea1SDimitry Andric   // If a function was passed to the constructor, this is its body.
766*0fca6ea1SDimitry Andric   // If a statement was passed to the constructor, this is that statement.
767*0fca6ea1SDimitry Andric   // Null if no analysis target was passed to the constructor.
768*0fca6ea1SDimitry Andric   Stmt *InitialTargetStmt = nullptr;
769*0fca6ea1SDimitry Andric 
770*0fca6ea1SDimitry Andric   // Maps from prvalues of record type to their result objects. Shared between
771*0fca6ea1SDimitry Andric   // all environments for the same analysis target.
772*0fca6ea1SDimitry Andric   // FIXME: It's somewhat unsatisfactory that we have to use a `shared_ptr`
773*0fca6ea1SDimitry Andric   // here, though the cost is acceptable: The overhead of a `shared_ptr` is
774*0fca6ea1SDimitry Andric   // incurred when it is copied, and this happens only relatively rarely (when
775*0fca6ea1SDimitry Andric   // we fork the environment). The need for a `shared_ptr` will go away once we
776*0fca6ea1SDimitry Andric   // introduce a shared call-context object (see above).
777*0fca6ea1SDimitry Andric   std::shared_ptr<PrValueToResultObject> ResultObjectMap;
778*0fca6ea1SDimitry Andric 
779*0fca6ea1SDimitry Andric   // The following three member variables handle various different types of
780*0fca6ea1SDimitry Andric   // return values when the current analysis target is a function.
781*0fca6ea1SDimitry Andric   // - If the return type is not a reference and not a record: Value returned
782*0fca6ea1SDimitry Andric   //   by the function.
78306c3fb27SDimitry Andric   Value *ReturnVal = nullptr;
784*0fca6ea1SDimitry Andric   // - If the return type is a reference: Storage location of the reference
785*0fca6ea1SDimitry Andric   //   returned by the function.
786bdd1243dSDimitry Andric   StorageLocation *ReturnLoc = nullptr;
787*0fca6ea1SDimitry Andric   // - If the return type is a record or the function being analyzed is a
788*0fca6ea1SDimitry Andric   //   constructor: Storage location into which the return value should be
789*0fca6ea1SDimitry Andric   //   constructed.
790*0fca6ea1SDimitry Andric   RecordStorageLocation *LocForRecordReturnVal = nullptr;
791*0fca6ea1SDimitry Andric 
792bdd1243dSDimitry Andric   // The storage location of the `this` pointee. Should only be null if the
793*0fca6ea1SDimitry Andric   // analysis target is not a method.
7945f757f3fSDimitry Andric   RecordStorageLocation *ThisPointeeLoc = nullptr;
795bdd1243dSDimitry Andric 
7965f757f3fSDimitry Andric   // Maps from declarations and glvalue expression to storage locations that are
79704eeddc0SDimitry Andric   // assigned to them. Unlike the maps in `DataflowAnalysisContext`, these
79804eeddc0SDimitry Andric   // include only storage locations that are in scope for a particular basic
79904eeddc0SDimitry Andric   // block.
80004eeddc0SDimitry Andric   llvm::DenseMap<const ValueDecl *, StorageLocation *> DeclToLoc;
80104eeddc0SDimitry Andric   llvm::DenseMap<const Expr *, StorageLocation *> ExprToLoc;
8025f757f3fSDimitry Andric   // Maps from prvalue expressions and storage locations to the values that
8035f757f3fSDimitry Andric   // are assigned to them.
80406c3fb27SDimitry Andric   // We preserve insertion order so that join/widen process values in
80506c3fb27SDimitry Andric   // deterministic sequence. This in turn produces deterministic SAT formulas.
8065f757f3fSDimitry Andric   llvm::MapVector<const Expr *, Value *> ExprToVal;
80706c3fb27SDimitry Andric   llvm::MapVector<const StorageLocation *, Value *> LocToVal;
80804eeddc0SDimitry Andric 
80906c3fb27SDimitry Andric   Atom FlowConditionToken;
81004eeddc0SDimitry Andric };
81104eeddc0SDimitry Andric 
81206c3fb27SDimitry Andric /// Returns the storage location for the implicit object of a
81306c3fb27SDimitry Andric /// `CXXMemberCallExpr`, or null if none is defined in the environment.
81406c3fb27SDimitry Andric /// Dereferences the pointer if the member call expression was written using
81506c3fb27SDimitry Andric /// `->`.
8165f757f3fSDimitry Andric RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
8175f757f3fSDimitry Andric                                                  const Environment &Env);
81806c3fb27SDimitry Andric 
81906c3fb27SDimitry Andric /// Returns the storage location for the base object of a `MemberExpr`, or null
82006c3fb27SDimitry Andric /// if none is defined in the environment. Dereferences the pointer if the
82106c3fb27SDimitry Andric /// member expression was written using `->`.
8225f757f3fSDimitry Andric RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
82306c3fb27SDimitry Andric                                              const Environment &Env);
82406c3fb27SDimitry Andric 
8254824e7fdSDimitry Andric } // namespace dataflow
8264824e7fdSDimitry Andric } // namespace clang
8274824e7fdSDimitry Andric 
8284824e7fdSDimitry Andric #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H
829