clang  16.0.0git
DataflowAnalysisContext.cpp
Go to the documentation of this file.
1 //===-- DataflowAnalysisContext.cpp -----------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines 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 
16 #include "clang/AST/ExprCXX.h"
19 #include "llvm/Support/Debug.h"
20 #include <cassert>
21 #include <memory>
22 #include <utility>
23 
24 namespace clang {
25 namespace dataflow {
26 
28  if (!Type.isNull() &&
30  // FIXME: Explore options to avoid eager initialization of fields as some of
31  // them might not be needed for a particular analysis.
32  llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
33  for (const FieldDecl *Field : getObjectFields(Type))
34  FieldLocs.insert({Field, &createStorageLocation(Field->getType())});
35  return takeOwnership(
36  std::make_unique<AggregateStorageLocation>(Type, std::move(FieldLocs)));
37  }
38  return takeOwnership(std::make_unique<ScalarStorageLocation>(Type));
39 }
40 
43  if (auto *Loc = getStorageLocation(D))
44  return *Loc;
45  auto &Loc = createStorageLocation(D.getType());
46  setStorageLocation(D, Loc);
47  return Loc;
48 }
49 
52  if (auto *Loc = getStorageLocation(E))
53  return *Loc;
54  auto &Loc = createStorageLocation(E.getType());
55  setStorageLocation(E, Loc);
56  return Loc;
57 }
58 
61  auto CanonicalPointeeType =
62  PointeeType.isNull() ? PointeeType : PointeeType.getCanonicalType();
63  auto Res = NullPointerVals.try_emplace(CanonicalPointeeType, nullptr);
64  if (Res.second) {
65  auto &PointeeLoc = createStorageLocation(CanonicalPointeeType);
66  Res.first->second =
67  &takeOwnership(std::make_unique<PointerValue>(PointeeLoc));
68  }
69  return *Res.first->second;
70 }
71 
72 static std::pair<BoolValue *, BoolValue *>
74  auto Res = std::make_pair(&LHS, &RHS);
75  if (&RHS < &LHS)
76  std::swap(Res.first, Res.second);
77  return Res;
78 }
79 
81  BoolValue &RHS) {
82  if (&LHS == &RHS)
83  return LHS;
84 
85  auto Res = ConjunctionVals.try_emplace(makeCanonicalBoolValuePair(LHS, RHS),
86  nullptr);
87  if (Res.second)
88  Res.first->second =
89  &takeOwnership(std::make_unique<ConjunctionValue>(LHS, RHS));
90  return *Res.first->second;
91 }
92 
94  BoolValue &RHS) {
95  if (&LHS == &RHS)
96  return LHS;
97 
98  auto Res = DisjunctionVals.try_emplace(makeCanonicalBoolValuePair(LHS, RHS),
99  nullptr);
100  if (Res.second)
101  Res.first->second =
102  &takeOwnership(std::make_unique<DisjunctionValue>(LHS, RHS));
103  return *Res.first->second;
104 }
105 
107  auto Res = NegationVals.try_emplace(&Val, nullptr);
108  if (Res.second)
109  Res.first->second = &takeOwnership(std::make_unique<NegationValue>(Val));
110  return *Res.first->second;
111 }
112 
114  BoolValue &RHS) {
115  if (&LHS == &RHS)
116  return getBoolLiteralValue(true);
117 
118  auto Res = ImplicationVals.try_emplace(std::make_pair(&LHS, &RHS), nullptr);
119  if (Res.second)
120  Res.first->second =
121  &takeOwnership(std::make_unique<ImplicationValue>(LHS, RHS));
122  return *Res.first->second;
123 }
124 
126  BoolValue &RHS) {
127  if (&LHS == &RHS)
128  return getBoolLiteralValue(true);
129 
130  auto Res = BiconditionalVals.try_emplace(makeCanonicalBoolValuePair(LHS, RHS),
131  nullptr);
132  if (Res.second)
133  Res.first->second =
134  &takeOwnership(std::make_unique<BiconditionalValue>(LHS, RHS));
135  return *Res.first->second;
136 }
137 
139  return createAtomicBoolValue();
140 }
141 
143  AtomicBoolValue &Token, BoolValue &Constraint) {
144  auto Res = FlowConditionConstraints.try_emplace(&Token, &Constraint);
145  if (!Res.second) {
146  Res.first->second = &getOrCreateConjunction(*Res.first->second, Constraint);
147  }
148 }
149 
152  auto &ForkToken = makeFlowConditionToken();
153  FlowConditionDeps[&ForkToken].insert(&Token);
154  addFlowConditionConstraint(ForkToken, Token);
155  return ForkToken;
156 }
157 
160  AtomicBoolValue &SecondToken) {
161  auto &Token = makeFlowConditionToken();
162  FlowConditionDeps[&Token].insert(&FirstToken);
163  FlowConditionDeps[&Token].insert(&SecondToken);
165  getOrCreateDisjunction(FirstToken, SecondToken));
166  return Token;
167 }
168 
170 DataflowAnalysisContext::querySolver(llvm::DenseSet<BoolValue *> Constraints) {
171  Constraints.insert(&getBoolLiteralValue(true));
172  Constraints.insert(&getOrCreateNegation(getBoolLiteralValue(false)));
173  return S->solve(std::move(Constraints));
174 }
175 
177  BoolValue &Val) {
178  // Returns true if and only if truth assignment of the flow condition implies
179  // that `Val` is also true. We prove whether or not this property holds by
180  // reducing the problem to satisfiability checking. In other words, we attempt
181  // to show that assuming `Val` is false makes the constraints induced by the
182  // flow condition unsatisfiable.
183  llvm::DenseSet<BoolValue *> Constraints = {&Token, &getOrCreateNegation(Val)};
184  llvm::DenseSet<AtomicBoolValue *> VisitedTokens;
185  addTransitiveFlowConditionConstraints(Token, Constraints, VisitedTokens);
186  return isUnsatisfiable(std::move(Constraints));
187 }
188 
190  // Returns true if and only if we cannot prove that the flow condition can
191  // ever be false.
193  llvm::DenseSet<AtomicBoolValue *> VisitedTokens;
194  addTransitiveFlowConditionConstraints(Token, Constraints, VisitedTokens);
195  return isUnsatisfiable(std::move(Constraints));
196 }
197 
199  BoolValue &Val2) {
200  llvm::DenseSet<BoolValue *> Constraints = {
201  &getOrCreateNegation(getOrCreateIff(Val1, Val2))};
202  return isUnsatisfiable(Constraints);
203 }
204 
205 void DataflowAnalysisContext::addTransitiveFlowConditionConstraints(
207  llvm::DenseSet<AtomicBoolValue *> &VisitedTokens) {
208  auto Res = VisitedTokens.insert(&Token);
209  if (!Res.second)
210  return;
211 
212  auto ConstraintsIt = FlowConditionConstraints.find(&Token);
213  if (ConstraintsIt == FlowConditionConstraints.end()) {
214  Constraints.insert(&Token);
215  } else {
216  // Bind flow condition token via `iff` to its set of constraints:
217  // FC <=> (C1 ^ C2 ^ ...), where Ci are constraints
218  Constraints.insert(&getOrCreateIff(Token, *ConstraintsIt->second));
219  }
220 
221  auto DepsIt = FlowConditionDeps.find(&Token);
222  if (DepsIt != FlowConditionDeps.end()) {
223  for (AtomicBoolValue *DepToken : DepsIt->second) {
224  addTransitiveFlowConditionConstraints(*DepToken, Constraints,
225  VisitedTokens);
226  }
227  }
228 }
229 
230 BoolValue &DataflowAnalysisContext::substituteBoolValue(
231  BoolValue &Val,
232  llvm::DenseMap<BoolValue *, BoolValue *> &SubstitutionsCache) {
233  auto It = SubstitutionsCache.find(&Val);
234  if (It != SubstitutionsCache.end()) {
235  // Return memoized result of substituting this boolean value.
236  return *It->second;
237  }
238 
239  // Handle substitution on the boolean value (and its subvalues), saving the
240  // result into `SubstitutionsCache`.
241  BoolValue *Result;
242  switch (Val.getKind()) {
244  Result = &Val;
245  break;
246  }
247  case Value::Kind::Negation: {
248  auto &Negation = *cast<NegationValue>(&Val);
249  auto &Sub = substituteBoolValue(Negation.getSubVal(), SubstitutionsCache);
250  Result = &getOrCreateNegation(Sub);
251  break;
252  }
254  auto &Disjunct = *cast<DisjunctionValue>(&Val);
255  auto &LeftSub =
256  substituteBoolValue(Disjunct.getLeftSubValue(), SubstitutionsCache);
257  auto &RightSub =
258  substituteBoolValue(Disjunct.getRightSubValue(), SubstitutionsCache);
259  Result = &getOrCreateDisjunction(LeftSub, RightSub);
260  break;
261  }
263  auto &Conjunct = *cast<ConjunctionValue>(&Val);
264  auto &LeftSub =
265  substituteBoolValue(Conjunct.getLeftSubValue(), SubstitutionsCache);
266  auto &RightSub =
267  substituteBoolValue(Conjunct.getRightSubValue(), SubstitutionsCache);
268  Result = &getOrCreateConjunction(LeftSub, RightSub);
269  break;
270  }
272  auto &IV = *cast<ImplicationValue>(&Val);
273  auto &LeftSub =
274  substituteBoolValue(IV.getLeftSubValue(), SubstitutionsCache);
275  auto &RightSub =
276  substituteBoolValue(IV.getRightSubValue(), SubstitutionsCache);
277  Result = &getOrCreateImplication(LeftSub, RightSub);
278  break;
279  }
281  auto &BV = *cast<BiconditionalValue>(&Val);
282  auto &LeftSub =
283  substituteBoolValue(BV.getLeftSubValue(), SubstitutionsCache);
284  auto &RightSub =
285  substituteBoolValue(BV.getRightSubValue(), SubstitutionsCache);
286  Result = &getOrCreateIff(LeftSub, RightSub);
287  break;
288  }
289  default:
290  llvm_unreachable("Unhandled Value Kind");
291  }
292  SubstitutionsCache[&Val] = Result;
293  return *Result;
294 }
295 
298  llvm::DenseMap<AtomicBoolValue *, BoolValue *> Substitutions) {
299  assert(
300  Substitutions.find(&getBoolLiteralValue(true)) == Substitutions.end() &&
301  Substitutions.find(&getBoolLiteralValue(false)) == Substitutions.end() &&
302  "Do not substitute true/false boolean literals");
303  llvm::DenseMap<BoolValue *, BoolValue *> SubstitutionsCache(
304  Substitutions.begin(), Substitutions.end());
305  return buildAndSubstituteFlowConditionWithCache(Token, SubstitutionsCache);
306 }
307 
308 BoolValue &DataflowAnalysisContext::buildAndSubstituteFlowConditionWithCache(
310  llvm::DenseMap<BoolValue *, BoolValue *> &SubstitutionsCache) {
311  auto ConstraintsIt = FlowConditionConstraints.find(&Token);
312  if (ConstraintsIt == FlowConditionConstraints.end()) {
313  return getBoolLiteralValue(true);
314  }
315  auto DepsIt = FlowConditionDeps.find(&Token);
316  if (DepsIt != FlowConditionDeps.end()) {
317  for (AtomicBoolValue *DepToken : DepsIt->second) {
318  auto &NewDep = buildAndSubstituteFlowConditionWithCache(
319  *DepToken, SubstitutionsCache);
320  SubstitutionsCache[DepToken] = &NewDep;
321  }
322  }
323  return substituteBoolValue(*ConstraintsIt->second, SubstitutionsCache);
324 }
325 
327  llvm::DenseSet<BoolValue *> Constraints = {&Token};
328  llvm::DenseSet<AtomicBoolValue *> VisitedTokens;
329  addTransitiveFlowConditionConstraints(Token, Constraints, VisitedTokens);
330 
331  llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {
332  {&getBoolLiteralValue(false), "False"},
333  {&getBoolLiteralValue(true), "True"}};
334  llvm::dbgs() << debugString(Constraints, AtomNames);
335 }
336 
337 const ControlFlowContext *
339  // Canonicalize the key:
340  F = F->getDefinition();
341  if (F == nullptr)
342  return nullptr;
343  auto It = FunctionContexts.find(F);
344  if (It != FunctionContexts.end())
345  return &It->second;
346 
347  if (Stmt *Body = F->getBody()) {
348  auto CFCtx = ControlFlowContext::build(F, *Body, F->getASTContext());
349  // FIXME: Handle errors.
350  assert(CFCtx);
351  auto Result = FunctionContexts.insert({F, std::move(*CFCtx)});
352  return &Result.first->second;
353  }
354 
355  return nullptr;
356 }
357 
358 } // namespace dataflow
359 } // namespace clang
360 
361 using namespace clang;
362 
364  const Expr *Current = &E;
365  if (auto *EWC = dyn_cast<ExprWithCleanups>(Current)) {
366  Current = EWC->getSubExpr();
367  assert(Current != nullptr);
368  }
369  Current = Current->IgnoreParens();
370  assert(Current != nullptr);
371  return *Current;
372 }
373 
375  if (auto *E = dyn_cast<Expr>(&S))
376  return ignoreCFGOmittedNodes(*E);
377  return S;
378 }
379 
380 // FIXME: Does not precisely handle non-virtual diamond inheritance. A single
381 // field decl will be modeled for all instances of the inherited field.
382 static void
385  if (Type->isIncompleteType() || Type->isDependentType() ||
386  !Type->isRecordType())
387  return;
388 
389  for (const FieldDecl *Field : Type->getAsRecordDecl()->fields())
390  Fields.insert(Field);
391  if (auto *CXXRecord = Type->getAsCXXRecordDecl())
392  for (const CXXBaseSpecifier &Base : CXXRecord->bases())
393  getFieldsFromClassHierarchy(Base.getType(), Fields);
394 }
395 
396 /// Gets the set of all fields in the type.
401  return Fields;
402 }
clang::dataflow::DataflowAnalysisContext::createStorageLocation
StorageLocation & createStorageLocation(QualType Type)
Returns a new storage location appropriate for Type.
Definition: DataflowAnalysisContext.cpp:27
clang::Type::isRecordType
bool isRecordType() const
Definition: Type.h:6930
clang::Decl::getASTContext
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:415
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
getFieldsFromClassHierarchy
static void getFieldsFromClassHierarchy(QualType Type, llvm::DenseSet< const FieldDecl * > &Fields)
Definition: DataflowAnalysisContext.cpp:383
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:731
clang::dataflow::StorageLocation
Base class for elements of the local variable store and of the heap.
Definition: StorageLocation.h:28
clang::QualType::getCanonicalType
QualType getCanonicalType() const
Definition: Type.h:6631
clang::FieldDecl
Represents a member of a struct/union/class.
Definition: Decl.h:2878
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::dataflow::Value::Kind::Disjunction
@ Disjunction
clang::Type
The base class of the type hierarchy.
Definition: Type.h:1559
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
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::FunctionDecl::getDefinition
FunctionDecl * getDefinition()
Get the definition for this declaration.
Definition: Decl.h:2144
DebugSupport.h
clang::dataflow::DataflowAnalysisContext::dumpFlowCondition
LLVM_DUMP_METHOD void dumpFlowCondition(AtomicBoolValue &Token)
Definition: DataflowAnalysisContext.cpp:326
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
clang::FunctionDecl::getBody
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
Definition: Decl.cpp:3097
clang::dataflow::ControlFlowContext::build
static llvm::Expected< ControlFlowContext > build(const Decl *D, Stmt &S, ASTContext &C)
Builds a ControlFlowContext from an AST node.
Definition: ControlFlowContext.cpp:48
clang::dataflow::ignoreCFGOmittedNodes
const Expr & ignoreCFGOmittedNodes(const Expr &E)
Skip past nodes that the CFG does not emit.
Definition: DataflowAnalysisContext.cpp:363
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:879
llvm::DenseSet
Definition: Sema.h:77
clang::Type::getAsCXXRecordDecl
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1759
ExprCXX.h
Base
clang::dataflow::AtomicBoolValue
Models an atomic boolean.
Definition: Value.h:95
clang::dataflow::Value::Kind::Conjunction
@ Conjunction
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::Value::Kind::Negation
@ Negation
clang::dataflow::BoolValue
Models a boolean.
Definition: Value.h:80
clang::dataflow::makeCanonicalBoolValuePair
static std::pair< BoolValue *, BoolValue * > makeCanonicalBoolValuePair(BoolValue &LHS, BoolValue &RHS)
Definition: DataflowAnalysisContext.cpp:73
clang::Type::isUnionType
bool isUnionType() const
Definition: Type.cpp:595
clang::Type::isDependentType
bool isDependentType() const
Whether this type is a dependent type, meaning that its definition somehow depends on a template para...
Definition: Type.h:2261
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::RecordDecl::fields
field_range fields() const
Definition: Decl.h:4155
clang::QualType::isNull
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:796
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::Type::getAsRecordDecl
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition: Type.cpp:1763
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::dataflow::debugString
llvm::StringRef debugString(Value::Kind Kind)
Returns a string representation of a value kind.
Definition: DebugSupport.cpp:35
clang::Type::isStructureOrClassType
bool isStructureOrClassType() const
Definition: Type.cpp:581
DataflowAnalysisContext.h
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::Value::Kind::AtomicBool
@ AtomicBool
clang::Stmt
Stmt - This represents one statement.
Definition: Stmt.h:70
clang::Expr::getType
QualType getType() const
Definition: Expr.h:141
clang::CXXBaseSpecifier
Represents a base class of a C++ class.
Definition: DeclCXX.h:146
clang::dataflow::Solver::Result
Definition: Solver.h:28
clang::dataflow::Value::Kind::Implication
@ Implication
clang::dataflow::DataflowAnalysisContext::getOrCreateIff
BoolValue & getOrCreateIff(BoolValue &LHS, BoolValue &RHS)
Returns a boolean value that represents LHS <=> RHS.
Definition: DataflowAnalysisContext.cpp:125
clang::dataflow::DataflowAnalysisContext::takeOwnership
std::enable_if< std::is_base_of< StorageLocation, T >::value, T & >::type takeOwnership(std::unique_ptr< T > Loc)
Takes ownership of Loc and returns a reference to it.
Definition: DataflowAnalysisContext.h:75
clang::dataflow::PointerValue
Models a symbolic pointer. Specifically, any value of type T*.
Definition: Value.h:244
clang::ValueDecl::getType
QualType getType() const
Definition: Decl.h:685
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::Type::isIncompleteType
bool isIncompleteType(NamedDecl **Def=nullptr) const
Types are partitioned into 3 broad categories (C99 6.2.5p1): object types, function types,...
Definition: Type.cpp:2234
clang::FunctionDecl
Represents a function declaration or definition.
Definition: Decl.h:1877
Value.h
clang::dataflow::Value::Kind::Biconditional
@ Biconditional
clang::interp::Sub
bool Sub(InterpState &S, CodePtr OpPC)
Definition: Interp.h:142
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