Refactor GeneratesMethod target resolution to use named constructor parameter mapping#25
Conversation
Co-authored-by: dex3r <3155725+dex3r@users.noreply.github.com>
Co-authored-by: dex3r <3155725+dex3r@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR refactors how [GeneratesMethod] attribute constructor argument resolution is performed in the source generator. Instead of implicitly accessing ConstructorArguments[0] (positional index), the generator now resolves the index by explicitly finding the constructor parameter named SameClassMethodName using Roslyn's IParameterSymbol. A test fixture usage is also updated to exercise the named-argument form of the attribute.
Changes:
- Refactored
GeneratesMethodGenerationTargetCollectorto resolve the target method name argument by matching the constructor parameter name, instead of hard-coding index0. - Added
using MattSourceGenHelpers.Abstractions;to supportnameof(GeneratesMethod.SameClassMethodName)in the generator. - Updated
TestColorsClassinUnitTest1.csto use an explicit named argument (sameClassMethodName:) for the[GeneratesMethod]attribute.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
MattSourceGenHelpers.Generators/GeneratesMethodGenerationTargetCollector.cs |
Core refactor: adds parameter name-based resolution loop instead of positional index [0] |
MattSourceGenHelpers.Tests/UnitTest1.cs |
Updates attribute usage to named argument form to exercise the refactored path |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| for (int parameterIndex = 0; parameterIndex < constructorParameters.Length; parameterIndex++) | ||
| { | ||
| IParameterSymbol constructorParameter = constructorParameters[parameterIndex]; | ||
| if (constructorParameter.Name.Equals(nameof(GeneratesMethod.SameClassMethodName), StringComparison.OrdinalIgnoreCase)) |
There was a problem hiding this comment.
The comparison uses nameof(GeneratesMethod.SameClassMethodName), which evaluates to "SameClassMethodName" (PascalCase — the property name), while the constructor parameter name is "sameClassMethodName" (camelCase). The match only works because OrdinalIgnoreCase is used. This creates a subtle semantic mismatch: the intent is to find a constructor parameter by name, but the nameof expression refers to the property, not the parameter.
A more precise approach would be to compare directly against the known constructor parameter name using Ordinal comparison (e.g., "sameClassMethodName"), or to restructure the comparison to be case-sensitive with the correct casing. Since C# identifiers are case-sensitive, using OrdinalIgnoreCase for constructor parameter name matching could theoretically match unintended parameters if a different constructor overload were ever added with a similarly-named parameter differing only in case. While not a current bug, it reduces the clarity and robustness of the intent expressed in the code.
| if (constructorParameter.Name.Equals(nameof(GeneratesMethod.SameClassMethodName), StringComparison.OrdinalIgnoreCase)) | |
| if (string.Equals(constructorParameter.Name, "sameClassMethodName", StringComparison.Ordinal)) |
[GeneratesMethod]handling in the generator relied on implicit positional access to constructor arguments. This change makes target method resolution explicit by mapping constructor arguments via theSameClassMethodNameparameter name (nameof(...)) instead of assuming index0.Generator: remove implicit constructor argument indexing
GeneratesMethodGenerationTargetCollectorto resolve the constructor argument index by matching constructor parameter name againstnameof(GeneratesMethod.SameClassMethodName).Usage coverage: named argument form
sameClassMethodName:), validating compatibility with the refactored resolution path.Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.