[PATCH] D140794: [ASTMatcher] Add coroutineBodyStmt matcher

2023-03-01 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added a comment.

In D140794#4160358 , @ccotter wrote:

> Thanks both! Assuming this passes build, would one of you mind committing 
> this for me? `Chris Cotter `

Happy to do so! I've landed it on your behalf in 
dcf5ad89dcc5cc69b9df3e5dd9be71c65642f519 



Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140794/new/

https://reviews.llvm.org/D140794

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D140794: [ASTMatcher] Add coroutineBodyStmt matcher

2023-03-01 Thread Aaron Ballman via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGdcf5ad89dcc5: [ASTMatcher] Add coroutineBodyStmt matcher 
(authored by ccotter, committed by aaron.ballman).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140794/new/

https://reviews.llvm.org/D140794

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/lib/ASTMatchers/Dynamic/Registry.cpp
  clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
  clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp

Index: clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp
===
--- clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -364,7 +364,8 @@
 "to build matcher: mapAnyOf.",
 ParseWithError("mapAnyOf(\"foo\")"));
   EXPECT_EQ("Input value has unresolved overloaded type: "
-"Matcher",
+"Matcher",
 ParseMatcherWithError("hasBody(stmt())"));
   EXPECT_EQ(
   "1:1: Error parsing argument 1 for matcher decl.\n"
Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -678,6 +678,48 @@
   EXPECT_TRUE(matchesConditionally(CoYieldCode, 
coyieldExpr(isExpansionInMainFile()), 
true, {"-std=c++20", "-I/"}, M));
+
+  StringRef NonCoroCode = R"cpp(
+#include 
+void non_coro_function() {
+}
+)cpp";
+
+  EXPECT_TRUE(matchesConditionally(CoReturnCode, coroutineBodyStmt(), true,
+   {"-std=c++20", "-I/"}, M));
+  EXPECT_TRUE(matchesConditionally(CoAwaitCode, coroutineBodyStmt(), true,
+   {"-std=c++20", "-I/"}, M));
+  EXPECT_TRUE(matchesConditionally(CoYieldCode, coroutineBodyStmt(), true,
+   {"-std=c++20", "-I/"}, M));
+
+  EXPECT_FALSE(matchesConditionally(NonCoroCode, coroutineBodyStmt(), true,
+{"-std=c++20", "-I/"}, M));
+
+  StringRef CoroWithDeclCode = R"cpp(
+#include 
+void coro() {
+  int thevar;
+  co_return 1;
+}
+)cpp";
+  EXPECT_TRUE(matchesConditionally(
+  CoroWithDeclCode,
+  coroutineBodyStmt(hasBody(compoundStmt(
+  has(declStmt(containsDeclaration(0, varDecl(hasName("thevar",
+  true, {"-std=c++20", "-I/"}, M));
+
+  StringRef CoroWithTryCatchDeclCode = R"cpp(
+#include 
+void coro() try {
+  int thevar;
+  co_return 1;
+} catch (...) {}
+)cpp";
+  EXPECT_TRUE(matchesConditionally(
+  CoroWithTryCatchDeclCode,
+  coroutineBodyStmt(hasBody(cxxTryStmt(has(compoundStmt(has(
+  declStmt(containsDeclaration(0, varDecl(hasName("thevar")),
+  true, {"-std=c++20", "-I/"}, M));
 }
 
 TEST(Matcher, isClassMessage) {
Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -175,6 +175,7 @@
   REGISTER_MATCHER(containsDeclaration);
   REGISTER_MATCHER(continueStmt);
   REGISTER_MATCHER(coreturnStmt);
+  REGISTER_MATCHER(coroutineBodyStmt);
   REGISTER_MATCHER(coyieldExpr);
   REGISTER_MATCHER(cudaKernelCallExpr);
   REGISTER_MATCHER(cxxBaseSpecifier);
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -910,6 +910,8 @@
 const internal::VariadicDynCastAllOfMatcher caseStmt;
 const internal::VariadicDynCastAllOfMatcher defaultStmt;
 const internal::VariadicDynCastAllOfMatcher compoundStmt;
+const internal::VariadicDynCastAllOfMatcher
+coroutineBodyStmt;
 const internal::VariadicDynCastAllOfMatcher cxxCatchStmt;
 const internal::VariadicDynCastAllOfMatcher cxxTryStmt;
 const internal::VariadicDynCastAllOfMatcher cxxThrowExpr;
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2450,6 +2450,17 @@
 extern const internal::VariadicDynCastAllOfMatcher
 coyieldExpr;
 
+/// Matches coroutine body statements.
+///
+/// coroutineBodyStmt() matches the coroutine below
+/// \code
+///   generator gen() {
+/// co_return;
+///   }
+/// \endcode
+extern const internal::VariadicDynCastAllOfMatcher
+coroutineBodyStmt;
+
 /// Matches nullptr literal.
 extern const internal::VariadicDynCastAllOfMatcher
 

[PATCH] D140794: [ASTMatcher] Add coroutineBodyStmt matcher

2023-02-28 Thread Chris Cotter via Phabricator via cfe-commits
ccotter added a comment.

Thanks both! Assuming this passes build, would one of you mind committing this 
for me? `Chris Cotter `


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140794/new/

https://reviews.llvm.org/D140794

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D140794: [ASTMatcher] Add coroutineBodyStmt matcher

2023-02-28 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman accepted this revision.
aaron.ballman added a comment.
This revision is now accepted and ready to land.

LGTM! Thanks @sammccall for weighing in, I appreciate it. :-)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140794/new/

https://reviews.llvm.org/D140794

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D140794: [ASTMatcher] Add coroutineBodyStmt matcher

2023-02-27 Thread Chris Cotter via Phabricator via cfe-commits
ccotter updated this revision to Diff 500996.
ccotter added a comment.

fix bad 'arc diff'


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140794/new/

https://reviews.llvm.org/D140794

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/lib/ASTMatchers/Dynamic/Registry.cpp
  clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
  clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp

Index: clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp
===
--- clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -364,7 +364,8 @@
 "to build matcher: mapAnyOf.",
 ParseWithError("mapAnyOf(\"foo\")"));
   EXPECT_EQ("Input value has unresolved overloaded type: "
-"Matcher",
+"Matcher",
 ParseMatcherWithError("hasBody(stmt())"));
   EXPECT_EQ(
   "1:1: Error parsing argument 1 for matcher decl.\n"
Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -678,6 +678,48 @@
   EXPECT_TRUE(matchesConditionally(CoYieldCode, 
coyieldExpr(isExpansionInMainFile()), 
true, {"-std=c++20", "-I/"}, M));
+
+  StringRef NonCoroCode = R"cpp(
+#include 
+void non_coro_function() {
+}
+)cpp";
+
+  EXPECT_TRUE(matchesConditionally(CoReturnCode, coroutineBodyStmt(), true,
+   {"-std=c++20", "-I/"}, M));
+  EXPECT_TRUE(matchesConditionally(CoAwaitCode, coroutineBodyStmt(), true,
+   {"-std=c++20", "-I/"}, M));
+  EXPECT_TRUE(matchesConditionally(CoYieldCode, coroutineBodyStmt(), true,
+   {"-std=c++20", "-I/"}, M));
+
+  EXPECT_FALSE(matchesConditionally(NonCoroCode, coroutineBodyStmt(), true,
+{"-std=c++20", "-I/"}, M));
+
+  StringRef CoroWithDeclCode = R"cpp(
+#include 
+void coro() {
+  int thevar;
+  co_return 1;
+}
+)cpp";
+  EXPECT_TRUE(matchesConditionally(
+  CoroWithDeclCode,
+  coroutineBodyStmt(hasBody(compoundStmt(
+  has(declStmt(containsDeclaration(0, varDecl(hasName("thevar",
+  true, {"-std=c++20", "-I/"}, M));
+
+  StringRef CoroWithTryCatchDeclCode = R"cpp(
+#include 
+void coro() try {
+  int thevar;
+  co_return 1;
+} catch (...) {}
+)cpp";
+  EXPECT_TRUE(matchesConditionally(
+  CoroWithTryCatchDeclCode,
+  coroutineBodyStmt(hasBody(cxxTryStmt(has(compoundStmt(has(
+  declStmt(containsDeclaration(0, varDecl(hasName("thevar")),
+  true, {"-std=c++20", "-I/"}, M));
 }
 
 TEST(Matcher, isClassMessage) {
Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -175,6 +175,7 @@
   REGISTER_MATCHER(containsDeclaration);
   REGISTER_MATCHER(continueStmt);
   REGISTER_MATCHER(coreturnStmt);
+  REGISTER_MATCHER(coroutineBodyStmt);
   REGISTER_MATCHER(coyieldExpr);
   REGISTER_MATCHER(cudaKernelCallExpr);
   REGISTER_MATCHER(cxxBaseSpecifier);
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -910,6 +910,8 @@
 const internal::VariadicDynCastAllOfMatcher caseStmt;
 const internal::VariadicDynCastAllOfMatcher defaultStmt;
 const internal::VariadicDynCastAllOfMatcher compoundStmt;
+const internal::VariadicDynCastAllOfMatcher
+coroutineBodyStmt;
 const internal::VariadicDynCastAllOfMatcher cxxCatchStmt;
 const internal::VariadicDynCastAllOfMatcher cxxTryStmt;
 const internal::VariadicDynCastAllOfMatcher cxxThrowExpr;
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2450,6 +2450,17 @@
 extern const internal::VariadicDynCastAllOfMatcher
 coyieldExpr;
 
+/// Matches coroutine body statements.
+///
+/// coroutineBodyStmt() matches the coroutine below
+/// \code
+///   generator gen() {
+/// co_return;
+///   }
+/// \endcode
+extern const internal::VariadicDynCastAllOfMatcher
+coroutineBodyStmt;
+
 /// Matches nullptr literal.
 extern const internal::VariadicDynCastAllOfMatcher
 cxxNullPtrLiteralExpr;
@@ -5460,9 +5471,10 @@
   return false;
 }
 
-/// Matches a 'for', 'while', 'do' statement or a function definition that has
-/// a given body. Note that in 

[PATCH] D140794: [ASTMatcher] Add coroutineBodyStmt matcher

2023-02-27 Thread Chris Cotter via Phabricator via cfe-commits
ccotter updated this revision to Diff 500995.
ccotter added a comment.

- update release note, rebase


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140794/new/

https://reviews.llvm.org/D140794

Files:
  clang/include/clang/ASTMatchers/ASTMatchers.h


Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -5495,13 +5495,11 @@
 /// with compoundStmt()
 ///   matching '{}'
 ///   but does not match 'void f();'
-AST_POLYMORPHIC_MATCHER_P(hasBody,
-  AST_POLYMORPHIC_SUPPORTED_TYPES(DoStmt, ForStmt,
-  WhileStmt,
-  CXXForRangeStmt,
-  FunctionDecl,
-  CoroutineBodyStmt),
-  internal::Matcher, InnerMatcher) {
+AST_POLYMORPHIC_MATCHER_P(
+hasBody,
+AST_POLYMORPHIC_SUPPORTED_TYPES(DoStmt, ForStmt, WhileStmt, 
CXXForRangeStmt,
+FunctionDecl, CoroutineBodyStmt),
+internal::Matcher, InnerMatcher) {
   if (Finder->isTraversalIgnoringImplicitNodes() && isDefaultedHelper())
 return false;
   const Stmt *const Statement = internal::GetBodyMatcher::get(Node);


Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -5495,13 +5495,11 @@
 /// with compoundStmt()
 ///   matching '{}'
 ///   but does not match 'void f();'
-AST_POLYMORPHIC_MATCHER_P(hasBody,
-  AST_POLYMORPHIC_SUPPORTED_TYPES(DoStmt, ForStmt,
-  WhileStmt,
-  CXXForRangeStmt,
-  FunctionDecl,
-  CoroutineBodyStmt),
-  internal::Matcher, InnerMatcher) {
+AST_POLYMORPHIC_MATCHER_P(
+hasBody,
+AST_POLYMORPHIC_SUPPORTED_TYPES(DoStmt, ForStmt, WhileStmt, CXXForRangeStmt,
+FunctionDecl, CoroutineBodyStmt),
+internal::Matcher, InnerMatcher) {
   if (Finder->isTraversalIgnoringImplicitNodes() && isDefaultedHelper())
 return false;
   const Stmt *const Statement = internal::GetBodyMatcher::get(Node);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D140794: [ASTMatcher] Add coroutineBodyStmt matcher

2023-02-27 Thread Sam McCall via Phabricator via cfe-commits
sammccall added a comment.

It seems pretty weird to me that the two child edges from functiondecl -> 
coroutinebodystmt -> compoundstmt are both called "body".

However that *is* what they're called in the AST today, and having the matchers 
correspond to the AST's names seems important.
So this seems OK to me (renaming the inner "body" edge to something else seems 
like a good idea, but is out of scope here).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140794/new/

https://reviews.llvm.org/D140794

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D140794: [ASTMatcher] Add coroutineBodyStmt matcher

2023-02-27 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added a comment.

> Hmmm, I'm coming around to reusing hasBody() like you've done here. I think 
> it's pretty weird to read: 
> functionDecl(hasBody(coroutineBodyStmt(hasBody(stmt().bind(...))) because of 
> the duplicated calls to hasBody, but I think it's more defensible now than I 
> was originally thinking. I'm still curious if other folks who care about AST 
> matchers have an opinion given that this is a bit trickier than usual.

I think I'm okay with this direction, but one last try at pinging @klimek and 
@sammccall in case they've got an opinion. If we don't hear from them by Thur 
of this week, I'd say it's fine to move forward with the patch as-is.




Comment at: clang/docs/ReleaseNotes.rst:871
 
+- Add ``coroutineBodyStmt`` matcher.
+

You should also mention that the `hasBody` matcher now works with coroutine 
bodies.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140794/new/

https://reviews.llvm.org/D140794

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D140794: [ASTMatcher] Add coroutineBodyStmt matcher

2023-02-26 Thread Chris Cotter via Phabricator via cfe-commits
ccotter added a comment.

Bump - anyone else have any thoughts here?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140794/new/

https://reviews.llvm.org/D140794

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D140794: [ASTMatcher] Add coroutineBodyStmt matcher

2023-01-10 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added inline comments.



Comment at: clang/include/clang/ASTMatchers/ASTMatchers.h:5503
+  FunctionDecl,
+  CoroutineBodyStmt),
   internal::Matcher, InnerMatcher) {

ccotter wrote:
> aaron.ballman wrote:
> > ccotter wrote:
> > > aaron.ballman wrote:
> > > > I'm not certain it makes sense to me to add `CoroutineBodyStmt` to 
> > > > `hasBody` -- in this case, it doesn't *have* a body, it *is* the body.
> > > With respect to `hasBody()`, my intent was to treat the CoroutineBodyStmt 
> > > node as analogous to a FunctionDecl or WhileStmt. WhileStmts have 
> > > information like the loop condition expression, as CoroutineBodyStmts 
> > > contain the synthesized expressions such as the initial suspend Stmt. 
> > > Both WhileStmts and CoroutineBodyStmts then have the `getBody()` methods, 
> > > usually a CompoundStmt for WhileStmts and either a CompoundStmt or 
> > > TryStmt for CoroutineBodyStmts.
> > > 
> > > Ultimately, I wanted to be able to match the CoroutineBodyStmt's 
> > > `function-body` (using the grammar) from the standard, e.g., 
> > > `coroutineBodyStmt(hasBody(compoundStmt().bind(...)))`. If there is a 
> > > different approach you'd recommend that's in line with the AST matcher 
> > > design strategy, I can use that instead.
> > What concerns me about the approach you have is that it doesn't model the 
> > AST. A coroutine body statement is a special kind of function body, so it 
> > does not itself *have* a body. So this is a bit like adding `CompoundStmt` 
> > to the `hasBody` matcher in that regard.
> > 
> > To me, the correct way to surface this would be to write the matcher: 
> > `functionDecl(hasBody(coroutineBodyStmt()))` to get to the coroutine body, 
> > and if you want to bind to the compound statement, I'd imagine 
> > `functionDecl(hasBody(coroutineBodyStmt(has(compoundStmt().bind(...)` 
> > would be the correct approach. My thinking there is that we'd use the 
> > `has()` traversal matcher to go from the coroutine body to any of the extra 
> > information it tracks (the compound statement, the promise, 
> > allocate/deallocate, etc).
> > 
> > Pinging @klimek and @sammccall for additional opinions.
> I think I see. With my proposal, the match would be 
> `functionDecl(hasBody(coroutineBodyStmt(hasBody(stmt().bind(...)`. For 
> completeness, your suggestion would need 
> `functionDecl(hasBody(coroutineBodyStmt(has(stmt(anyOf(cxxTryStmt(), 
> compoundStmt()).bind(...))`.
> 
> I am a bit hung up though on two things, and clarifications on both would 
> help solidify my understanding of the design philosophy of the matchers. 
> First, since `CoroutineBodyStmt` has a `getBody()` method, I assumed it would 
> make it eligible for the `hasBody` matcher, although perhaps I am making an 
> incorrect assumption/generalization here?
> 
> Second, the `has()` approach seems less accurate since we would be relying on 
> the fact that the other children nodes of `CoroutineBodyStmt` (initial or 
> final suspend point, etc) would never be a `CompoundStmt` or `CXXTryStmt`, 
> else we might get unintentional matches. Or, one might miss the CXXTryStmt 
> corner case.
> 
> Follow up question - should a need arise (say, authoring many clang-tidy 
> checks that need extensive coroutine matcher support on the initial suspend 
> point etc), would we see the matchers supporting things like 
> `coroutineBodyStmt(hasInitialSuspendPoint(...), hasFinalSuspendPoint(..))`, 
> or rely on a combination of `has` approach / non-ASTMatcher logic (or locally 
> defined ASTMatchers within the clang-tidy library)?
> 
> It looks like this phab can be broken down into two changes - first, the 
> addition of a `coroutineBodyStmt` matcher, and second, a `hasBody` traversal 
> matcher for `coroutineBodyStmt`. Happy to separate these out depending on the 
> direction of the discussion.
> I am a bit hung up though on two things, and clarifications on both would 
> help solidify my understanding of the design philosophy of the matchers. 
> First, since CoroutineBodyStmt has a getBody() method, I assumed it would 
> make it eligible for the hasBody matcher, although perhaps I am making an 
> incorrect assumption/generalization here?

As I understand the evolution here, we started out with `hasBody()` to match on 
function declaration AST nodes with a body. It then evolved to include 
do/while/for (and eventually range-based for) loops, which is a bit of an odd 
decision (why not anything with a substatement, like `if` or `switch`?). Now 
we're looking to add support for the coroutine body node, but that has a half 
dozen+ different things we can traverse to, one of which is the compound 
statement for the coroutine body. All of these cases are kind of different from 
one another, so the design is a bit confusing (at least to me).

> 

[PATCH] D140794: [ASTMatcher] Add coroutineBodyStmt matcher

2023-01-10 Thread Chris Cotter via Phabricator via cfe-commits
ccotter added inline comments.



Comment at: clang/include/clang/ASTMatchers/ASTMatchers.h:5503
+  FunctionDecl,
+  CoroutineBodyStmt),
   internal::Matcher, InnerMatcher) {

aaron.ballman wrote:
> ccotter wrote:
> > aaron.ballman wrote:
> > > I'm not certain it makes sense to me to add `CoroutineBodyStmt` to 
> > > `hasBody` -- in this case, it doesn't *have* a body, it *is* the body.
> > With respect to `hasBody()`, my intent was to treat the CoroutineBodyStmt 
> > node as analogous to a FunctionDecl or WhileStmt. WhileStmts have 
> > information like the loop condition expression, as CoroutineBodyStmts 
> > contain the synthesized expressions such as the initial suspend Stmt. Both 
> > WhileStmts and CoroutineBodyStmts then have the `getBody()` methods, 
> > usually a CompoundStmt for WhileStmts and either a CompoundStmt or TryStmt 
> > for CoroutineBodyStmts.
> > 
> > Ultimately, I wanted to be able to match the CoroutineBodyStmt's 
> > `function-body` (using the grammar) from the standard, e.g., 
> > `coroutineBodyStmt(hasBody(compoundStmt().bind(...)))`. If there is a 
> > different approach you'd recommend that's in line with the AST matcher 
> > design strategy, I can use that instead.
> What concerns me about the approach you have is that it doesn't model the 
> AST. A coroutine body statement is a special kind of function body, so it 
> does not itself *have* a body. So this is a bit like adding `CompoundStmt` to 
> the `hasBody` matcher in that regard.
> 
> To me, the correct way to surface this would be to write the matcher: 
> `functionDecl(hasBody(coroutineBodyStmt()))` to get to the coroutine body, 
> and if you want to bind to the compound statement, I'd imagine 
> `functionDecl(hasBody(coroutineBodyStmt(has(compoundStmt().bind(...)` 
> would be the correct approach. My thinking there is that we'd use the `has()` 
> traversal matcher to go from the coroutine body to any of the extra 
> information it tracks (the compound statement, the promise, 
> allocate/deallocate, etc).
> 
> Pinging @klimek and @sammccall for additional opinions.
I think I see. With my proposal, the match would be 
`functionDecl(hasBody(coroutineBodyStmt(hasBody(stmt().bind(...)`. For 
completeness, your suggestion would need 
`functionDecl(hasBody(coroutineBodyStmt(has(stmt(anyOf(cxxTryStmt(), 
compoundStmt()).bind(...))`.

I am a bit hung up though on two things, and clarifications on both would help 
solidify my understanding of the design philosophy of the matchers. First, 
since `CoroutineBodyStmt` has a `getBody()` method, I assumed it would make it 
eligible for the `hasBody` matcher, although perhaps I am making an incorrect 
assumption/generalization here?

Second, the `has()` approach seems less accurate since we would be relying on 
the fact that the other children nodes of `CoroutineBodyStmt` (initial or final 
suspend point, etc) would never be a `CompoundStmt` or `CXXTryStmt`, else we 
might get unintentional matches. Or, one might miss the CXXTryStmt corner case.

Follow up question - should a need arise (say, authoring many clang-tidy checks 
that need extensive coroutine matcher support on the initial suspend point 
etc), would we see the matchers supporting things like 
`coroutineBodyStmt(hasInitialSuspendPoint(...), hasFinalSuspendPoint(..))`, or 
rely on a combination of `has` approach / non-ASTMatcher logic (or locally 
defined ASTMatchers within the clang-tidy library)?

It looks like this phab can be broken down into two changes - first, the 
addition of a `coroutineBodyStmt` matcher, and second, a `hasBody` traversal 
matcher for `coroutineBodyStmt`. Happy to separate these out depending on the 
direction of the discussion.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140794/new/

https://reviews.llvm.org/D140794

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D140794: [ASTMatcher] Add coroutineBodyStmt matcher

2023-01-10 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added a subscriber: sammccall.
aaron.ballman added inline comments.



Comment at: clang/include/clang/ASTMatchers/ASTMatchers.h:5503
+  FunctionDecl,
+  CoroutineBodyStmt),
   internal::Matcher, InnerMatcher) {

ccotter wrote:
> aaron.ballman wrote:
> > I'm not certain it makes sense to me to add `CoroutineBodyStmt` to 
> > `hasBody` -- in this case, it doesn't *have* a body, it *is* the body.
> With respect to `hasBody()`, my intent was to treat the CoroutineBodyStmt 
> node as analogous to a FunctionDecl or WhileStmt. WhileStmts have information 
> like the loop condition expression, as CoroutineBodyStmts contain the 
> synthesized expressions such as the initial suspend Stmt. Both WhileStmts and 
> CoroutineBodyStmts then have the `getBody()` methods, usually a CompoundStmt 
> for WhileStmts and either a CompoundStmt or TryStmt for CoroutineBodyStmts.
> 
> Ultimately, I wanted to be able to match the CoroutineBodyStmt's 
> `function-body` (using the grammar) from the standard, e.g., 
> `coroutineBodyStmt(hasBody(compoundStmt().bind(...)))`. If there is a 
> different approach you'd recommend that's in line with the AST matcher design 
> strategy, I can use that instead.
What concerns me about the approach you have is that it doesn't model the AST. 
A coroutine body statement is a special kind of function body, so it does not 
itself *have* a body. So this is a bit like adding `CompoundStmt` to the 
`hasBody` matcher in that regard.

To me, the correct way to surface this would be to write the matcher: 
`functionDecl(hasBody(coroutineBodyStmt()))` to get to the coroutine body, and 
if you want to bind to the compound statement, I'd imagine 
`functionDecl(hasBody(coroutineBodyStmt(has(compoundStmt().bind(...)` would 
be the correct approach. My thinking there is that we'd use the `has()` 
traversal matcher to go from the coroutine body to any of the extra information 
it tracks (the compound statement, the promise, allocate/deallocate, etc).

Pinging @klimek and @sammccall for additional opinions.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140794/new/

https://reviews.llvm.org/D140794

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D140794: [ASTMatcher] Add coroutineBodyStmt matcher

2023-01-10 Thread Chris Cotter via Phabricator via cfe-commits
ccotter updated this revision to Diff 487789.
ccotter added a comment.

- Fix ParserTest.Errors


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140794/new/

https://reviews.llvm.org/D140794

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/lib/ASTMatchers/Dynamic/Registry.cpp
  clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
  clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp

Index: clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp
===
--- clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -366,7 +366,8 @@
 "to build matcher: mapAnyOf.",
 ParseWithError("mapAnyOf(\"foo\")"));
   EXPECT_EQ("Input value has unresolved overloaded type: "
-"Matcher",
+"Matcher",
 ParseMatcherWithError("hasBody(stmt())"));
   EXPECT_EQ(
   "1:1: Error parsing argument 1 for matcher decl.\n"
Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -678,6 +678,48 @@
   EXPECT_TRUE(matchesConditionally(CoYieldCode, 
coyieldExpr(isExpansionInMainFile()), 
true, {"-std=c++20", "-I/"}, M));
+
+  StringRef NonCoroCode = R"cpp(
+#include 
+void non_coro_function() {
+}
+)cpp";
+
+  EXPECT_TRUE(matchesConditionally(CoReturnCode, coroutineBodyStmt(), true,
+   {"-std=c++20", "-I/"}, M));
+  EXPECT_TRUE(matchesConditionally(CoAwaitCode, coroutineBodyStmt(), true,
+   {"-std=c++20", "-I/"}, M));
+  EXPECT_TRUE(matchesConditionally(CoYieldCode, coroutineBodyStmt(), true,
+   {"-std=c++20", "-I/"}, M));
+
+  EXPECT_FALSE(matchesConditionally(NonCoroCode, coroutineBodyStmt(), true,
+{"-std=c++20", "-I/"}, M));
+
+  StringRef CoroWithDeclCode = R"cpp(
+#include 
+void coro() {
+  int thevar;
+  co_return 1;
+}
+)cpp";
+  EXPECT_TRUE(matchesConditionally(
+  CoroWithDeclCode,
+  coroutineBodyStmt(hasBody(compoundStmt(
+  has(declStmt(containsDeclaration(0, varDecl(hasName("thevar",
+  true, {"-std=c++20", "-I/"}, M));
+
+  StringRef CoroWithTryCatchDeclCode = R"cpp(
+#include 
+void coro() try {
+  int thevar;
+  co_return 1;
+} catch (...) {}
+)cpp";
+  EXPECT_TRUE(matchesConditionally(
+  CoroWithTryCatchDeclCode,
+  coroutineBodyStmt(hasBody(cxxTryStmt(has(compoundStmt(has(
+  declStmt(containsDeclaration(0, varDecl(hasName("thevar")),
+  true, {"-std=c++20", "-I/"}, M));
 }
 
 TEST(Matcher, isClassMessage) {
Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -175,6 +175,7 @@
   REGISTER_MATCHER(containsDeclaration);
   REGISTER_MATCHER(continueStmt);
   REGISTER_MATCHER(coreturnStmt);
+  REGISTER_MATCHER(coroutineBodyStmt);
   REGISTER_MATCHER(coyieldExpr);
   REGISTER_MATCHER(cudaKernelCallExpr);
   REGISTER_MATCHER(cxxBaseSpecifier);
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -909,6 +909,8 @@
 const internal::VariadicDynCastAllOfMatcher caseStmt;
 const internal::VariadicDynCastAllOfMatcher defaultStmt;
 const internal::VariadicDynCastAllOfMatcher compoundStmt;
+const internal::VariadicDynCastAllOfMatcher
+coroutineBodyStmt;
 const internal::VariadicDynCastAllOfMatcher cxxCatchStmt;
 const internal::VariadicDynCastAllOfMatcher cxxTryStmt;
 const internal::VariadicDynCastAllOfMatcher cxxThrowExpr;
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2449,6 +2449,17 @@
 extern const internal::VariadicDynCastAllOfMatcher
 coyieldExpr;
 
+/// Matches coroutine body statements.
+///
+/// coroutineBodyStmt() matches the coroutine below
+/// \code
+///   generator gen() {
+/// co_return;
+///   }
+/// \endcode
+extern const internal::VariadicDynCastAllOfMatcher
+coroutineBodyStmt;
+
 /// Matches nullptr literal.
 extern const internal::VariadicDynCastAllOfMatcher
 cxxNullPtrLiteralExpr;
@@ -5460,9 +5471,9 @@
 }
 
 /// Matches a 'for', 'while', 'do while' statement or a function
-/// definition that has a given body. Note that in case of 

[PATCH] D140794: [ASTMatcher] Add coroutineBodyStmt matcher

2023-01-09 Thread Chris Cotter via Phabricator via cfe-commits
ccotter updated this revision to Diff 487661.
ccotter marked an inline comment as not done.
ccotter added a comment.

- Add hasBody matcher support for coroutineBodyStmt
- update doc
- Sort list
- clang-format


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140794/new/

https://reviews.llvm.org/D140794

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/lib/ASTMatchers/Dynamic/Registry.cpp
  clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -678,6 +678,48 @@
   EXPECT_TRUE(matchesConditionally(CoYieldCode, 
coyieldExpr(isExpansionInMainFile()), 
true, {"-std=c++20", "-I/"}, M));
+
+  StringRef NonCoroCode = R"cpp(
+#include 
+void non_coro_function() {
+}
+)cpp";
+
+  EXPECT_TRUE(matchesConditionally(CoReturnCode, coroutineBodyStmt(), true,
+   {"-std=c++20", "-I/"}, M));
+  EXPECT_TRUE(matchesConditionally(CoAwaitCode, coroutineBodyStmt(), true,
+   {"-std=c++20", "-I/"}, M));
+  EXPECT_TRUE(matchesConditionally(CoYieldCode, coroutineBodyStmt(), true,
+   {"-std=c++20", "-I/"}, M));
+
+  EXPECT_FALSE(matchesConditionally(NonCoroCode, coroutineBodyStmt(), true,
+{"-std=c++20", "-I/"}, M));
+
+  StringRef CoroWithDeclCode = R"cpp(
+#include 
+void coro() {
+  int thevar;
+  co_return 1;
+}
+)cpp";
+  EXPECT_TRUE(matchesConditionally(
+  CoroWithDeclCode,
+  coroutineBodyStmt(hasBody(compoundStmt(
+  has(declStmt(containsDeclaration(0, varDecl(hasName("thevar",
+  true, {"-std=c++20", "-I/"}, M));
+
+  StringRef CoroWithTryCatchDeclCode = R"cpp(
+#include 
+void coro() try {
+  int thevar;
+  co_return 1;
+} catch (...) {}
+)cpp";
+  EXPECT_TRUE(matchesConditionally(
+  CoroWithTryCatchDeclCode,
+  coroutineBodyStmt(hasBody(cxxTryStmt(has(compoundStmt(has(
+  declStmt(containsDeclaration(0, varDecl(hasName("thevar")),
+  true, {"-std=c++20", "-I/"}, M));
 }
 
 TEST(Matcher, isClassMessage) {
Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -175,6 +175,7 @@
   REGISTER_MATCHER(containsDeclaration);
   REGISTER_MATCHER(continueStmt);
   REGISTER_MATCHER(coreturnStmt);
+  REGISTER_MATCHER(coroutineBodyStmt);
   REGISTER_MATCHER(coyieldExpr);
   REGISTER_MATCHER(cudaKernelCallExpr);
   REGISTER_MATCHER(cxxBaseSpecifier);
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -909,6 +909,8 @@
 const internal::VariadicDynCastAllOfMatcher caseStmt;
 const internal::VariadicDynCastAllOfMatcher defaultStmt;
 const internal::VariadicDynCastAllOfMatcher compoundStmt;
+const internal::VariadicDynCastAllOfMatcher
+coroutineBodyStmt;
 const internal::VariadicDynCastAllOfMatcher cxxCatchStmt;
 const internal::VariadicDynCastAllOfMatcher cxxTryStmt;
 const internal::VariadicDynCastAllOfMatcher cxxThrowExpr;
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2449,6 +2449,17 @@
 extern const internal::VariadicDynCastAllOfMatcher
 coyieldExpr;
 
+/// Matches coroutine body statements.
+///
+/// coroutineBodyStmt() matches the coroutine below
+/// \code
+///   generator gen() {
+/// co_return;
+///   }
+/// \endcode
+extern const internal::VariadicDynCastAllOfMatcher
+coroutineBodyStmt;
+
 /// Matches nullptr literal.
 extern const internal::VariadicDynCastAllOfMatcher
 cxxNullPtrLiteralExpr;
@@ -5460,9 +5471,9 @@
 }
 
 /// Matches a 'for', 'while', 'do while' statement or a function
-/// definition that has a given body. Note that in case of functions
-/// this matcher only matches the definition itself and not the other
-/// declarations of the same function.
+/// or coroutine definition that has a given body. Note that in case of
+/// functions this matcher only matches the definition itself and not
+/// the other declarations of the same function.
 ///
 /// Given
 /// \code
@@ -5484,12 +5495,11 @@
 ///   matching '{}'
 ///   but does not match 'void f();'
 
-AST_POLYMORPHIC_MATCHER_P(hasBody,
-  

[PATCH] D140794: [ASTMatcher] Add coroutineBodyStmt matcher

2023-01-09 Thread Chris Cotter via Phabricator via cfe-commits
ccotter added inline comments.



Comment at: clang/include/clang/ASTMatchers/ASTMatchers.h:5503
+  FunctionDecl,
+  CoroutineBodyStmt),
   internal::Matcher, InnerMatcher) {

aaron.ballman wrote:
> I'm not certain it makes sense to me to add `CoroutineBodyStmt` to `hasBody` 
> -- in this case, it doesn't *have* a body, it *is* the body.
With respect to `hasBody()`, my intent was to treat the CoroutineBodyStmt node 
as analogous to a FunctionDecl or WhileStmt. WhileStmts have information like 
the loop condition expression, as CoroutineBodyStmts contain the synthesized 
expressions such as the initial suspend Stmt. Both WhileStmts and 
CoroutineBodyStmts then have the `getBody()` methods, usually a CompoundStmt 
for WhileStmts and either a CompoundStmt or TryStmt for CoroutineBodyStmts.

Ultimately, I wanted to be able to match the CoroutineBodyStmt's 
`function-body` (using the grammar) from the standard, e.g., 
`coroutineBodyStmt(hasBody(compoundStmt().bind(...)))`. If there is a different 
approach you'd recommend that's in line with the AST matcher design strategy, I 
can use that instead.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140794/new/

https://reviews.llvm.org/D140794

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D140794: [ASTMatcher] Add coroutineBodyStmt matcher

2023-01-09 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added a comment.

Thank you for this! FWIW, it looks like precommit CI found some issues that 
need to be resolved.




Comment at: clang/include/clang/ASTMatchers/ASTMatchers.h:5503
+  FunctionDecl,
+  CoroutineBodyStmt),
   internal::Matcher, InnerMatcher) {

I'm not certain it makes sense to me to add `CoroutineBodyStmt` to `hasBody` -- 
in this case, it doesn't *have* a body, it *is* the body.



Comment at: clang/lib/ASTMatchers/Dynamic/Registry.cpp:171
   REGISTER_MATCHER(compoundStmt);
+  REGISTER_MATCHER(coroutineBodyStmt);
   REGISTER_MATCHER(coawaitExpr);

Please keep this sorted alphabetically.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140794/new/

https://reviews.llvm.org/D140794

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D140794: [ASTMatcher] Add coroutineBodyStmt matcher

2022-12-30 Thread Chris Cotter via Phabricator via cfe-commits
ccotter updated this revision to Diff 485748.
ccotter added a comment.

- Add hasBody matcher support for coroutineBodyStmt


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140794/new/

https://reviews.llvm.org/D140794

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/lib/ASTMatchers/Dynamic/Registry.cpp
  clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -678,6 +678,52 @@
   EXPECT_TRUE(matchesConditionally(CoYieldCode, 
coyieldExpr(isExpansionInMainFile()), 
true, {"-std=c++20", "-I/"}, M));
+
+  StringRef NonCoroCode = R"cpp(
+#include 
+void non_coro_function() {
+}
+)cpp";
+
+  EXPECT_TRUE(matchesConditionally(CoReturnCode, 
+   coroutineBodyStmt(),
+   true, {"-std=c++20", "-I/"}, M));
+  EXPECT_TRUE(matchesConditionally(CoAwaitCode, 
+   coroutineBodyStmt(),
+   true, {"-std=c++20", "-I/"}, M));
+  EXPECT_TRUE(matchesConditionally(CoYieldCode, 
+   coroutineBodyStmt(),
+   true, {"-std=c++20", "-I/"}, M));
+
+  EXPECT_FALSE(matchesConditionally(NonCoroCode,
+   coroutineBodyStmt(),
+   true, {"-std=c++20", "-I/"}, M));
+
+  StringRef CoroWithDeclCode = R"cpp(
+#include 
+void coro() {
+  int thevar;
+  co_return 1;
+}
+)cpp";
+  EXPECT_TRUE(matchesConditionally(
+  CoroWithDeclCode,
+  coroutineBodyStmt(hasBody(compoundStmt(
+  has(declStmt(containsDeclaration(0, varDecl(hasName("thevar",
+  true, {"-std=c++20", "-I/"}, M));
+
+  StringRef CoroWithTryCatchDeclCode = R"cpp(
+#include 
+void coro() try {
+  int thevar;
+  co_return 1;
+} catch (...) {}
+)cpp";
+  EXPECT_TRUE(matchesConditionally(
+  CoroWithTryCatchDeclCode,
+  coroutineBodyStmt(hasBody(cxxTryStmt(has(compoundStmt(
+  has(declStmt(containsDeclaration(0, varDecl(hasName("thevar")),
+  true, {"-std=c++20", "-I/"}, M));
 }
 
 TEST(Matcher, isClassMessage) {
Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -168,6 +168,7 @@
   REGISTER_MATCHER(complexType);
   REGISTER_MATCHER(compoundLiteralExpr);
   REGISTER_MATCHER(compoundStmt);
+  REGISTER_MATCHER(coroutineBodyStmt);
   REGISTER_MATCHER(coawaitExpr);
   REGISTER_MATCHER(conditionalOperator);
   REGISTER_MATCHER(constantArrayType);
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -909,6 +909,7 @@
 const internal::VariadicDynCastAllOfMatcher caseStmt;
 const internal::VariadicDynCastAllOfMatcher defaultStmt;
 const internal::VariadicDynCastAllOfMatcher compoundStmt;
+const internal::VariadicDynCastAllOfMatcher coroutineBodyStmt;
 const internal::VariadicDynCastAllOfMatcher cxxCatchStmt;
 const internal::VariadicDynCastAllOfMatcher cxxTryStmt;
 const internal::VariadicDynCastAllOfMatcher cxxThrowExpr;
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2449,6 +2449,17 @@
 extern const internal::VariadicDynCastAllOfMatcher
 coyieldExpr;
 
+/// Matches coroutine body statements.
+///
+/// coroutineBodyStmt() matches the coroutine below
+/// \code
+///   generator gen() {
+/// co_return;
+///   }
+/// \endcode
+extern const internal::VariadicDynCastAllOfMatcher
+coroutineBodyStmt;
+
 /// Matches nullptr literal.
 extern const internal::VariadicDynCastAllOfMatcher
 cxxNullPtrLiteralExpr;
@@ -5488,7 +5499,8 @@
   AST_POLYMORPHIC_SUPPORTED_TYPES(DoStmt, ForStmt,
   WhileStmt,
   CXXForRangeStmt,
-  FunctionDecl),
+  FunctionDecl,
+  CoroutineBodyStmt),
   internal::Matcher, InnerMatcher) {
   if (Finder->isTraversalIgnoringImplicitNodes() && isDefaultedHelper())
 return