[clang] 4eecd19 - [clang][dataflow] Allow MatchSwitch to return a value
Sam Estep via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 24 06:33:46 PDT 2022
Author: Sam Estep
Date: 2022-06-24T13:32:47Z
New Revision: 4eecd194b073492a309b87c8f60da6614bba9153
URL: https://github.com/llvm/llvm-project/commit/4eecd194b073492a309b87c8f60da6614bba9153
DIFF: https://github.com/llvm/llvm-project/commit/4eecd194b073492a309b87c8f60da6614bba9153.diff
LOG: [clang][dataflow] Allow MatchSwitch to return a value
This patch adds another `typename` parameter to `MatchSwitch` class: `Result` (defaults to `void`), corresponding to the return type of the function. This necessitates a couple minor changes to the `MatchSwitchBuilder` class, and is tested via a new `ReturnNonVoid` test in `clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp`.
Reviewed By: gribozavr2, sgatev, xazax.hun
Differential Revision: https://reviews.llvm.org/D128467
Added:
Modified:
clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h
clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h b/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h
index 2aaaf78f9cd0e..77271bda188d5 100644
--- a/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h
+++ b/clang/include/clang/Analysis/FlowSensitive/MatchSwitch.h
@@ -46,8 +46,8 @@ template <typename LatticeT> struct TransferState {
/// Matches against `Stmt` and, based on its structure, dispatches to an
/// appropriate handler.
-template <typename State>
-using MatchSwitch = std::function<void(const Stmt &, ASTContext &, State &)>;
+template <typename State, typename Result = void>
+using MatchSwitch = std::function<Result(const Stmt &, ASTContext &, State &)>;
/// Collects cases of a "match switch": a collection of matchers paired with
/// 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();
/// }
/// \endcode
-template <typename State> class MatchSwitchBuilder {
+template <typename State, typename Result = void> class MatchSwitchBuilder {
public:
/// Registers an action that will be triggered by the match of a pattern
/// against the input statement.
@@ -79,24 +79,24 @@ template <typename State> class MatchSwitchBuilder {
template <typename Node>
MatchSwitchBuilder &&
CaseOf(ast_matchers::internal::Matcher<Stmt> M,
- std::function<void(const Node *,
- const ast_matchers::MatchFinder::MatchResult &,
- State &)>
+ 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) { A(cast<Node>(Stmt), R, S); });
+ State &S) { return A(cast<Node>(Stmt), R, S); });
return std::move(*this);
}
- MatchSwitch<State> Build() && {
+ MatchSwitch<State, Result> Build() && {
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);
if (Results.empty())
- return;
+ return {};
// Look through the map for the first binding of the form "TagN..." use
// that to select the action.
for (const auto &Element : Results[0].getMap()) {
@@ -104,12 +104,12 @@ template <typename State> class MatchSwitchBuilder {
size_t Index = 0;
if (ID.consume_front("Tag") && !ID.getAsInteger(10, Index) &&
Index < Actions.size()) {
- Actions[Index](
+ return Actions[Index](
&Stmt,
ast_matchers::MatchFinder::MatchResult(Results[0], &Context), S);
- return;
}
}
+ return {};
};
}
@@ -142,7 +142,7 @@ template <typename State> class MatchSwitchBuilder {
}
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 &)>>
Actions;
};
diff --git a/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp b/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp
index bd2ae0e96c01e..98319760fd206 100644
--- a/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp
@@ -204,3 +204,29 @@ TEST_F(MatchSwitchTest, Neither) {
RunDataflow(Code,
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);
+}
More information about the cfe-commits
mailing list