Skip to content

Remove UseProvidedBody string matching from DelegateBodySyntaxExtractor#96

Merged
dex3r merged 3 commits intofeature/metehod_templatefrom
copilot/remove-looking-for-body-statement
Apr 2, 2026
Merged

Remove UseProvidedBody string matching from DelegateBodySyntaxExtractor#96
dex3r merged 3 commits intofeature/metehod_templatefrom
copilot/remove-looking-for-body-statement

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 25, 2026

DelegateBodySyntaxExtractor searched for lambdas by matching the string "UseProvidedBody" against method names in the syntax tree. This is fragile and unnecessary since BodyGenerationData.RuntimeDelegateBody already tells us whether a delegate body was provided.

Approach

Instead of string-matching a method name, use the data from BodyGenerationData to decide when to extract, and structural position to decide what to extract:

  • FluentBodyResult — Added HasDelegateBody flag, set when RuntimeDelegateBody is non-null
  • GeneratesMethodGenerationPipeline — Reversed the flow: execute the generator method first, then use HasDelegateBody to conditionally trigger syntax extraction
  • DelegateBodySyntaxExtractor — Replaced descendant-node scan for "UseProvidedBody" with structural lookup: find the outermost InvocationExpressionSyntax in the method's return expression and extract its lambda argument
-InvocationExpressionSyntax? invocation = generatorMethodSyntax
-    .DescendantNodes()
-    .OfType<InvocationExpressionSyntax>()
-    .FirstOrDefault(inv =>
-        inv.Expression is MemberAccessExpressionSyntax memberAccess &&
-        memberAccess.Name.Identifier.Text == "UseProvidedBody");
+ExpressionSyntax? returnExpression = GetReturnExpression(generatorMethodSyntax);
+if (returnExpression is not InvocationExpressionSyntax invocation)
+    return null;

Pre-existing fix

Added missing WithCompileTimeConstants and Stage5 implementations in DataMethodBodyBuilders.cs to fix build errors on this branch.

Original prompt

This section details on the original issue you should resolve

<issue_title>Remove looking for body statement</issue_title>
<issue_description>In a previous PR, #94, a new way to create body was added: to copy the code defined in UseProvidedBody method to the target body.

I like how that works, but I don't like how that is implemented. In DelegateBodySyntaxExtractor, the code looks for memberAccess.Name.Identifier.Text == "UseProvidedBody" which is not very clean.

In BodyGenerationData record, the delegate defined in UseProvidedBody is already stored. Is that not enough to copy the source code? Maybe UseProvidedBody instead of taking Action/Func delegate, should take some "Expression" parameter, or something, so it can capture the exact code, which would remove the need to look for "UseProvidedBody" string?</issue_description>

Comments on the Issue (you are @copilot in this section)


⚡ Quickly spin up Copilot coding agent tasks from anywhere on your macOS or Windows machine with Raycast.

Copilot AI and others added 2 commits March 25, 2026 16:17
Refactor the delegate body extraction to use structural syntax analysis
instead of searching for the "UseProvidedBody" method name string.

Changes:
- DelegateBodySyntaxExtractor now finds the lambda by looking at the
  outermost invocation's lambda argument in the method's return
  expression, instead of scanning for "UseProvidedBody" string
- FluentBodyResult gets HasDelegateBody flag indicating RuntimeDelegateBody
  was set in BodyGenerationData
- BodyGenerationDataExtractor sets HasDelegateBody when RuntimeDelegateBody
  is non-null
- GeneratesMethodGenerationPipeline executes the method first, then uses
  HasDelegateBody to decide if syntax extraction is needed
- Add missing WithCompileTimeConstants implementations to fix pre-existing
  build errors in DataMethodBodyBuilders

Co-authored-by: dex3r <3155725+dex3r@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dex3r/EasySourceGenerators/sessions/ea25cd90-2a07-42c1-8091-f255cb2c6687
Copilot AI changed the title [WIP] Remove looking for body statement Remove UseProvidedBody string matching from DelegateBodySyntaxExtractor Mar 25, 2026
Copilot AI requested a review from dex3r March 25, 2026 16:20
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 2, 2026

