[clang] [Clang][ASTMatchers] Make `hasConditionVariableStatement` support `for` loop, `while` loop and `switch` statement (PR #154298)
Yanzuo Liu via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 19 08:36:47 PDT 2025
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 <zwuis at 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 <zwuis at outlook.com>
Date: Tue, 19 Aug 2025 23:36:39 +0800
Subject: [PATCH 2/2] statement -> statements
Co-authored-by: Aaron Ballman <aaron at 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
------------
More information about the cfe-commits
mailing list