clang: include/clang/Analysis/FlowSensitive/DataflowAnalysis.h Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSIS_H
15#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSIS_H
16
17#include
18#include
19#include <type_traits>
20#include
21#include
22
31#include "llvm/ADT/STLExtras.h"
32#include "llvm/ADT/STLFunctionalExtras.h"
33#include "llvm/ADT/SmallVector.h"
34#include "llvm/Support/Errc.h"
35#include "llvm/Support/Error.h"
36
38namespace dataflow {
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79template <typename Derived, typename LatticeT>
81public:
82
84
86
90
92
94 return {static_cast<Derived *>(this)->initialElement()};
95 }
96
99
100 Lattice L1 = llvm::any_cast<const Lattice &>(E1.Value);
101 const Lattice &L2 = llvm::any_cast<const Lattice &>(E2.Value);
102 L1.join(L2);
103 return {std::move(L1)};
104 }
105
108 Lattice &C = llvm::any_cast<Lattice &>(Current.Value);
109 const Lattice &P = llvm::any_cast<const Lattice &>(Previous.Value);
110 return widenInternal(Rank0{}, C, P);
111 }
112
115 const Lattice &L1 = llvm::any_cast<const Lattice &>(E1.Value);
116 const Lattice &L2 = llvm::any_cast<const Lattice &>(E2.Value);
117 return L1 == L2;
118 }
119
122 Lattice &L = llvm::any_cast<Lattice &>(E.Value);
123 static_cast<Derived *>(this)->transfer(Element, L, Env);
124 }
125
128 transferBranchInternal(Rank0{}, *static_cast<Derived *>(this), Branch, Stmt,
130 }
131
132private:
133
134
135 struct Rank1 {};
136 struct Rank0 : Rank1 {};
137
138
139 template
140 static auto widenInternal(Rank0, T &Current, const T &Prev)
141 -> decltype(Current.widen(Prev)) {
142 return Current.widen(Prev);
143 }
144
145
146
147
152 }
153
154
155 template
156 static auto transferBranchInternal(Rank0, Analysis &A, bool Branch,
157 const Stmt *Stmt, TypeErasedLattice &L,
158 Environment &Env)
159 -> std::void_t<decltype(A.transferBranch(
160 Branch, Stmt, std::declval<LatticeT &>(), Env))> {
161 A.transferBranch(Branch, Stmt, llvm::any_cast<Lattice &>(L.Value), Env);
162 }
163
164
165 template
166 static void transferBranchInternal(Rank1, Analysis &A, bool, const Stmt *,
167 TypeErasedLattice &, Environment &) {}
168
169 ASTContext &Context;
170};
171
172
174
176
177
179};
180
181
182
183template
187
188
189
190
194};
195
196
197
198
199template <typename AnalysisT, typename Diagnostic>
203
204
205
206
210};
211
212
214
215
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231template
233 std::optional<DataflowAnalysisState>>>
238 CFGEltCallbacksTypeErased TypeErasedCallbacks;
239 if (PostAnalysisCallbacks.Before) {
240 TypeErasedCallbacks.Before =
241 [&PostAnalysisCallbacks](const CFGElement &Element,
242 const TypeErasedDataflowAnalysisState &State) {
243 auto *Lattice =
244 llvm::any_cast(&State.Lattice.Value);
245
246
247 PostAnalysisCallbacks.Before(
248 Element, DataflowAnalysisState{
249 *Lattice, State.Env.fork()});
250 };
251 }
252 if (PostAnalysisCallbacks.After) {
253 TypeErasedCallbacks.After =
254 [&PostAnalysisCallbacks](const CFGElement &Element,
255 const TypeErasedDataflowAnalysisState &State) {
256 auto *Lattice =
257 llvm::any_cast(&State.Lattice.Value);
258
259
260 PostAnalysisCallbacks.After(
261 Element, DataflowAnalysisState{
262 *Lattice, State.Env.fork()});
263 };
264 }
265
267 ACFG, Analysis, InitEnv, TypeErasedCallbacks, MaxBlockVisits);
268 if (!TypeErasedBlockStates)
269 return TypeErasedBlockStates.takeError();
270
271 std::vector<std::optional<DataflowAnalysisState>>
273 BlockStates.reserve(TypeErasedBlockStates->size());
274
275 llvm::transform(
276 std::move(*TypeErasedBlockStates), std::back_inserter(BlockStates),
277 [](auto &OptState) {
278 return llvm::transformOptional(
279 std::move(OptState), [](TypeErasedDataflowAnalysisState &&State) {
280 return DataflowAnalysisState{
281 llvm::any_cast(
282 std::move(State.Lattice.Value)),
283 std::move(State.Env)};
284 });
285 });
287}
288
289
290
291
292
293
294template
296 -> decltype(AnalysisT(ASTCtx, Env)) {
297 return AnalysisT(ASTCtx, Env);
298}
299template
301 -> decltype(AnalysisT(ASTCtx)) {
302 return AnalysisT(ASTCtx);
303}
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320template <typename AnalysisT, typename Diagnostic>
327 if (!Context)
328 return Context.takeError();
329
330 auto Solver = std::make_unique(MaxSATIterations);
333 AnalysisT Analysis = createAnalysis(ASTCtx, Env);
336 if (Diagnoser.Before) {
337 PostAnalysisCallbacks.Before =
338 [&ASTCtx, &Diagnoser,
341 auto EltDiagnostics = Diagnoser.Before(
342 Elt, ASTCtx,
344 llvm::any_cast<const typename AnalysisT::Lattice &>(
345 State.Lattice.Value),
346 State.Env));
347 llvm::move(EltDiagnostics, std::back_inserter(Diagnostics));
348 };
349 }
350 if (Diagnoser.After) {
351 PostAnalysisCallbacks.After =
352 [&ASTCtx, &Diagnoser,
355 auto EltDiagnostics = Diagnoser.After(
356 Elt, ASTCtx,
358 llvm::any_cast<const typename AnalysisT::Lattice &>(
359 State.Lattice.Value),
360 State.Env));
361 llvm::move(EltDiagnostics, std::back_inserter(Diagnostics));
362 };
363 }
364 if (llvm::Error Err =
366 PostAnalysisCallbacks, MaxBlockVisits)
367 .takeError())
368 return std::move(Err);
369
371 return llvm::createStringError(llvm::errc::interrupted,
372 "SAT solver timed out");
373
374 return Diagnostics;
375}
376
377
378
379
380
381template <typename AnalysisT, typename Diagnostic>
388 return diagnoseFunction(FuncDecl, ASTCtx, Callbacks, MaxSATIterations,
389 MaxBlockVisits);
390}
391
392
393
394
396public:
397
399};
400
401}
402}
403
404#endif
Defines the clang::ASTContext interface.
llvm::ArrayRef< std::optional< TypeErasedDataflowAnalysisState > > BlockStates
Stores the state of a CFG block if it has been evaluated by the analysis.
const Environment & InitEnv
Initial state to start the analysis.
TypeErasedDataflowAnalysis & Analysis
The analysis to be run.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Represents a top-level expression in a basic block.
Represents a function declaration or definition.
Stmt - This represents one statement.
Holds CFG with additional information derived from it that is needed to perform dataflow analysis.
static llvm::Expected< AdornedCFG > build(const FunctionDecl &Func)
Builds an AdornedCFG from a FunctionDecl.
Owns objects that encompass the state of a program and stores context that is used during dataflow an...
Base class template for dataflow analyses built on a single lattice type.
LatticeJoinEffect widenTypeErased(TypeErasedLattice &Current, const TypeErasedLattice &Previous) final
Chooses a lattice element that approximates the current element at a program point,...
ASTContext & getASTContext() final
Returns the ASTContext that is used by the analysis.
DataflowAnalysis(ASTContext &Context, DataflowAnalysisOptions Options)
bool isEqualTypeErased(const TypeErasedLattice &E1, const TypeErasedLattice &E2) final
Returns true if and only if the two given type-erased lattice elements are equal.
DataflowAnalysis(ASTContext &Context)
TypeErasedLattice joinTypeErased(const TypeErasedLattice &E1, const TypeErasedLattice &E2) final
Joins two type-erased lattice elements by computing their least upper bound.
void transferBranchTypeErased(bool Branch, const Stmt *Stmt, TypeErasedLattice &E, Environment &Env) final
Applies the analysis transfer function for a given edge from a CFG block of a conditional statement.
TypeErasedLattice typeErasedInitialElement() final
Returns a type-erased lattice element that models the initial state of a basic block.
LatticeT Lattice
Bounded join-semilattice that is used in the analysis.
void transferTypeErased(const CFGElement &Element, TypeErasedLattice &E, Environment &Env) final
Applies the analysis transfer function for a given control flow graph element and type-erased lattice...
Abstract base class for dataflow "models": reusable analysis components that model a particular aspec...
virtual bool transfer(const CFGElement &Element, Environment &Env)=0
Return value indicates whether the model processed the Element.
Supplements Environment with non-standard comparison and join operations.
Holds the state of the program (store and heap) at a given program point.
An interface for a SAT solver that can be used by dataflow analyses.
virtual bool reachedLimit() const =0
Type-erased base class for dataflow analyses built on a single lattice type.
void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env, Environment::ValueModel &Model)
Evaluates S and updates Env accordingly.
llvm::function_ref< llvm::SmallVector< Diagnostic >(const CFGElement &, ASTContext &, const TransferStateForDiagnostics< typename AnalysisT::Lattice > &)> DiagnosisCallback
A callback for performing diagnosis on a CFG element, called with the state before or after visiting ...
constexpr std::int32_t kDefaultMaxBlockVisits
Default for the maximum number of block visits during analysis.
llvm::Expected< std::vector< std::optional< TypeErasedDataflowAnalysisState > > > runTypeErasedDataflowAnalysis(const AdornedCFG &ACFG, TypeErasedDataflowAnalysis &Analysis, const Environment &InitEnv, const CFGEltCallbacksTypeErased &PostAnalysisCallbacks, std::int32_t MaxBlockVisits)
Performs dataflow analysis and returns a mapping from basic block IDs to dataflow analysis states tha...
llvm::Expected< llvm::SmallVector< Diagnostic > > diagnoseFunction(const FunctionDecl &FuncDecl, ASTContext &ASTCtx, DiagnosisCallbacks< AnalysisT, Diagnostic > Diagnoser, std::int64_t MaxSATIterations=kDefaultMaxSATIterations, std::int32_t MaxBlockVisits=kDefaultMaxBlockVisits)
Runs a dataflow analysis over the given function and then runs Diagnoser over the results.
llvm::Expected< std::vector< std::optional< DataflowAnalysisState< typename AnalysisT::Lattice > > > > runDataflowAnalysis(const AdornedCFG &ACFG, AnalysisT &Analysis, const Environment &InitEnv, CFGEltCallbacks< AnalysisT > PostAnalysisCallbacks={}, std::int32_t MaxBlockVisits=kDefaultMaxBlockVisits)
Performs dataflow analysis and returns a mapping from basic block IDs to dataflow analysis states tha...
std::function< void(const CFGElement &, const DataflowAnalysisState< typename AnalysisT::Lattice > &)> CFGEltCallback
A callback to be called with the state before or after visiting a CFG element.
LatticeEffect LatticeJoinEffect
auto createAnalysis(ASTContext &ASTCtx, Environment &Env) -> decltype(AnalysisT(ASTCtx, Env))
LatticeEffect
Effect indicating whether a lattice operation resulted in a new value.
constexpr std::int64_t kDefaultMaxSATIterations
Default for the maximum number of SAT solver iterations during analysis.
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
A pair of callbacks to be called with the state before and after visiting a CFG element.
CFGEltCallbackTypeErased Before
CFGEltCallbackTypeErased After
A pair of callbacks to be called with the state before and after visiting a CFG element.
CFGEltCallback< AnalysisT > After
CFGEltCallback< AnalysisT > Before
A pair of callbacks for performing diagnosis on a CFG element, called with the state before and after...
DiagnosisCallback< AnalysisT, Diagnostic > Before
DiagnosisCallback< AnalysisT, Diagnostic > After
A read-only version of TransferState.
Type-erased model of the program at a given program point.
Type-erased lattice element container.