forked from OSchip/llvm-project
[clang][dataflow] Allow MatchSwitch to return a value
Reland of D128467. This version replaces `return {};` with `return Result();`, since the former failed on GCC with `Result = void`. Reviewed By: gribozavr2 Differential Revision: https://reviews.llvm.org/D128533
This commit is contained in:
parent
f6c79c6ae4
commit
8c278a2781
|
@ -46,8 +46,8 @@ template <typename LatticeT> struct TransferState {
|
||||||
|
|
||||||
/// Matches against `Stmt` and, based on its structure, dispatches to an
|
/// Matches against `Stmt` and, based on its structure, dispatches to an
|
||||||
/// appropriate handler.
|
/// appropriate handler.
|
||||||
template <typename State>
|
template <typename State, typename Result = void>
|
||||||
using MatchSwitch = std::function<void(const Stmt &, ASTContext &, State &)>;
|
using MatchSwitch = std::function<Result(const Stmt &, ASTContext &, State &)>;
|
||||||
|
|
||||||
/// Collects cases of a "match switch": a collection of matchers paired with
|
/// Collects cases of a "match switch": a collection of matchers paired with
|
||||||
/// callbacks, which together define a switch that can be applied to a
|
/// callbacks, which together define a switch that can be applied to a
|
||||||
|
@ -68,7 +68,7 @@ using MatchSwitch = std::function<void(const Stmt &, ASTContext &, State &)>;
|
||||||
/// .Build();
|
/// .Build();
|
||||||
/// }
|
/// }
|
||||||
/// \endcode
|
/// \endcode
|
||||||
template <typename State> class MatchSwitchBuilder {
|
template <typename State, typename Result = void> class MatchSwitchBuilder {
|
||||||
public:
|
public:
|
||||||
/// Registers an action that will be triggered by the match of a pattern
|
/// Registers an action that will be triggered by the match of a pattern
|
||||||
/// against the input statement.
|
/// against the input statement.
|
||||||
|
@ -79,24 +79,24 @@ public:
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
MatchSwitchBuilder &&
|
MatchSwitchBuilder &&
|
||||||
CaseOf(ast_matchers::internal::Matcher<Stmt> M,
|
CaseOf(ast_matchers::internal::Matcher<Stmt> M,
|
||||||
std::function<void(const Node *,
|
std::function<Result(const Node *,
|
||||||
const ast_matchers::MatchFinder::MatchResult &,
|
const ast_matchers::MatchFinder::MatchResult &,
|
||||||
State &)>
|
State &)>
|
||||||
A) && {
|
A) && {
|
||||||
Matchers.push_back(std::move(M));
|
Matchers.push_back(std::move(M));
|
||||||
Actions.push_back(
|
Actions.push_back(
|
||||||
[A = std::move(A)](const Stmt *Stmt,
|
[A = std::move(A)](const Stmt *Stmt,
|
||||||
const ast_matchers::MatchFinder::MatchResult &R,
|
const ast_matchers::MatchFinder::MatchResult &R,
|
||||||
State &S) { A(cast<Node>(Stmt), R, S); });
|
State &S) { return A(cast<Node>(Stmt), R, S); });
|
||||||
return std::move(*this);
|
return std::move(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchSwitch<State> Build() && {
|
MatchSwitch<State, Result> Build() && {
|
||||||
return [Matcher = BuildMatcher(), Actions = std::move(Actions)](
|
return [Matcher = BuildMatcher(), Actions = std::move(Actions)](
|
||||||
const Stmt &Stmt, ASTContext &Context, State &S) {
|
const Stmt &Stmt, ASTContext &Context, State &S) -> Result {
|
||||||
auto Results = ast_matchers::matchDynamic(Matcher, Stmt, Context);
|
auto Results = ast_matchers::matchDynamic(Matcher, Stmt, Context);
|
||||||
if (Results.empty())
|
if (Results.empty())
|
||||||
return;
|
return Result();
|
||||||
// Look through the map for the first binding of the form "TagN..." use
|
// Look through the map for the first binding of the form "TagN..." use
|
||||||
// that to select the action.
|
// that to select the action.
|
||||||
for (const auto &Element : Results[0].getMap()) {
|
for (const auto &Element : Results[0].getMap()) {
|
||||||
|
@ -104,12 +104,12 @@ public:
|
||||||
size_t Index = 0;
|
size_t Index = 0;
|
||||||
if (ID.consume_front("Tag") && !ID.getAsInteger(10, Index) &&
|
if (ID.consume_front("Tag") && !ID.getAsInteger(10, Index) &&
|
||||||
Index < Actions.size()) {
|
Index < Actions.size()) {
|
||||||
Actions[Index](
|
return Actions[Index](
|
||||||
&Stmt,
|
&Stmt,
|
||||||
ast_matchers::MatchFinder::MatchResult(Results[0], &Context), S);
|
ast_matchers::MatchFinder::MatchResult(Results[0], &Context), S);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return Result();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ast_matchers::internal::DynTypedMatcher> Matchers;
|
std::vector<ast_matchers::internal::DynTypedMatcher> Matchers;
|
||||||
std::vector<std::function<void(
|
std::vector<std::function<Result(
|
||||||
const Stmt *, const ast_matchers::MatchFinder::MatchResult &, State &)>>
|
const Stmt *, const ast_matchers::MatchFinder::MatchResult &, State &)>>
|
||||||
Actions;
|
Actions;
|
||||||
};
|
};
|
||||||
|
|
|
@ -204,3 +204,29 @@ TEST_F(MatchSwitchTest, Neither) {
|
||||||
RunDataflow(Code,
|
RunDataflow(Code,
|
||||||
UnorderedElementsAre(Pair("p", Holds(BooleanLattice(false)))));
|
UnorderedElementsAre(Pair("p", Holds(BooleanLattice(false)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(MatchSwitchTest, ReturnNonVoid) {
|
||||||
|
using namespace ast_matchers;
|
||||||
|
|
||||||
|
auto Unit =
|
||||||
|
tooling::buildASTFromCode("void f() { int x = 42; }", "input.cc",
|
||||||
|
std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Context = Unit->getASTContext();
|
||||||
|
const auto *S =
|
||||||
|
selectFirst<FunctionDecl>(
|
||||||
|
"f",
|
||||||
|
match(functionDecl(isDefinition(), hasName("f")).bind("f"), Context))
|
||||||
|
->getBody();
|
||||||
|
|
||||||
|
MatchSwitch<const int, std::vector<int>> Switch =
|
||||||
|
MatchSwitchBuilder<const int, std::vector<int>>()
|
||||||
|
.CaseOf<Stmt>(stmt(),
|
||||||
|
[](const Stmt *, const MatchFinder::MatchResult &,
|
||||||
|
const int &State) -> std::vector<int> {
|
||||||
|
return {1, State, 3};
|
||||||
|
})
|
||||||
|
.Build();
|
||||||
|
std::vector<int> Actual = Switch(*S, Context, 7);
|
||||||
|
std::vector<int> Expected{1, 7, 3};
|
||||||
|
EXPECT_EQ(Actual, Expected);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue