#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSIS_H
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSIS_H
#include <iterator>
#include <utility>
#include <vector>
#include "clang/AST/ASTContext.h"
#include "clang/AST/Stmt.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
#include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h"
#include "llvm/ADT/Any.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Error.h"
namespace clang {
namespace dataflow {
template <typename Derived, typename LatticeT>
class DataflowAnalysis : public TypeErasedDataflowAnalysis {
public:
using Lattice = LatticeT;
explicit DataflowAnalysis(ASTContext &Context) : Context(Context) {}
explicit DataflowAnalysis(ASTContext &Context, bool ApplyBuiltinTransfer)
: TypeErasedDataflowAnalysis(ApplyBuiltinTransfer), Context(Context) {}
explicit DataflowAnalysis(ASTContext &Context,
DataflowAnalysisOptions Options)
: TypeErasedDataflowAnalysis(Options), Context(Context) {}
ASTContext &getASTContext() final { return Context; }
TypeErasedLattice typeErasedInitialElement() final {
return {static_cast<Derived *>(this)->initialElement()};
}
LatticeJoinEffect joinTypeErased(TypeErasedLattice &E1,
const TypeErasedLattice &E2) final {
Lattice &L1 = llvm::any_cast<Lattice &>(E1.Value);
const Lattice &L2 = llvm::any_cast<const Lattice &>(E2.Value);
return L1.join(L2);
}
bool isEqualTypeErased(const TypeErasedLattice &E1,
const TypeErasedLattice &E2) final {
const Lattice &L1 = llvm::any_cast<const Lattice &>(E1.Value);
const Lattice &L2 = llvm::any_cast<const Lattice &>(E2.Value);
return L1 == L2;
}
void transferTypeErased(const Stmt *Stmt, TypeErasedLattice &E,
Environment &Env) final {
Lattice &L = llvm::any_cast<Lattice &>(E.Value);
static_cast<Derived *>(this)->transfer(Stmt, L, Env);
}
private:
ASTContext &Context;
};
template <typename LatticeT> struct DataflowAnalysisState {
LatticeT Lattice;
Environment Env;
};
template <typename AnalysisT>
llvm::Expected<std::vector<
llvm::Optional<DataflowAnalysisState<typename AnalysisT::Lattice>>>>
runDataflowAnalysis(
const ControlFlowContext &CFCtx, AnalysisT &Analysis,
const Environment &InitEnv,
std::function<void(const Stmt *, const DataflowAnalysisState<
typename AnalysisT::Lattice> &)>
PostVisitStmt = nullptr) {
std::function<void(const Stmt *, const TypeErasedDataflowAnalysisState &)>
PostVisitStmtClosure = nullptr;
if (PostVisitStmt != nullptr) {
PostVisitStmtClosure = [&PostVisitStmt](
const Stmt *Stmt,
const TypeErasedDataflowAnalysisState &State) {
auto *Lattice =
llvm::any_cast<typename AnalysisT::Lattice>(&State.Lattice.Value);
PostVisitStmt(Stmt, DataflowAnalysisState<typename AnalysisT::Lattice>{
*Lattice, State.Env});
};
}
auto TypeErasedBlockStates = runTypeErasedDataflowAnalysis(
CFCtx, Analysis, InitEnv, PostVisitStmtClosure);
if (!TypeErasedBlockStates)
return TypeErasedBlockStates.takeError();
std::vector<
llvm::Optional<DataflowAnalysisState<typename AnalysisT::Lattice>>>
BlockStates;
BlockStates.reserve(TypeErasedBlockStates->size());
llvm::transform(std::move(*TypeErasedBlockStates),
std::back_inserter(BlockStates), [](auto &OptState) {
return std::move(OptState).map([](auto &&State) {
return DataflowAnalysisState<typename AnalysisT::Lattice>{
llvm::any_cast<typename AnalysisT::Lattice>(
std::move(State.Lattice.Value)),
std::move(State.Env)};
});
});
return BlockStates;
}
class DataflowModel : public Environment::ValueModel {
public:
virtual bool transfer(const Stmt *Stmt, Environment &Env) = 0;
};
} }
#endif