-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Move diagnostic generation from LibraryImportGenerator to LibraryImportDiagnosticsAnalyzer #123780
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
… diagnostics Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
…itional analyzer loading Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
…till reports diagnostics) Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
This comment was marked as resolved.
This comment was marked as resolved.
jkoritzinsky
left a comment
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 address this review.
|
|
||
| // Only analyze methods with LibraryImportAttribute | ||
| AttributeData? libraryImportAttr = null; | ||
| foreach (AttributeData attr in method.GetAttributes()) | ||
| { | ||
| if (attr.AttributeClass?.ToDisplayString() == TypeNames.LibraryImportAttribute) | ||
| { | ||
| libraryImportAttr = attr; | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| if (libraryImportAttr is null) | ||
| return false; |
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.
Use the LibraryImportAttribute type from the compilation (via GetBestTypeByMetadataName) instead of matching on name
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.
Fixed in 6232571. Now uses GetBestTypeByMetadataName to get the LibraryImportAttribute type and compares using SymbolEqualityComparer.Default.Equals.
|
|
||
| // Process the LibraryImport attribute | ||
| LibraryImportCompilationData libraryImportData = | ||
| ProcessLibraryImportAttribute(libraryImportAttr) ?? |
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.
If ProcessLibraryImportAttribute returns null, we can stop handling diagnostics here. We already know we have an invalid compilation.
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.
Fixed in 6232571. Now returns early with empty diagnostics when ProcessLibraryImportAttribute returns null.
|
|
||
| /// <summary> | ||
| /// Filters the <see cref="IncrementalValuesProvider{TValue}"/> by whether or not the element has a value, discarding diagnostics. | ||
| /// Use this when diagnostics are reported by an analyzer instead of the generator. | ||
| /// </summary> | ||
| public static IncrementalValuesProvider<T> FilterWithoutReportingDiagnostics<T>(this IncrementalValuesProvider<DiagnosticOr<T>> diagnosticOrValues) | ||
| { | ||
| var (values, _) = diagnosticOrValues.Split(); | ||
| return values; | ||
| } |
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'll eventually remove usages of DiagnosticOr so we shouldn't need this helper anyway.
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.
Removed in 6232571. Now uses Split() directly instead of a helper method.
| protected override IEnumerable<DiagnosticAnalyzer> GetDiagnosticAnalyzers() | ||
| { | ||
| // Include the corresponding diagnostics analyzer when testing specific generators. | ||
| // Note: The analyzer is available alongside the generator but diagnostics are still | ||
| // reported by the generator for now. This will change as we migrate diagnostics to analyzers. | ||
| foreach (var analyzer in base.GetDiagnosticAnalyzers()) | ||
| { | ||
| yield return analyzer; | ||
| } | ||
| } | ||
|
|
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.
Instead of overriding GetDiagnosticAnalyzers(), update CSharpSourceGeneratorVerifier to have a TAnalyzer argument as well (and instantiate an instance of that analyzer here).
That should enable you to remove the diagnostics from the LibraryImportGenerator source generator's code.
…per review feedback Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
| }); | ||
|
|
||
| var methodsToGenerate = context.FilterAndReportDiagnostics(methodsWithDiagnostics); | ||
| // Filter methods but don't report diagnostics - the analyzer will handle that |
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 Filter out the diagnostics earlier. I would like to not see DiagnosticOr used in the pipeline at all and instead have diagnostics dropped before they ever get into a step's output.
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.
Fixed in 7a1d4df. Removed DiagnosticOr from the pipeline entirely. Methods are now filtered with Where directly using a new IsValidMethodForGeneration method that returns a boolean.
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 we're moving the diagnostics to be emitted by the analyzer, we can change these tests to not run the generator and only run the analyzer.
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.
Fixed in 7a1d4df. Changed Diagnostics.cs to use CSharpAnalyzerVerifier<LibraryImportDiagnosticsAnalyzer> instead of running the generator. Updated the analyzer verifier to ignore compiler diagnostics since without the generator, partial methods don't have implementations.
…null, remove helper method Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
…analyzer only Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
Description
Moves diagnostic generation from the
LibraryImportGeneratorsource generator to a newLibraryImportDiagnosticsAnalyzer, per Roslyn team recommendation.Changes:
LibraryImportDiagnosticsAnalyzer.cswith infrastructure to run diagnostic logicSymbolEqualityComparerto compare attribute types instead of string matchingProcessLibraryImportAttributereturns null (invalid compilation)CSharpSourceGeneratorVerifierto accept aTAnalyzertype parameter for specifying which analyzer to run alongside a generatorLibraryImportGenerator:DiagnosticOrusage from the pipelineIsValidMethodForGenerationmethod that returns a boolean for filteringWheredirectly before entering the pipelineCSharpAnalyzerVerifierinstead ofCSharpSourceGeneratorVerifier:CSharpAnalyzerVerifier.Testto ignore compiler diagnostics since partial methods won't have implementations without the generatorLibraryImportDiagnosticsAnalyzerEmptyDiagnosticAnalyzerfrom Microsoft.CodeAnalysis.Testing as a placeholderCurrent state: 672/703 tests pass (95%). The analyzer reports most diagnostics but doesn't yet handle all edge cases that the generator previously handled (e.g.,
InvalidStringMarshallingConfigurationvalidation, some MarshalAs field validations).Next steps (future PRs):
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.