Codecov Report

❌ Patch coverage is 16.07143% with 47 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
....Generators/DataBuilding/DataMethodBodyBuilders.cs 0.00% 14 Missing ⚠️
...crementalGenerators/DelegateBodySyntaxExtractor.cs 0.00% 14 Missing ⚠️
...talGenerators/GeneratesMethodGenerationPipeline.cs 0.00% 13 Missing ⚠️
...crementalGenerators/BodyGenerationDataExtractor.cs 53.84% 4 Missing and 2 partials ⚠️

📢 Thoughts on this report? Let us know!

@dex3r dex3r marked this pull request as ready for review April 2, 2026 11:29
Copilot AI review requested due to automatic review settings April 2, 2026 11:29
@dex3r dex3r merged commit bfb4dfc into feature/metehod_template Apr 2, 2026
2 checks passed
@dex3r dex3r deleted the copilot/remove-looking-for-body-statement branch April 2, 2026 11:29
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes fragile string-matching for detecting UseProvidedBody and instead uses BodyGenerationData.RuntimeDelegateBody to decide when to extract a delegate body, while updating syntax extraction to look at the generator method’s return expression structure.

Changes:

  • Added HasDelegateBody to FluentBodyResult and populated it from BodyGenerationData.RuntimeDelegateBody.
  • Reordered fluent-body generation flow to execute the generator method first, then conditionally run syntax extraction only when a delegate body was provided.
  • Updated DelegateBodySyntaxExtractor to extract the lambda body from the outermost invocation in the generator method’s return expression (instead of scanning descendants for "UseProvidedBody"), and added missing fluent builder stages for compile-time constants.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
EasySourceGenerators.Generators/IncrementalGenerators/GeneratesMethodGenerationPipeline.cs Switches fluent-body flow to runtime-execute first and then conditionally syntax-extract delegate bodies.
EasySourceGenerators.Generators/IncrementalGenerators/GeneratesMethodExecutionRuntime.cs Extends FluentBodyResult to include HasDelegateBody.
EasySourceGenerators.Generators/IncrementalGenerators/DelegateBodySyntaxExtractor.cs Changes extraction strategy to use the generator method’s return expression shape and adds GetReturnExpression.
EasySourceGenerators.Generators/IncrementalGenerators/BodyGenerationDataExtractor.cs Sets HasDelegateBody based on presence of RuntimeDelegateBody.
EasySourceGenerators.Generators/DataBuilding/DataMethodBodyBuilders.cs Adds missing WithCompileTimeConstants and Stage5 builder implementations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +126 to +130
if (result!.HasDelegateBody)
{
string? delegateBody = DelegateBodySyntaxExtractor.TryExtractDelegateBody(methodInfo.Syntax);
if (delegateBody != null)
{
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When HasDelegateBody is true but TryExtractDelegateBody returns null (e.g., non-lambda argument or unexpected return-expression shape), the code silently falls back to GenerateSimplePartialMethod. For parameterized delegates, ReturnValue will be null and the generated partial method will return default, which is incorrect and hard to diagnose. Consider reporting a diagnostic (and failing generation for that target) when HasDelegateBody is true but extraction fails, instead of falling back to the runtime-evaluated ReturnValue.

Copilot uses AI. Check for mistakes.
Comment on lines +64 to +70
if (method.Body != null)
{
ReturnStatementSyntax? returnStatement = method.Body.Statements
.OfType<ReturnStatementSyntax>()
.FirstOrDefault();
return returnStatement?.Expression;
}
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetReturnExpression’s comment says the method “assumes … at most one return statement”, but the implementation uses FirstOrDefault(), which will silently pick the first return if there are multiple. Consider enforcing the assumption (e.g., SingleOrDefault + diagnostic) or updating the comment/logic so unexpected shapes don’t lead to extracting the wrong expression without any signal.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants