-
Notifications
You must be signed in to change notification settings - Fork 465
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
Add missing [Generator] attribute analyzer and code fix #5235
Add missing [Generator] attribute analyzer and code fix #5235
Conversation
src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx
Outdated
Show resolved
Hide resolved
...soft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/Fixers/SourceGeneratorAttributeAnalyzerFix.cs
Outdated
Show resolved
Hide resolved
{ | ||
var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); | ||
var generator = editor.Generator; | ||
var generatorAttribute = generator.Attribute(WellKnownTypeNames.MicrosoftCodeAnalysisGeneratorAttribute); |
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.
Note: The parameterless attribute constructor makes the generator C#-only. I'd instead make the codefix add both languages, and let the user delete an extra language if needed.
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.
I'm not actually sure if that's enforced. I didn't find anywhere it was referenced in roslyn. @chsienki might know more.
I don't think we want to add both, I doubt that's correct in most cases. If anything, maybe use the document language
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.
Ah nm, it's used indirectly https://sourceroslyn.io/#Microsoft.CodeAnalysis/DiagnosticAnalyzer/AnalyzerFileReference.cs,60
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.
@ryzngard Using the document language isn't ideal IMO. The source generator may be meant for usage for both languages, while being written in C#. Since the attribute application doesn't explicitly specify a language version, this could be hard to catch for developers.
There are few options I can come up with:
- Offer 3 codefixes (C# - VB - Both)
- Heuristic 1:
- Look at the namespaces referenced in
using
statements if they are contain C#-specific, VB-specific, or both. In case there are none, I'd fall back to "both" and let the developer adjust the attribute.
- Look at the namespaces referenced in
- Heuristic 2:
- Look at the type name if it contains "CSharp" or "VB" (or "VisualBasic"), and fall back to both languages
- Heuristic 3:
- Combines both above.
Simplest is probably the first option to offer 3 codefixes.
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.
I think for now it will be fine to leave it with the default value. Ultimately a C# generator targeting a C# only project is the most likely scenario. We could put the lang parameter in and default it to C# as a hint that you can change it if people feel strongly (or as @ryzngard said, use the document language), but this feels like we're probably just over engineering something that we can address down the line if we get customer feedback about it.
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.
While true, I think that's overengineering for the problem space right now. We also don't catch cases where the user puts the wrong language with the analyzer... we just don't know. During compilation I'm sure the generator will fail if the attribute is configured incorrectly. Hopefully whatever error happens is enough to help the author figure out next steps. Having the code fix as is does exactly what the analyzer catches, no more and no less. Having some hard to follow heuristics is unwarranted until we have a stronger user opinion on the matter.
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 should use the approach from ApplyDiagnosticAnalyzerAttributeFix
for consistency.
src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/SourceGeneratorAttributeAnalyzer.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/SourceGeneratorAttributeAnalyzer.cs
Outdated
Show resolved
Hide resolved
...crosoft.CodeAnalysis.Analyzers/UnitTests/MetaAnalyzers/MissingGeneratorAttributeRuleTests.cs
Outdated
Show resolved
Hide resolved
...crosoft.CodeAnalysis.Analyzers/UnitTests/MetaAnalyzers/MissingGeneratorAttributeRuleTests.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/SourceGeneratorAttributeAnalyzer.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx
Outdated
Show resolved
Hide resolved
src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/SourceGeneratorAttributeAnalyzer.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/SourceGeneratorAttributeAnalyzer.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/SourceGeneratorAttributeAnalyzer.cs
Outdated
Show resolved
Hide resolved
...crosoft.CodeAnalysis.Analyzers/UnitTests/MetaAnalyzers/MissingGeneratorAttributeRuleTests.cs
Outdated
Show resolved
Hide resolved
...crosoft.CodeAnalysis.Analyzers/UnitTests/MetaAnalyzers/MissingGeneratorAttributeRuleTests.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx
Outdated
Show resolved
Hide resolved
src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx
Outdated
Show resolved
Hide resolved
src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx
Outdated
Show resolved
Hide resolved
...soft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/Fixers/SourceGeneratorAttributeAnalyzerFix.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/SourceGeneratorAttributeAnalyzer.cs
Outdated
Show resolved
Hide resolved
return; | ||
} | ||
|
||
if (!symbol.AllInterfaces.Any(i => sourceGenerator.Equals(i, SymbolEqualityComparer.Default))) |
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.
I don't recall the name but I think there is an helper function for this that reads better.
src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/SourceGeneratorAttributeAnalyzer.cs
Outdated
Show resolved
Hide resolved
...soft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/Fixers/SourceGeneratorAttributeAnalyzerFix.cs
Outdated
Show resolved
Hide resolved
...soft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/Fixers/SourceGeneratorAttributeAnalyzerFix.cs
Outdated
Show resolved
Hide resolved
…/SourceGeneratorAttributeAnalyzerFix.cs Co-authored-by: Youssef Victor <[email protected]>
...soft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/Fixers/SourceGeneratorAttributeAnalyzerFix.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/SourceGeneratorAttributeAnalyzer.cs
Outdated
Show resolved
Hide resolved
var language = languageNames[i] == LanguageNames.CSharp | ||
? nameof(LanguageNames.CSharp) | ||
: nameof(LanguageNames.VisualBasic); | ||
var language = languageNames[i]; | ||
|
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.
Sorry I think I was incorrect here. The constant value is "C#", it doesn't match the field constant name ("CSharp").
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 know, I trusted you Youssef. 😑
I'll get this tomorrow as well when it's not bedtime 😉
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.
Sorry again.
Actually, even the UICulture suggestion is failing CI (I don't quite understand why). But the failure is for the good this time. If it's wrong to use UICulture for string.Format
, then this should get updated and the analyzer should be enabled in roslyn:
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.
I was just jesting, it's easy to make that mistake. I often forget that "C#" is what the string is.
As for UICulture, I'll look into that. I would expect it to be correct, but it's possible not formatting for culture at all is more correct in these cases.
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.
src\Microsoft.CodeAnalysis.Analyzers\Core\MetaAnalyzers\Fixers\SourceGeneratorAttributeAnalyzerFix.cs(38,21): error CA1305: (NETCORE_ENGINEERING_TELEMETRY=Build) The behavior of 'string.Format(string, object)' could vary based on the current user's locale settings. Replace this call in 'SourceGeneratorAttributeAnalyzerFix.RegisterCodeFixesAsync(CodeFixContext)' with a call to 'string.Format(IFormatProvider, string, params object[])'
Here it is... This seems to be disabled during build in VS though. @sharwell is the correct thing to do is pass CurrentCulture
here?
Going through my old PRs. Apologies for dropping this on the floor :( PTAL if you get a moment. |
src/Microsoft.CodeAnalysis.Analyzers/Core/AnalyzerReleases.Unshipped.md
Outdated
Show resolved
Hide resolved
...soft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/Fixers/SourceGeneratorAttributeAnalyzerFix.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx
Outdated
Show resolved
Hide resolved
src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx
Outdated
Show resolved
Hide resolved
<data name="MissingSourceGeneratorAttributeTitle" xml:space="preserve"> | ||
<value>Missing 'Generator' Attribute</value> | ||
</data> | ||
<data name="AddGeneratorAttribute_1" xml:space="preserve"> |
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 are not really consistent for naming of the code fix titles but I would avoid _X
.
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.
What is the way to distinguish between this and AddGeneratorAttribute_2
?
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.
Maybe _OneLanguage
and _TwoLanguages
? Otherwise you could use the naming style from Roslyn here.
src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/SourceGeneratorAttributeAnalyzer.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.CodeAnalysis.Analyzers/Microsoft.CodeAnalysis.Analyzers.md
Outdated
Show resolved
Hide resolved
...soft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/Fixers/SourceGeneratorAttributeAnalyzerFix.cs
Outdated
Show resolved
Hide resolved
...soft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/Fixers/SourceGeneratorAttributeAnalyzerFix.cs
Outdated
Show resolved
Hide resolved
….com/ryzngard/roslyn-analyzers into features/missing_generator_attribute
Co-authored-by: Youssef Victor <[email protected]>
….com/ryzngard/roslyn-analyzers into features/missing_generator_attribute
Codecov Report
@@ Coverage Diff @@
## main #5235 +/- ##
========================================
Coverage 95.58% 95.58%
========================================
Files 1284 1287 +3
Lines 296834 297314 +480
Branches 18101 18122 +21
========================================
+ Hits 283725 284191 +466
- Misses 10670 10678 +8
- Partials 2439 2445 +6 |
{ | ||
// CSharp is the only language, which is the default paramterless | ||
// constructor for the Generator attribute | ||
generatorAttribute = generator.Attribute(WellKnownTypeNames.MicrosoftCodeAnalysisGeneratorAttribute).WithAddImportsAnnotation(); |
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.
Looks like imports annotation isn't working as I was expecting (TestSimpleClass_FullyQualified_CSharp
should have failed).
I think Roslyn can improve this by assuming the annotation is meant to any descendant nodes, but for now we can generate the type syntax ourselves and pass it to generator.Attribute
similar to
Lines 86 to 91 in c314521
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); | |
var obsoleteAttributeSymbol = semanticModel.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemObsoleteAttribute); | |
if (obsoleteAttributeSymbol is null) | |
{ | |
return document; | |
} |
Lines 103 to 104 in c314521
var obsoleteAttribute = generator.Attribute( | |
generator.TypeExpression(obsoleteAttributeSymbol).WithAddImportsAnnotation(), |
Feel free if you don't want to make it in this PR.
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.
I think we need to extend this to IIncrementalGenerator
Closing old PR. This could be used for anyone moving forward to implement this |
Fixes #5050
Adds an analyzer and code fix to ensure that types that implement
ISourceGenerator
also have the[Generator]
attribute. Works in both C# and Visual Basic.