Refactor GeneratesMethodGenerator into a tiny orchestrator with focused helper components#14
Conversation
Co-authored-by: dex3r <3155725+dex3r@users.noreply.github.com>
Co-authored-by: dex3r <3155725+dex3r@users.noreply.github.com>
GeneratesMethodGenerator into focused components and centralize diagnostics
dex3r
left a comment
There was a problem hiding this comment.
That is a good start. Now, extract even more code out of GeneratesMethodGenerator, so it's very tiny. The helper classes and methods should be small and unit-testable.
There was a problem hiding this comment.
Pull request overview
Refactors GeneratesMethodGenerator to improve structure by separating target collection/validation and centralizing diagnostic descriptors, while keeping the generation logic and outputs the same.
Changes:
- Extracted
[GeneratesMethod]discovery/validation intoGeneratesMethodGenerationTargetCollectorand introducedGeneratesMethodGenerationTargetas a typed transfer model. - Centralized diagnostic descriptors into
GeneratesMethodGenerator.Diagnostics.csand updated generator code to reference them. - Replaced
varwith explicit types in touched generator paths.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| MattSourceGenHelpers.Generators/GeneratesMethodGenerator.cs | Updated generator to consume collected targets, reference centralized diagnostics, and use explicit typing. |
| MattSourceGenHelpers.Generators/GeneratesMethodGenerator.Diagnostics.cs | New centralized diagnostic descriptor definitions (MSGH001–MSGH004). |
| MattSourceGenHelpers.Generators/GeneratesMethodGenerationTargetCollector.cs | New collector that discovers/validates generator methods and emits validation diagnostics. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: dex3r <3155725+dex3r@users.noreply.github.com>
Co-authored-by: dex3r <3155725+dex3r@users.noreply.github.com>
Done in 681caa0 (with follow-up polish in e89e0c4). |
GeneratesMethodGenerator into focused components and centralize diagnosticsGeneratesMethodGenerator into a tiny orchestrator with focused helper components
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| PortableExecutableReference? match = compilation.References | ||
| .OfType<PortableExecutableReference>() | ||
| .FirstOrDefault(reference => string.Equals( | ||
| Path.GetFileNameWithoutExtension(reference.FilePath), | ||
| assemblyName.Name, | ||
| StringComparison.OrdinalIgnoreCase)); | ||
| return match?.FilePath != null ? context.LoadFromAssemblyPath(match.FilePath) : null; |
There was a problem hiding this comment.
PortableExecutableReference.FilePath is nullable, but the predicate calls Path.GetFileNameWithoutExtension(reference.FilePath) without a null check. This can throw (and also triggers nullable warnings) when the compilation contains in-memory references with FilePath == null. Consider filtering to reference.FilePath is not null before calling Path.* (and/or using a safe fallback).
There was a problem hiding this comment.
Fixed in 095d0c1 by guarding reference.FilePath is not null before calling Path.GetFileNameWithoutExtension in the resolver lookup.
| PortableExecutableReference? abstractionsReference = compilation.References | ||
| .OfType<PortableExecutableReference>() | ||
| .FirstOrDefault(reference => string.Equals( | ||
| Path.GetFileNameWithoutExtension(reference.FilePath), | ||
| "MattSourceGenHelpers.Abstractions", | ||
| StringComparison.OrdinalIgnoreCase)); |
There was a problem hiding this comment.
The lookup for the Abstractions reference assumes reference.FilePath is non-null (Path.GetFileNameWithoutExtension(reference.FilePath)). FilePath can be null for some metadata references, which would crash the generator. Add a null check in the predicate (or otherwise handle null paths) before calling Path.*.
There was a problem hiding this comment.
Fixed in 095d0c1 by adding a null-safe predicate for reference.FilePath in the Abstractions-reference lookup.
| .FirstOrDefault(reference => string.Equals( | ||
| Path.GetFileNameWithoutExtension(reference.FilePath), | ||
| assemblyName.Name, | ||
| StringComparison.OrdinalIgnoreCase)); |
There was a problem hiding this comment.
Same nullable FilePath issue in the AssemblyLoadContext resolver: Path.GetFileNameWithoutExtension(reference.FilePath) can throw if FilePath is null. Guard with reference.FilePath is not null before using it.
| .FirstOrDefault(reference => string.Equals( | |
| Path.GetFileNameWithoutExtension(reference.FilePath), | |
| assemblyName.Name, | |
| StringComparison.OrdinalIgnoreCase)); | |
| .FirstOrDefault(reference => | |
| reference.FilePath is not null && | |
| string.Equals( | |
| Path.GetFileNameWithoutExtension(reference.FilePath), | |
| assemblyName.Name, | |
| StringComparison.OrdinalIgnoreCase)); |
There was a problem hiding this comment.
Addressed in 095d0c1 with the suggested null guard in the second AssemblyLoadContext resolver lookup.
|
@copilot apply changes based on the comments in this thread |
Co-authored-by: dex3r <3155725+dex3r@users.noreply.github.com>
Applied in 095d0c1. I implemented the thread feedback by adding null guards for |
PortableExecutableReference.FilePathhandling in runtime resolver/lookupsOriginal 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.