clang  16.0.0git
DataflowAnalysisContext.h
Go to the documentation of this file.
1 //===-- DataflowAnalysisContext.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 a DataflowAnalysisContext class that owns objects that
10 // encompass the state of a program and stores context that is used during
11 // dataflow analysis.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSISCONTEXT_H
16 #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSISCONTEXT_H
17 
18 #include "clang/AST/Decl.h"
19 #include "clang/AST/Expr.h"
20 #include "clang/AST/TypeOrdering.h"
25 #include "llvm/ADT/DenseMap.h"
26 #include "llvm/ADT/DenseSet.h"
27 #include "llvm/Support/Compiler.h"
28 #include <cassert>
29 #include <memory>
30 #include <type_traits>
31 #include <utility>
32 #include <vector>
33 
34 namespace clang {
35 namespace dataflow {
36 
37 /// Skip past nodes that the CFG does not emit. These nodes are invisible to
38 /// flow-sensitive analysis, and should be ignored as they will effectively not
39 /// exist.
40 ///
41 /// * `ParenExpr` - The CFG takes the operator precedence into account, but
42 /// otherwise omits the node afterwards.
43 ///
44 /// * `ExprWithCleanups` - The CFG will generate the appropriate calls to
45 /// destructors and then omit the node.
46 ///
47 const Expr &ignoreCFGOmittedNodes(const Expr &E);
48 const Stmt &ignoreCFGOmittedNodes(const Stmt &S);
49 
50 /// Returns the set of all fields in the type.
52 
53 /// Owns objects that encompass the state of a program and stores context that
54 /// is used during dataflow analysis.
56 public:
57  /// Constructs a dataflow analysis context.
58  ///
59  /// Requirements:
60  ///
61  /// `S` must not be null.
62  DataflowAnalysisContext(std::unique_ptr<Solver> S)
63  : S(std::move(S)), TrueVal(createAtomicBoolValue()),
64  FalseVal(createAtomicBoolValue()) {
65  assert(this->S != nullptr);
66  }
67 
68  /// Takes ownership of `Loc` and returns a reference to it.
69  ///
70  /// Requirements:
71  ///
72  /// `Loc` must not be null.
73  template <typename T>
74  std::enable_if_t<std::is_base_of<StorageLocation, T>::value, T &>
75  takeOwnership(std::unique_ptr<T> Loc) {
76  assert(Loc != nullptr);
77  Locs.push_back(std::move(Loc));
78  return *cast<T>(Locs.back().get());
79  }
80 
81  /// Takes ownership of `Val` and returns a reference to it.
82  ///
83  /// Requirements:
84  ///
85  /// `Val` must not be null.
86  template <typename T>
87  std::enable_if_t<std::is_base_of<Value, T>::value, T &>
88  takeOwnership(std::unique_ptr<T> Val) {
89  assert(Val != nullptr);
90  Vals.push_back(std::move(Val));
91  return *cast<T>(Vals.back().get());
92  }
93 
94  /// Returns a new storage location appropriate for `Type`.
95  ///
96  /// A null `Type` is interpreted as the pointee type of `std::nullptr_t`.
98 
99  /// Returns a stable storage location for `D`.
101 
102  /// Returns a stable storage location for `E`.
104 
105  /// Assigns `Loc` as the storage location of `D`.
106  ///
107  /// Requirements:
108  ///
109  /// `D` must not be assigned a storage location.
111  assert(DeclToLoc.find(&D) == DeclToLoc.end());
112  DeclToLoc[&D] = &Loc;
113  }
114 
115  /// Returns the storage location assigned to `D` or null if `D` has no
116  /// assigned storage location.
118  auto It = DeclToLoc.find(&D);
119  return It == DeclToLoc.end() ? nullptr : It->second;
120  }
121 
122  /// Assigns `Loc` as the storage location of `E`.
123  ///
124  /// Requirements:
125  ///
126  /// `E` must not be assigned a storage location.
127  void setStorageLocation(const Expr &E, StorageLocation &Loc) {
128  const Expr &CanonE = ignoreCFGOmittedNodes(E);
129  assert(ExprToLoc.find(&CanonE) == ExprToLoc.end());
130  ExprToLoc[&CanonE] = &Loc;
131  }
132 
133  /// Returns the storage location assigned to `E` or null if `E` has no
134  /// assigned storage location.
136  auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));
137  return It == ExprToLoc.end() ? nullptr : It->second;
138  }
139 
140  /// Returns a pointer value that represents a null pointer. Calls with
141  /// `PointeeType` that are canonically equivalent will return the same result.
142  /// A null `PointeeType` can be used for the pointee of `std::nullptr_t`.
144 
145  /// Returns a symbolic boolean value that models a boolean literal equal to
146  /// `Value`.
148  return Value ? TrueVal : FalseVal;
149  }
150 
151  /// Creates an atomic boolean value.
153  return takeOwnership(std::make_unique<AtomicBoolValue>());
154  }
155 
156  /// Creates a Top value for booleans. Each instance is unique and can be
157  /// assigned a distinct truth value during solving.
158  ///
159  /// FIXME: `Top iff Top` is true when both Tops are identical (by pointer
160  /// equality), but not when they are distinct values. We should improve the
161  /// implementation so that `Top iff Top` has a consistent meaning, regardless
162  /// of the identity of `Top`. Moreover, I think the meaning should be
163  /// `false`.
165  return takeOwnership(std::make_unique<TopBoolValue>());
166  }
167 
168  /// Returns a boolean value that represents the conjunction of `LHS` and
169  /// `RHS`. Subsequent calls with the same arguments, regardless of their
170  /// order, will return the same result. If the given boolean values represent
171  /// the same value, the result will be the value itself.
173 
174  /// Returns a boolean value that represents the disjunction of `LHS` and
175  /// `RHS`. Subsequent calls with the same arguments, regardless of their
176  /// order, will return the same result. If the given boolean values represent
177  /// the same value, the result will be the value itself.
179 
180  /// Returns a boolean value that represents the negation of `Val`. Subsequent
181  /// calls with the same argument will return the same result.
183 
184  /// Returns a boolean value that represents `LHS => RHS`. Subsequent calls
185  /// with the same arguments, will return the same result. If the given boolean
186  /// values represent the same value, the result will be a value that
187  /// represents the true boolean literal.
189 
190  /// Returns a boolean value that represents `LHS <=> RHS`. Subsequent calls
191  /// with the same arguments, regardless of their order, will return the same
192  /// result. If the given boolean values represent the same value, the result
193  /// will be a value that represents the true boolean literal.
195 
196  /// Creates a fresh flow condition and returns a token that identifies it. The
197  /// token can be used to perform various operations on the flow condition such
198  /// as adding constraints to it, forking it, joining it with another flow
199  /// condition, or checking implications.
201 
202  /// Adds `Constraint` to the flow condition identified by `Token`.
204  BoolValue &Constraint);
205 
206  /// Creates a new flow condition with the same constraints as the flow
207  /// condition identified by `Token` and returns its token.
209 
210  /// Creates a new flow condition that represents the disjunction of the flow
211  /// conditions identified by `FirstToken` and `SecondToken`, and returns its
212  /// token.
214  AtomicBoolValue &SecondToken);
215 
216  // FIXME: This function returns the flow condition expressed directly as its
217  // constraints: (C1 AND C2 AND ...). This differs from the general approach in
218  // the framework where a flow condition is represented as a token (an atomic
219  // boolean) with dependencies and constraints tracked in `FlowConditionDeps`
220  // and `FlowConditionConstraints`: (FC <=> C1 AND C2 AND ...).
221  // Consider if we should make the representation of flow condition consistent,
222  // returning an atomic boolean token with separate constraints instead.
223  //
224  /// Builds and returns the logical formula defining the flow condition
225  /// identified by `Token`. If a value in the formula is present as a key in
226  /// `Substitutions`, it will be substituted with the value it maps to.
227  /// As an example, say we have flow condition tokens FC1, FC2, FC3 and
228  /// FlowConditionConstraints: { FC1: C1,
229  /// FC2: C2,
230  /// FC3: (FC1 v FC2) ^ C3 }
231  /// buildAndSubstituteFlowCondition(FC3, {{C1 -> C1'}}) will return a value
232  /// corresponding to (C1' v C2) ^ C3.
235  llvm::DenseMap<AtomicBoolValue *, BoolValue *> Substitutions);
236 
237  /// Returns true if and only if the constraints of the flow condition
238  /// identified by `Token` imply that `Val` is true.
240 
241  /// Returns true if and only if the constraints of the flow condition
242  /// identified by `Token` are always true.
244 
245  /// Returns true if `Val1` is equivalent to `Val2`.
246  /// Note: This function doesn't take into account constraints on `Val1` and
247  /// `Val2` imposed by the flow condition.
248  bool equivalentBoolValues(BoolValue &Val1, BoolValue &Val2);
249 
250  LLVM_DUMP_METHOD void dumpFlowCondition(AtomicBoolValue &Token);
251 
252  /// Returns the `ControlFlowContext` registered for `F`, if any. Otherwise,
253  /// returns null.
255 
256 private:
257  struct NullableQualTypeDenseMapInfo : private llvm::DenseMapInfo<QualType> {
258  static QualType getEmptyKey() {
259  // Allow a NULL `QualType` by using a different value as the empty key.
260  return QualType::getFromOpaquePtr(reinterpret_cast<Type *>(1));
261  }
262 
263  using DenseMapInfo::getHashValue;
264  using DenseMapInfo::getTombstoneKey;
265  using DenseMapInfo::isEqual;
266  };
267 
268  /// Adds all constraints of the flow condition identified by `Token` and all
269  /// of its transitive dependencies to `Constraints`. `VisitedTokens` is used
270  /// to track tokens of flow conditions that were already visited by recursive
271  /// calls.
272  void addTransitiveFlowConditionConstraints(
273  AtomicBoolValue &Token, llvm::DenseSet<BoolValue *> &Constraints,
274  llvm::DenseSet<AtomicBoolValue *> &VisitedTokens);
275 
276  /// Returns the outcome of satisfiability checking on `Constraints`.
277  /// Possible outcomes are:
278  /// - `Satisfiable`: A satisfying assignment exists and is returned.
279  /// - `Unsatisfiable`: A satisfying assignment does not exist.
280  /// - `TimedOut`: The search for a satisfying assignment was not completed.
281  Solver::Result querySolver(llvm::DenseSet<BoolValue *> Constraints);
282 
283  /// Returns true if the solver is able to prove that there is no satisfying
284  /// assignment for `Constraints`
285  bool isUnsatisfiable(llvm::DenseSet<BoolValue *> Constraints) {
286  return querySolver(std::move(Constraints)).getStatus() ==
288  }
289 
290  /// Returns a boolean value as a result of substituting `Val` and its sub
291  /// values based on entries in `SubstitutionsCache`. Intermediate results are
292  /// stored in `SubstitutionsCache` to avoid reprocessing values that have
293  /// already been visited.
294  BoolValue &substituteBoolValue(
295  BoolValue &Val,
296  llvm::DenseMap<BoolValue *, BoolValue *> &SubstitutionsCache);
297 
298  /// Builds and returns the logical formula defining the flow condition
299  /// identified by `Token`, sub values may be substituted based on entries in
300  /// `SubstitutionsCache`. Intermediate results are stored in
301  /// `SubstitutionsCache` to avoid reprocessing values that have already been
302  /// visited.
303  BoolValue &buildAndSubstituteFlowConditionWithCache(
304  AtomicBoolValue &Token,
305  llvm::DenseMap<BoolValue *, BoolValue *> &SubstitutionsCache);
306 
307  std::unique_ptr<Solver> S;
308 
309  // Storage for the state of a program.
310  std::vector<std::unique_ptr<StorageLocation>> Locs;
311  std::vector<std::unique_ptr<Value>> Vals;
312 
313  // Maps from program declarations and statements to storage locations that are
314  // assigned to them. These assignments are global (aggregated across all basic
315  // blocks) and are used to produce stable storage locations when the same
316  // basic blocks are evaluated multiple times. The storage locations that are
317  // in scope for a particular basic block are stored in `Environment`.
318  llvm::DenseMap<const ValueDecl *, StorageLocation *> DeclToLoc;
319  llvm::DenseMap<const Expr *, StorageLocation *> ExprToLoc;
320 
321  // Null pointer values, keyed by the canonical pointee type.
322  //
323  // FIXME: The pointer values are indexed by the pointee types which are
324  // required to initialize the `PointeeLoc` field in `PointerValue`. Consider
325  // creating a type-independent `NullPointerValue` without a `PointeeLoc`
326  // field.
327  llvm::DenseMap<QualType, PointerValue *, NullableQualTypeDenseMapInfo>
328  NullPointerVals;
329 
330  AtomicBoolValue &TrueVal;
331  AtomicBoolValue &FalseVal;
332 
333  // Indices that are used to avoid recreating the same composite boolean
334  // values.
335  llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, ConjunctionValue *>
336  ConjunctionVals;
337  llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, DisjunctionValue *>
338  DisjunctionVals;
339  llvm::DenseMap<BoolValue *, NegationValue *> NegationVals;
340  llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, ImplicationValue *>
341  ImplicationVals;
342  llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, BiconditionalValue *>
343  BiconditionalVals;
344 
345  // Flow conditions are tracked symbolically: each unique flow condition is
346  // associated with a fresh symbolic variable (token), bound to the clause that
347  // defines the flow condition. Conceptually, each binding corresponds to an
348  // "iff" of the form `FC <=> (C1 ^ C2 ^ ...)` where `FC` is a flow condition
349  // token (an atomic boolean) and `Ci`s are the set of constraints in the flow
350  // flow condition clause. The set of constraints (C1 ^ C2 ^ ...) are stored in
351  // the `FlowConditionConstraints` map, keyed by the token of the flow
352  // condition.
353  //
354  // Flow conditions depend on other flow conditions if they are created using
355  // `forkFlowCondition` or `joinFlowConditions`. The graph of flow condition
356  // dependencies is stored in the `FlowConditionDeps` map.
357  llvm::DenseMap<AtomicBoolValue *, llvm::DenseSet<AtomicBoolValue *>>
358  FlowConditionDeps;
359  llvm::DenseMap<AtomicBoolValue *, BoolValue *> FlowConditionConstraints;
360 
361  llvm::DenseMap<const FunctionDecl *, ControlFlowContext> FunctionContexts;
362 };
363 
364 } // namespace dataflow
365 } // namespace clang
366 
367 #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSISCONTEXT_H
clang::dataflow::DataflowAnalysisContext::createStorageLocation
StorageLocation & createStorageLocation(QualType Type)
Returns a new storage location appropriate for Type.
Definition: DataflowAnalysisContext.cpp:27
clang::dataflow::DataflowAnalysisContext::takeOwnership
std::enable_if_t< std::is_base_of< StorageLocation, T >::value, T & > takeOwnership(std::unique_ptr< T > Loc)
Takes ownership of Loc and returns a reference to it.
Definition: DataflowAnalysisContext.h:75
clang::dataflow::DataflowAnalysisContext::getStableStorageLocation
StorageLocation & getStableStorageLocation(const VarDecl &D)
Returns a stable storage location for D.
Definition: DataflowAnalysisContext.cpp:42
clang::dataflow::DataflowAnalysisContext::makeFlowConditionToken
AtomicBoolValue & makeFlowConditionToken()
Creates a fresh flow condition and returns a token that identifies it.
Definition: DataflowAnalysisContext.cpp:138
clang::dataflow::Solver::Result::Status::Unsatisfiable
@ Unsatisfiable
Indicates that there is no satisfying assignment for a boolean formula.
clang::dataflow::Solver::Result::getStatus
Status getStatus() const
Returns the status of satisfiability checking on the queried boolean formula.
Definition: Solver.h:63
clang::dataflow::DataflowAnalysisContext::setStorageLocation
void setStorageLocation(const ValueDecl &D, StorageLocation &Loc)
Assigns Loc as the storage location of D.
Definition: DataflowAnalysisContext.h:110
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:737
clang::dataflow::StorageLocation
Base class for elements of the local variable store and of the heap.
Definition: StorageLocation.h:28
clang::dataflow::getObjectFields
llvm::DenseSet< const FieldDecl * > getObjectFields(QualType Type)
Returns the set of all fields in the type.
Definition: DataflowAnalysisContext.cpp:398
clang::dataflow::DataflowAnalysisContext::flowConditionImplies
bool flowConditionImplies(AtomicBoolValue &Token, BoolValue &Val)
Returns true if and only if the constraints of the flow condition identified by Token imply that Val ...
Definition: DataflowAnalysisContext.cpp:176
clang::Token
Token - This structure provides full information about a lexed token.
Definition: Token.h:34
clang::Type
The base class of the type hierarchy.
Definition: Type.h:1565
clang::dataflow::DataflowAnalysisContext::flowConditionIsTautology
bool flowConditionIsTautology(AtomicBoolValue &Token)
Returns true if and only if the constraints of the flow condition identified by Token are always true...
Definition: DataflowAnalysisContext.cpp:189
Decl.h
clang::dataflow::DataflowAnalysisContext::getOrCreateConjunction
BoolValue & getOrCreateConjunction(BoolValue &LHS, BoolValue &RHS)
Returns a boolean value that represents the conjunction of LHS and RHS.
Definition: DataflowAnalysisContext.cpp:80
clang::dataflow::DataflowAnalysisContext
Owns objects that encompass the state of a program and stores context that is used during dataflow an...
Definition: DataflowAnalysisContext.h:55
clang::dataflow::DataflowAnalysisContext::dumpFlowCondition
LLVM_DUMP_METHOD void dumpFlowCondition(AtomicBoolValue &Token)
Definition: DataflowAnalysisContext.cpp:326
clang::dataflow::DataflowAnalysisContext::DataflowAnalysisContext
DataflowAnalysisContext(std::unique_ptr< Solver > S)
Constructs a dataflow analysis context.
Definition: DataflowAnalysisContext.h:62
clang::dataflow::DataflowAnalysisContext::getOrCreateDisjunction
BoolValue & getOrCreateDisjunction(BoolValue &LHS, BoolValue &RHS)
Returns a boolean value that represents the disjunction of LHS and RHS.
Definition: DataflowAnalysisContext.cpp:93
Solver.h
clang::dataflow::ignoreCFGOmittedNodes
const Expr & ignoreCFGOmittedNodes(const Expr &E)
Skip past nodes that the CFG does not emit.
Definition: DataflowAnalysisContext.cpp:363
Expr.h
clang::dataflow::DataflowAnalysisContext::addFlowConditionConstraint
void addFlowConditionConstraint(AtomicBoolValue &Token, BoolValue &Constraint)
Adds Constraint to the flow condition identified by Token.
Definition: DataflowAnalysisContext.cpp:142
clang::VarDecl
Represents a variable declaration or definition.
Definition: Decl.h:906
llvm::DenseSet
Definition: Sema.h:77
clang::dataflow::AtomicBoolValue
Models an atomic boolean.
Definition: Value.h:119
clang::dataflow::DataflowAnalysisContext::joinFlowConditions
AtomicBoolValue & joinFlowConditions(AtomicBoolValue &FirstToken, AtomicBoolValue &SecondToken)
Creates a new flow condition that represents the disjunction of the flow conditions identified by Fir...
Definition: DataflowAnalysisContext.cpp:159
clang::dataflow::BoolValue
Models a boolean.
Definition: Value.h:92
clang::dataflow::DataflowAnalysisContext::getStorageLocation
StorageLocation * getStorageLocation(const Expr &E) const
Returns the storage location assigned to E or null if E has no assigned storage location.
Definition: DataflowAnalysisContext.h:135
clang::dataflow::DataflowAnalysisContext::getOrCreateNullPointerValue
PointerValue & getOrCreateNullPointerValue(QualType PointeeType)
Returns a pointer value that represents a null pointer.
Definition: DataflowAnalysisContext.cpp:60
clang::dataflow::DataflowAnalysisContext::getOrCreateImplication
BoolValue & getOrCreateImplication(BoolValue &LHS, BoolValue &RHS)
Returns a boolean value that represents LHS => RHS.
Definition: DataflowAnalysisContext.cpp:113
clang::ValueDecl
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:701
TypeOrdering.h
clang::dataflow::DataflowAnalysisContext::buildAndSubstituteFlowCondition
BoolValue & buildAndSubstituteFlowCondition(AtomicBoolValue &Token, llvm::DenseMap< AtomicBoolValue *, BoolValue * > Substitutions)
Builds and returns the logical formula defining the flow condition identified by Token.
Definition: DataflowAnalysisContext.cpp:296
clang::dataflow::DataflowAnalysisContext::getControlFlowContext
const ControlFlowContext * getControlFlowContext(const FunctionDecl *F)
Returns the ControlFlowContext registered for F, if any.
Definition: DataflowAnalysisContext.cpp:338
clang::dataflow::ControlFlowContext
Holds CFG and other derived context that is needed to perform dataflow analysis.
Definition: ControlFlowContext.h:31
clang::dataflow::DataflowAnalysisContext::forkFlowCondition
AtomicBoolValue & forkFlowCondition(AtomicBoolValue &Token)
Creates a new flow condition with the same constraints as the flow condition identified by Token and ...
Definition: DataflowAnalysisContext.cpp:151
clang::dataflow::DataflowAnalysisContext::getBoolLiteralValue
AtomicBoolValue & getBoolLiteralValue(bool Value) const
Returns a symbolic boolean value that models a boolean literal equal to Value.
Definition: DataflowAnalysisContext.h:147
clang::QualType::getFromOpaquePtr
static QualType getFromOpaquePtr(const void *Ptr)
Definition: Type.h:784
std
Definition: Format.h:4477
clang::dataflow::DataflowAnalysisContext::createTopBoolValue
TopBoolValue & createTopBoolValue()
Creates a Top value for booleans.
Definition: DataflowAnalysisContext.h:164
ControlFlowContext.h
clang::dataflow::DataflowAnalysisContext::setStorageLocation
void setStorageLocation(const Expr &E, StorageLocation &Loc)
Assigns Loc as the storage location of E.
Definition: DataflowAnalysisContext.h:127
clang::dataflow::DataflowAnalysisContext::getStorageLocation
StorageLocation * getStorageLocation(const ValueDecl &D) const
Returns the storage location assigned to D or null if D has no assigned storage location.
Definition: DataflowAnalysisContext.h:117
clang
Definition: CalledOnceCheck.h:17
clang::dataflow::TopBoolValue
Models the trivially true formula, which is Top in the lattice of boolean formulas.
Definition: Value.h:109
clang::dataflow::Value
Base class for all values computed by abstract interpretation.
Definition: Value.h:32
StorageLocation.h
clang::dataflow::DataflowAnalysisContext::getOrCreateIff
BoolValue & getOrCreateIff(BoolValue &LHS, BoolValue &RHS)
Returns a boolean value that represents LHS <=> RHS.
Definition: DataflowAnalysisContext.cpp:125
clang::dataflow::PointerValue
Models a symbolic pointer. Specifically, any value of type T*.
Definition: Value.h:268
clang::Expr
This represents one expression.
Definition: Expr.h:109
clang::dataflow::DataflowAnalysisContext::equivalentBoolValues
bool equivalentBoolValues(BoolValue &Val1, BoolValue &Val2)
Returns true if Val1 is equivalent to Val2.
Definition: DataflowAnalysisContext.cpp:198
clang::FunctionDecl
Represents a function declaration or definition.
Definition: Decl.h:1904
clang::dataflow::DataflowAnalysisContext::takeOwnership
std::enable_if_t< std::is_base_of< Value, T >::value, T & > takeOwnership(std::unique_ptr< T > Val)
Takes ownership of Val and returns a reference to it.
Definition: DataflowAnalysisContext.h:88
Value.h
clang::dataflow::DataflowAnalysisContext::getOrCreateNegation
BoolValue & getOrCreateNegation(BoolValue &Val)
Returns a boolean value that represents the negation of Val.
Definition: DataflowAnalysisContext.cpp:106
clang::dataflow::DataflowAnalysisContext::createAtomicBoolValue
AtomicBoolValue & createAtomicBoolValue()
Creates an atomic boolean value.
Definition: DataflowAnalysisContext.h:152