https://github.com/zwuis updated https://github.com/llvm/llvm-project/pull/154298
>From 14102c2c5bbd5c4caa9049f87699cce82cdc4481 Mon Sep 17 00:00:00 2001 From: Yanzuo Liu <zw...@outlook.com> Date: Tue, 19 Aug 2025 17:29:18 +0800 Subject: [PATCH 1/2] Make `hasConditionVariableStatement` support `for` loop, `while` loop and `switch` statement --- clang/docs/ReleaseNotes.rst | 3 ++ clang/include/clang/ASTMatchers/ASTMatchers.h | 17 ++++++---- .../ASTMatchers/ASTMatchersNodeTest.cpp | 33 +++++++++++++++++++ .../ASTMatchers/ASTMatchersTraversalTest.cpp | 15 --------- 4 files changed, 47 insertions(+), 21 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b86a9c437ffb1..7ca574d316250 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -322,6 +322,9 @@ AST Matchers - Add a boolean member ``IgnoreSystemHeaders`` to ``MatchFinderOptions``. This allows it to ignore nodes in system headers when traversing the AST. +- ``hasConditionVariableStatement`` now supports ``for`` loop, ``while`` loop + and ``switch`` statement. + clang-format ------------ - Add ``SpaceInEmptyBraces`` option and set it to ``Always`` for WebKit style. diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index cbd931cabd806..787f4a9af0772 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -5661,8 +5661,8 @@ AST_POLYMORPHIC_MATCHER_P(hasInitStatement, return Init != nullptr && InnerMatcher.matches(*Init, Finder, Builder); } -/// Matches the condition expression of an if statement, for loop, -/// switch statement or conditional operator. +/// Matches the condition expression of an if statement, for loop, while loop, +/// do-while loop, switch statement or conditional operator. /// /// Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true)))) /// \code @@ -5739,16 +5739,21 @@ AST_POLYMORPHIC_MATCHER_P(equalsBoundNode, return Builder->removeBindings(Predicate); } -/// Matches the condition variable statement in an if statement. +/// Matches the condition variable statement in an if statement, for loop, +/// while loop or switch statement. /// /// Given /// \code /// if (A* a = GetAPointer()) {} +/// for (; A* a = GetAPointer(); ) {} /// \endcode /// hasConditionVariableStatement(...) -/// matches 'A* a = GetAPointer()'. -AST_MATCHER_P(IfStmt, hasConditionVariableStatement, - internal::Matcher<DeclStmt>, InnerMatcher) { +/// matches both 'A* a = GetAPointer()'. +AST_POLYMORPHIC_MATCHER_P(hasConditionVariableStatement, + AST_POLYMORPHIC_SUPPORTED_TYPES(IfStmt, ForStmt, + WhileStmt, + SwitchStmt), + internal::Matcher<DeclStmt>, InnerMatcher) { const DeclStmt* const DeclarationStatement = Node.getConditionVariableDeclStmt(); return DeclarationStatement != nullptr && diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp index b55928f7060da..d7df9cae01f33 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -1183,6 +1183,39 @@ TEST_P(ASTMatchersTest, AsmStatement) { EXPECT_TRUE(matches("void foo() { __asm(\"mov al, 2\"); }", asmStmt())); } +TEST_P(ASTMatchersTest, HasConditionVariableStatement) { + if (!GetParam().isCXX()) { + // FIXME: Add a test for `hasConditionVariableStatement()` that does not + // depend on C++. + return; + } + + StatementMatcher IfCondition = + ifStmt(hasConditionVariableStatement(declStmt())); + + EXPECT_TRUE(matches("void x() { if (int* a = 0) {} }", IfCondition)); + EXPECT_TRUE(notMatches("void x() { if (true) {} }", IfCondition)); + EXPECT_TRUE(notMatches("void x() { int x; if ((x = 42)) {} }", IfCondition)); + + StatementMatcher SwitchCondition = + switchStmt(hasConditionVariableStatement(declStmt())); + + EXPECT_TRUE(matches("void x() { switch (int a = 0) {} }", SwitchCondition)); + if (GetParam().isCXX17OrLater()) { + EXPECT_TRUE( + notMatches("void x() { switch (int a = 0; a) {} }", SwitchCondition)); + } + + StatementMatcher ForCondition = + forStmt(hasConditionVariableStatement(declStmt())); + + EXPECT_TRUE(matches("void x() { for (; int a = 0; ) {} }", ForCondition)); + EXPECT_TRUE(notMatches("void x() { for (int a = 0; ; ) {} }", ForCondition)); + + EXPECT_TRUE(matches("void x() { while (int a = 0) {} }", + whileStmt(hasConditionVariableStatement(declStmt())))); +} + TEST_P(ASTMatchersTest, HasCondition) { if (!GetParam().isCXX()) { // FIXME: Add a test for `hasCondition()` that does not depend on C++. diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp index d58bc00c995e0..c0a03deb5b543 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -5142,21 +5142,6 @@ TEST(ForEachLambdaCapture, MatchExplicitCapturesOnly) { matcher, std::make_unique<VerifyIdIsBoundTo<LambdaCapture>>("LC", 1))); } -TEST(HasConditionVariableStatement, DoesNotMatchCondition) { - EXPECT_TRUE(notMatches( - "void x() { if(true) {} }", - ifStmt(hasConditionVariableStatement(declStmt())))); - EXPECT_TRUE(notMatches( - "void x() { int x; if((x = 42)) {} }", - ifStmt(hasConditionVariableStatement(declStmt())))); -} - -TEST(HasConditionVariableStatement, MatchesConditionVariables) { - EXPECT_TRUE(matches( - "void x() { if(int* a = 0) {} }", - ifStmt(hasConditionVariableStatement(declStmt())))); -} - TEST(ForEach, BindsOneNode) { EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; };", recordDecl(hasName("C"), forEach(fieldDecl(hasName("x")).bind("x"))), >From 9e62f8d26ee638350c0d58b8f1eb475f761e83d1 Mon Sep 17 00:00:00 2001 From: Yanzuo Liu <zw...@outlook.com> Date: Tue, 19 Aug 2025 23:36:39 +0800 Subject: [PATCH 2/2] statement -> statements Co-authored-by: Aaron Ballman <aa...@aaronballman.com> --- clang/docs/ReleaseNotes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 7ca574d316250..b6ad73edb6960 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -323,7 +323,7 @@ AST Matchers allows it to ignore nodes in system headers when traversing the AST. - ``hasConditionVariableStatement`` now supports ``for`` loop, ``while`` loop - and ``switch`` statement. + and ``switch`` statements. clang-format ------------ _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits