r181588 - Add caseStmt(), defaultStmt(), eachCase() and hasCaseConstant() matchers.
Peter Collingbourne
peter at pcc.me.uk
Fri May 10 04:52:03 PDT 2013
Author: pcc
Date: Fri May 10 06:52:02 2013
New Revision: 181588
URL: http://llvm.org/viewvc/llvm-project?rev=181588&view=rev
Log:
Add caseStmt(), defaultStmt(), eachCase() and hasCaseConstant() matchers.
Differential Revision: http://llvm-reviews.chandlerc.com/D744
Modified:
cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=181588&r1=181587&r2=181588&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Fri May 10 06:52:02 2013
@@ -894,6 +894,26 @@ const internal::VariadicDynCastAllOfMatc
/// matches 'case 42: break;' and 'default: break;'.
const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchCase> switchCase;
+/// \brief Matches case statements inside switch statements.
+///
+/// Given
+/// \code
+/// switch(a) { case 42: break; default: break; }
+/// \endcode
+/// caseStmt()
+/// matches 'case 42: break;'.
+const internal::VariadicDynCastAllOfMatcher<Stmt, CaseStmt> caseStmt;
+
+/// \brief Matches default statements inside switch statements.
+///
+/// Given
+/// \code
+/// switch(a) { case 42: break; default: break; }
+/// \endcode
+/// defaultStmt()
+/// matches 'default: break;'.
+const internal::VariadicDynCastAllOfMatcher<Stmt, DefaultStmt> defaultStmt;
+
/// \brief Matches compound statements.
///
/// Example matches '{}' and '{{}}'in 'for (;;) {{}}'
@@ -3348,6 +3368,54 @@ AST_MATCHER_P_OVERLOAD(Stmt, equalsNode,
/// @}
+/// \brief Matches each case or default statement belonging to the given switch
+/// statement. This matcher may produce multiple matches.
+///
+/// Given
+/// \code
+/// switch (1) { case 1: case 2: default: switch (2) { case 3: case 4: ; } }
+/// \endcode
+/// switchStmt(forEachSwitchCase(caseStmt().bind("c"))).bind("s")
+/// matches four times, with "c" binding each of "case 1:", "case 2:",
+/// "case 3:" and "case 4:", and "s" respectively binding "switch (1)",
+/// "switch (1)", "switch (2)" and "switch (2)".
+AST_MATCHER_P(SwitchStmt, forEachSwitchCase, internal::Matcher<SwitchCase>,
+ InnerMatcher) {
+ // FIXME: getSwitchCaseList() does not necessarily guarantee a stable
+ // iteration order. We should use the more general iterating matchers once
+ // they are capable of expressing this matcher (for example, it should ignore
+ // case statements belonging to nested switch statements).
+ bool Matched = false;
+ for (const SwitchCase *SC = Node.getSwitchCaseList(); SC;
+ SC = SC->getNextSwitchCase()) {
+ BoundNodesTreeBuilder CaseBuilder;
+ bool CaseMatched = InnerMatcher.matches(*SC, Finder, &CaseBuilder);
+ if (CaseMatched) {
+ Matched = true;
+ Builder->addMatch(CaseBuilder.build());
+ }
+ }
+
+ return Matched;
+}
+
+/// \brief If the given case statement does not use the GNU case range
+/// extension, matches the constant given in the statement.
+///
+/// Given
+/// \code
+/// switch (1) { case 1: case 1+1: case 3 ... 4: ; }
+/// \endcode
+/// caseStmt(hasCaseConstant(integerLiteral()))
+/// matches "case 1:"
+AST_MATCHER_P(CaseStmt, hasCaseConstant, internal::Matcher<Expr>,
+ InnerMatcher) {
+ if (Node.getRHS())
+ return false;
+
+ return InnerMatcher.matches(*Node.getLHS(), Finder, Builder);
+}
+
} // end namespace ast_matchers
} // end namespace clang
Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp?rev=181588&r1=181587&r2=181588&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp Fri May 10 06:52:02 2013
@@ -2924,6 +2924,31 @@ TEST(SwitchCase, MatchesSwitch) {
EXPECT_TRUE(notMatches("void x() {}", switchStmt()));
}
+TEST(SwitchCase, MatchesEachCase) {
+ EXPECT_TRUE(notMatches("void x() { switch(42); }",
+ switchStmt(forEachSwitchCase(caseStmt()))));
+ EXPECT_TRUE(matches("void x() { switch(42) case 42:; }",
+ switchStmt(forEachSwitchCase(caseStmt()))));
+ EXPECT_TRUE(matches("void x() { switch(42) { case 42:; } }",
+ switchStmt(forEachSwitchCase(caseStmt()))));
+ EXPECT_TRUE(notMatches(
+ "void x() { if (1) switch(42) { case 42: switch (42) { default:; } } }",
+ ifStmt(has(switchStmt(forEachSwitchCase(defaultStmt()))))));
+ EXPECT_TRUE(matches("void x() { switch(42) { case 1+1: case 4:; } }",
+ switchStmt(forEachSwitchCase(
+ caseStmt(hasCaseConstant(integerLiteral()))))));
+ EXPECT_TRUE(notMatches("void x() { switch(42) { case 1+1: case 2+2:; } }",
+ switchStmt(forEachSwitchCase(
+ caseStmt(hasCaseConstant(integerLiteral()))))));
+ EXPECT_TRUE(notMatches("void x() { switch(42) { case 1 ... 2:; } }",
+ switchStmt(forEachSwitchCase(
+ caseStmt(hasCaseConstant(integerLiteral()))))));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void x() { switch (42) { case 1: case 2: case 3: default:; } }",
+ switchStmt(forEachSwitchCase(caseStmt().bind("x"))),
+ new VerifyIdIsBoundTo<CaseStmt>("x", 3)));
+}
+
TEST(ExceptionHandling, SimpleCases) {
EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", catchStmt()));
EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", tryStmt()));
More information about the cfe-commits
mailing list