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
Implement analyzer for unused resources #6338
base: main
Are you sure you want to change the base?
Conversation
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## main #6338 +/- ##
==========================================
- Coverage 96.44% 96.43% -0.02%
==========================================
Files 1411 1412 +1
Lines 337272 337334 +62
Branches 11155 11163 +8
==========================================
+ Hits 325289 325294 +5
- Misses 9179 9235 +56
- Partials 2804 2805 +1 |
public override void Initialize(AnalysisContext context) | ||
{ | ||
context.EnableConcurrentExecution(); | ||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); |
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.
Why do we need to report diagnostics on generated code?
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.
@mavasani I report the diagnostic in the C# code that is generated from resx. The other way I can think of is reporting a diagnostic with Location.None, but I think it's clearer to have a location.
var resourceFileNames = context.Options.AdditionalFiles | ||
.Where(f => Path.GetExtension(f.Path).Equals(".resx", StringComparison.Ordinal)).Select(f => Path.GetFileNameWithoutExtension(f.Path)).ToImmutableHashSet(); | ||
|
||
var resourceTypes = context.Compilation.GetSymbolsWithName(n => resourceFileNames.Contains(n), SymbolFilter.Type, context.CancellationToken) |
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.
This seems to be quite expensive - we are basically force completing symbols in CompilationStartAction callback. I think a better approach would be to register a SymbolAction callback with SymbolKind.NamedType
, check in the callback if the named type is static type which is the generated class for a resx file and add them to a set of resx types. The IPropertyReferenceOperation
callback will also collect the set of used properties which are static properties within a static named type and are of type string
. The compilation end action can then analyze both these sets and report diagnostics.
I wouldn't classify these as false positives, though we may want to have an editorconfig option that bails out of resx analysis for projects that give IVT access to any assembly. IMO, if a project defines a resx that is not used within that project but used by a referencing project, then the developer should move the resx out of that project into a resx file in the referencing project. |
This seems like a good idea. I don't see any other better alternative for specifying suppressions. We may want to follow the standard pattern we use in our editorconfig options when we want to specify one or more symbol names in the option value, for example: https://github.com/dotnet/roslyn-analyzers/blob/main/docs/Analyzer%20Configuration.md#excluded-type-names-with-derived-types |
@Youssef1313 I understand the usefulness of this analyzer, but wanted to confirm if you opened an issue on dotnet/runtime to take this through triage. Even though the analyzer is not .NET API specific, I think it would be good to do so to ensure there are no surprises on their side when this analyzer gets added. |
CreateLocalizableResourceString(nameof(AvoidUnusedResourcesTitle)), | ||
CreateLocalizableResourceString(nameof(AvoidUnusedResourceMessage)), | ||
DiagnosticCategory.Maintainability, | ||
RuleLevel.Disabled, |
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 am wondering if we should have this as RuleLevel.Ide_Suggestion
instead of disabled by default. I understand that the rule will not report suggestion diagnostics by default as it is a compilation end analyzer, but having this as an Info diagnostic by default will mean that specifying any non-default value for AnalysisMode will bump this to a warning and start reporting unused resource warnings on command line builds. We can also implicitly pass in all .resx files in the project as additional files when AnalysisMode
or AnalysisLevel
properties end with minimum
, recommended
or all
similar to the below added to MS.CA.Analyzers package:
roslyn-analyzers/src/Tools/GenerateDocumentationAndConfigFiles/Program.cs
Lines 1601 to 1608 in 79cc002
CodeAnalysisAnalyzersPackageName => @" | |
<!-- Target to add all 'EmbeddedResource' files with '.resx' extension as analyzer additional files --> | |
<Target Name=""AddAllResxFilesAsAdditionalFiles"" BeforeTargets=""CoreCompile"" Condition=""'@(EmbeddedResource)' != '' AND '$(SkipAddAllResxFilesAsAdditionalFiles)' != 'true'""> | |
<ItemGroup> | |
<EmbeddedResourceWithResxExtension Include=""@(EmbeddedResource)"" Condition=""'%(Extension)' == '.resx'"" /> | |
<AdditionalFiles Include=""%(EmbeddedResourceWithResxExtension.Identity)"" /> | |
</ItemGroup> | |
</Target> |
Thanks for review @mavasani. I opened dotnet/runtime#79745 and will get back to the PR once dotnet/runtime team approves the analyzer. |
This was approved in dotnet/runtime#79765. |
@Youssef1313 Do you plan to continue working on this PR? |
I don't see the value of an option here. Resources can't be defined as |
8131b24
to
931bb8b
Compare
@mavasani Sure. I rebased and fixed the merge conflicts, updated Let me know what do you think of the current implementation. Then, I think the obvious remaining task is to add an MSBuild target to the package that adds resx files as AdditionalFiles. Maybe we also need to add AdditionalFiles to CompilerVisibleItemMetadata? Not sure. Sorry for leaving this for long. |
IPropertyReferenceOperation
isn't produced fornameof(Prop)
only in VB roslyn#65969.editorconfig
option to specify suppressions, e.g,dotnet_code_quality.ignore_unused_resources = MyResources.Resource1,MyResources2.Resource2