Index: clang/docs/LibASTMatchersReference.html =================================================================== --- clang/docs/LibASTMatchersReference.html +++ clang/docs/LibASTMatchersReference.html @@ -7298,6 +7298,16 @@ +
Matches the substatement associated with a case statement. + +Given + switch (1) { case 1: break; case 2: return; break; default: return; break; } +caseStmt(hasSubstatement(returnStmt())) + matches "case 2: return;" +
Matches if the cast's source expression or opaque value's source expression matches the given matcher. @@ -7653,6 +7663,16 @@
Matches the substatement associated with a default statement. + +Given + switch (1) { case 1: break; case 2: return; break; default: return; break; } +defaultStmt(hasSubstatement(returnStmt())) + matches "default: return;" +
Matches the substatement associated with a label statement. + +Given + foo: return; + bar: break; +labelStmt(hasSubstatement(breakStmt())) + matches "bar: break;" +
Matches a `LambdaCapture` that refers to the specified `VarDecl`. The `VarDecl` can be a separate variable that is captured by value or Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ clang/include/clang/ASTMatchers/ASTMatchers.h @@ -2429,6 +2429,7 @@ /// Matches co_await expressions where the type of the promise is dependent extern const internal::VariadicDynCastAllOfMatcherdependentCoawaitExpr; + /// Matches co_yield expressions. /// /// Given @@ -7716,6 +7717,29 @@ return InnerMatcher.matches(*Node.getLHS(), Finder, Builder); } +/// Matches the substatement associated with a case, default or label statement. +/// +/// Given +/// \code +/// switch (1) { case 1: break; case 2: return; break; default: return; break; +/// } +/// foo: return; +/// bar: break; +/// \endcode +/// +/// caseStmt(hasSubstmt(returnStmt())) +/// matches "case 2: return;" +/// defaultStmt(hasSubstmt(returnStmt())) +/// matches "default: return;" +/// labelStmt(hasSubstmt(breakStmt())) +/// matches "bar: break;" +AST_POLYMORPHIC_MATCHER_P(hasSubstatement, + AST_POLYMORPHIC_SUPPORTED_TYPES(CaseStmt, DefaultStmt, + LabelStmt), + internal::Matcher , InnerMatcher) { + return InnerMatcher.matches(*Node.getSubStmt(), Finder, Builder); +} + /// Matches declaration that has a given attribute. /// /// Given Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -66,7 +66,7 @@ #define REGISTER_MATCHER(name) \ registerMatcher(#name, internal::makeMatcherAutoMarshall( \ - ::clang::ast_matchers::name, #name)); + ::clang::ast_matchers::name, #name)) #define REGISTER_MATCHER_OVERLOAD(name) \ registerMatcher(#name, \ @@ -143,7 +143,7 @@ REGISTER_MATCHER(atomicType); REGISTER_MATCHER(attr); REGISTER_MATCHER(autoType); - REGISTER_MATCHER(autoreleasePoolStmt) + REGISTER_MATCHER(autoreleasePoolStmt); REGISTER_MATCHER(binaryConditionalOperator); REGISTER_MATCHER(binaryOperator); REGISTER_MATCHER(binaryOperation); @@ -355,6 +355,7 @@ REGISTER_MATCHER(hasSpecializedTemplate); REGISTER_MATCHER(hasStaticStorageDuration); REGISTER_MATCHER(hasStructuredBlock); + REGISTER_MATCHER(hasSubstatement); REGISTER_MATCHER(hasSyntacticForm); REGISTER_MATCHER(hasTargetDecl); REGISTER_MATCHER(hasTemplateArgument); Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -145,6 +145,23 @@ HasDescendantVariableI)); } +TEST_P(ASTMatchersTest, HasCaseSubstmt) { + EXPECT_TRUE(matches( + "void f() { switch (1) { case 1: return; break; default: break; } }", + traverse(TK_AsIs, caseStmt(hasSubstatement(returnStmt()))))); +} + +TEST_P(ASTMatchersTest, HasDefaultSubstmt) { + EXPECT_TRUE(matches( + "void f() { switch (1) { case 1: return; break; default: break; } }", + traverse(TK_AsIs, defaultStmt(hasSubstatement(breakStmt()))))); +} + +TEST_P(ASTMatchersTest, HasLabelSubstmt) { + EXPECT_TRUE(matches("void f() { while (1) { bar: break; foo: return; } }", + traverse(TK_AsIs, labelStmt(hasSubstatement(breakStmt()))))); +} + TEST(TypeMatcher, MatchesClassType) { TypeMatcher TypeA = hasDeclaration(recordDecl(hasName("A")));