#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_
#include "clang/AST/ASTContext.h"
#include "clang/AST/Stmt.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
#include "llvm/ADT/StringRef.h"
#include <functional>
#include <string>
#include <utility>
#include <vector>
namespace clang {
namespace dataflow {
template <typename LatticeT> struct TransferState {
TransferState(LatticeT &Lattice, Environment &Env)
: Lattice(Lattice), Env(Env) {}
LatticeT &Lattice;
Environment &Env;
};
template <typename State, typename Result = void>
using MatchSwitch = std::function<Result(const Stmt &, ASTContext &, State &)>;
template <typename State, typename Result = void> class MatchSwitchBuilder {
public:
template <typename Node>
MatchSwitchBuilder &&
CaseOf(ast_matchers::internal::Matcher<Stmt> M,
std::function<Result(const Node *,
const ast_matchers::MatchFinder::MatchResult &,
State &)>
A) && {
Matchers.push_back(std::move(M));
Actions.push_back(
[A = std::move(A)](const Stmt *Stmt,
const ast_matchers::MatchFinder::MatchResult &R,
State &S) { return A(cast<Node>(Stmt), R, S); });
return std::move(*this);
}
MatchSwitch<State, Result> Build() && {
return [Matcher = BuildMatcher(), Actions = std::move(Actions)](
const Stmt &Stmt, ASTContext &Context, State &S) -> Result {
auto Results = ast_matchers::matchDynamic(Matcher, Stmt, Context);
if (Results.empty())
return Result();
for (const auto &Element : Results[0].getMap()) {
llvm::StringRef ID(Element.first);
size_t Index = 0;
if (ID.consume_front("Tag") && !ID.getAsInteger(10, Index) &&
Index < Actions.size()) {
return Actions[Index](
&Stmt,
ast_matchers::MatchFinder::MatchResult(Results[0], &Context), S);
}
}
return Result();
};
}
private:
ast_matchers::internal::DynTypedMatcher BuildMatcher() {
using ast_matchers::anything;
using ast_matchers::stmt;
using ast_matchers::unless;
using ast_matchers::internal::DynTypedMatcher;
if (Matchers.empty())
return stmt(unless(anything()));
for (int I = 0, N = Matchers.size(); I < N; ++I) {
std::string Tag = ("Tag" + llvm::Twine(I)).str();
Matchers[I].setAllowBind(true);
auto M = *Matchers[I].tryBind(Tag);
Matchers[I] =
!M.getTraversalKind() ? M.withTraversalKind(TK_AsIs) : std::move(M);
}
return DynTypedMatcher::constructVariadic(
DynTypedMatcher::VO_AnyOf, ASTNodeKind::getFromNodeKind<Stmt>(),
std::move(Matchers));
}
std::vector<ast_matchers::internal::DynTypedMatcher> Matchers;
std::vector<std::function<Result(
const Stmt *, const ast_matchers::MatchFinder::MatchResult &, State &)>>
Actions;
};
} } #endif