-
Notifications
You must be signed in to change notification settings - Fork 315
Support partial method customization without attributes #8627
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Co-authored-by: JoshLove-msft <[email protected]>
…ute generation) Co-authored-by: JoshLove-msft <[email protected]>
Co-authored-by: JoshLove-msft <[email protected]>
|
||
namespace Microsoft.TypeSpec.Generator.Providers | ||
{ | ||
internal class CodeGenMethodAttributeDefinition : TypeProvider |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot we shouldn't need a new attribute. Users should be able to just define a partial custom method and we should use our matching logic to figure out the corresponding method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! Removed the CodeGenMethodAttribute
and refactored to use the existing method matching logic.
Users now just define a partial method declaration in custom code (no attribute needed), and the generator automatically detects it by checking the syntax for the partial
keyword and absence of a method body. The partial declaration is matched to the generated method using the existing IsMatch
logic based on method name and parameter types.
Changes in commit 6ea25d3.
…l methods Co-authored-by: JoshLove-msft <[email protected]>
{ | ||
if (ShouldGenerate(method)) | ||
// Check if there's a matching partial method declaration in custom code | ||
var matchingPartialDeclaration = partialMethodDeclarations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot I think this is too late to be changing the signature. We will need to update it further upstream in RestClientProvider as it will impact the method body statements. Also, remember that for partial methods the generated method will need to have all required parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right that changing the signature after the method body is built is problematic. I've addressed the optional parameters issue in commit 39a938f by ensuring all parameters are required in partial method implementations.
However, the deeper concern about parameter references in the method body is valid - if custom code renames parameters, the body will still reference old names. The current implementation works for the common case where parameter names aren't changed, but full parameter renaming support would require:
- Detecting partial declarations before building method bodies, or
- Updating parameter references in the body when swapping signatures
Would you prefer I:
- a) Document that parameter renaming is not currently supported (signature must match exactly)
- b) Attempt to implement early detection of partial declarations before method body construction
- c) Leave as-is for now and track parameter renaming as a future enhancement?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We will need to implement early detection in RestClientProvider which is responsible for computing the operation parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Though thinking about it more, this would only account for customization of client methods and would not handle things like factory methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot since the main scenario is customizing client method signatures, let's move the detection logic to RestClientProvider.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved the detection logic to ScmMethodProviderCollection.BuildProtocolMethod() in commit 9a7e509. Now partial method signatures are detected and applied before the method body is built, resolving the parameter reference issue. The method body is constructed with the correct custom signature from the start, avoiding mismatches.
@copilot this isn't true. They wouldn't need to suppress the method, they would need to re-implement it in custom code though. |
…o default values) Co-authored-by: JoshLove-msft <[email protected]>
... You're correct - I'll update the PR description to reflect that users would need to re-implement the method in custom code, not suppress and re-implement. The suppression isn't required. |
…y signature customization Co-authored-by: JoshLove-msft <[email protected]>
Overview
This PR implements partial method support for the TypeSpec C# generator, allowing library authors to customize method signatures without having to reimplement the entire method body.
Problem
Previously, if a library author wanted to change just the signature of a generated method - for example, to adjust access modifiers - they would need to manually reimplement the full method body in custom code.
This was particularly problematic because:
Solution
Users can now define a partial method declaration in their custom code with no attribute required. The generator automatically:
partial
keyword and absence of a method bodyScmMethodProviderCollection.BuildProtocolMethod()
for client methods)This allows users to own the method signature while the generator owns the implementation.
Example Usage
Custom Code (user provides signature):
Generated Code (generator provides implementation):
Changes
Core Implementation
MethodSignatureModifiers.cs
: AddedPartial = 8192
flag for partial method supportCodeWriter.cs
: Updated to write thepartial
keyword when the modifier is setMethodProvider.cs
: AddedIsPartialMethod
property (with public setter) to track partial methodsNamedTypeSymbolProvider.cs
: Added logic to detect partial method declarations by checking syntax (partial keyword + no body)ScmMethodProviderCollection.cs
: Added early detection logic inBuildProtocolMethod()
to:TypeProvider.cs
: EnhancedBuildMethodsInternal()
to:ShouldGenerate()
to skip partial method declarations during suppression checksTests
CanCustomizeMethodSignature()
validating end-to-end functionalityBenefits
✅ Access modifier changes - Adjust method visibility
✅ Early signature customization - Signature is applied before method body construction, avoiding parameter reference issues
✅ Separation of concerns - User owns signature, generator owns implementation
✅ Type safety - Partial methods enforce matching signatures
✅ No breaking changes - Fully backward compatible with existing code
✅ No new attributes - Uses existing method matching logic automatically
✅ C# compliance - All parameters are required in partial implementations
Architecture
For client protocol methods, partial method detection happens in
ScmMethodProviderCollection.BuildProtocolMethod()
where method parameters are computed. This ensures the custom signature is applied before the method body is built, preventing parameter reference mismatches.For other method types (e.g., factory methods), partial method detection falls back to
TypeProvider.BuildMethodsInternal()
for compatibility.Note on Method Renaming
Method renaming could be added in the future using
CodeGenMemberAttribute
or similar approaches.Fixes #4418
Original prompt
💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.