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); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits