-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Remove analyzer cache from public surface area #79808
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
Conversation
| if (x is null || y is null) | ||
| return false; | ||
|
|
||
| return x.GetAnalyzerIdAndVersion().GetHashCode() == y.GetAnalyzerIdAndVersion().GetHashCode(); |
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.
aside: taht this is using HashCodes to determine equality is suppppper sus.
| private ImmutableArray<AnalyzerSetting> GetSettings( | ||
| Solution solution, AnalyzerReference analyzerReference, AnalyzerConfigOptions editorConfigOptions) | ||
| { | ||
| IEnumerable<DiagnosticAnalyzer> csharpAnalyzers = analyzerReference.GetAnalyzers(LanguageNames.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.
instead of realiing DiagAnalyzers here,e it gets moved into the IDiagService, which can then be the one stop shop for asking these questions in a general fashion. IN the future, IDiagService can then forward thse calls to OOP to do the actual work.
src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs
Outdated
Show resolved
Hide resolved
…yzer/AnalyzerSettingsProvider.cs
…/roslyn into hideAnalyzerCache
| // DiagnosticAnalyzerInfoCache AnalyzerInfoCache { get; } | ||
|
|
||
| ImmutableArray<DiagnosticDescriptor> GetDiagnosticDescriptors( | ||
| Solution solution, AnalyzerReference analyzerReference, string 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.
the IDiagService now gets data-oriented apis that were previous based on DiagAnalyzer and exposed off of DiagnosticAnalyzerInfoCache . This will allow these to, in the future, call over to oop.
Note: they will need to be made async first.
| if (x is null || y is null) | ||
| return false; | ||
|
|
||
| return x.GetAnalyzerIdAndVersion().GetHashCode() == y.GetAnalyzerIdAndVersion().GetHashCode(); |
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 it passes, i'm changing this equality to not use GetHashCode.
| GetDiagnosticSeverity(error), | ||
| _language, | ||
| new FileLinePositionSpan(project.FilePath ?? "", span: default), | ||
| AnalyzerInfoCache)); |
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 code used to directly access this cache. now, we just call into IDiagService up front to get the info we used to try to get inside GetDiagnosticData
| ImmutableArray<string> customTags; | ||
|
|
||
| if (analyzerInfoCache != null && analyzerInfoCache.TryGetDescriptorForDiagnosticId(errorId, out var descriptor)) | ||
| if (errorIdToDescriptor.TryGetValue(errorId, out var descriptor)) |
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.
all this was previously trying to do was map from errorid to a DiagDescriptor. so i made an api to do that (in bulk) so this can work in oop as well.
|
|
||
| ImmutableArray<DiagnosticDescriptor> GetDiagnosticDescriptors(ImmutableArray<DiagnosticAnalyzer> analyzers) | ||
| => analyzers.SelectManyAsArray(this._analyzerInfoCache.GetDiagnosticDescriptors); | ||
| } |
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.
all the acutal logic was moved here from the consuming client code on the outside.
|
@jasonmalinowski this is ready for review. |
| IEnumerable<DiagnosticAnalyzer> visualBasicAnalyzers = analyzerReference.GetAnalyzers(LanguageNames.VisualBasic); | ||
| var dotnetAnalyzers = csharpAnalyzers.Intersect(visualBasicAnalyzers, DiagnosticAnalyzerComparer.Instance); | ||
| csharpAnalyzers = csharpAnalyzers.Except(dotnetAnalyzers, DiagnosticAnalyzerComparer.Instance); | ||
| visualBasicAnalyzers = visualBasicAnalyzers.Except(dotnetAnalyzers, DiagnosticAnalyzerComparer.Instance); |
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 logic moved into DiagAnalService
|
|
||
| var descriptors = analyzerReference | ||
| .GetAnalyzers(project.Language) | ||
| .SelectManyAsArray(a => diagnosticAnalyzerService.AnalyzerInfoCache.GetDiagnosticDescriptors(a)); |
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 logic moved into DiagAnalService
|
@jasonmalinowski ptal. |
|
@jasonmalinowski Also, if the feedback is non-critical, let me know and ideally make non-blocking. There are multiple followup PRs, so it would be nicer to just roll the feedback into those. |
| csharpAnalyzers = csharpAnalyzers.Except(dotnetAnalyzers, DiagnosticAnalyzerComparer.Instance); | ||
| visualBasicAnalyzers = visualBasicAnalyzers.Except(dotnetAnalyzers, DiagnosticAnalyzerComparer.Instance); | ||
| var service = solution.Services.GetRequiredService<IDiagnosticAnalyzerService>(); | ||
| var map = service.GetDiagnosticDescriptors(solution, analyzerReference); |
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.
general pattern is takign the code that actually operates on DiagAnalyzers and push that into the IDiagnosticAnalyzerService impl. Then the code that processes the computed data stays at the feature level.
jasonmalinowski
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.
This all looks good except for the race being introduced into the external error reporting. Now that we're processing stuff asynchronously and adding it after the call, it would mean a later call to the Clear() methods won't clear them, and worse they might live around once they complete later.
I think a quick use of CancellationTokenSeries should fix up the issue though.
| internal interface IDiagnosticAnalyzerService : IWorkspaceService | ||
| { | ||
| ImmutableArray<DiagnosticDescriptor> GetDiagnosticDescriptors( | ||
| Solution solution, AnalyzerReference analyzerReference, string 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.
Should this be taking a Project rather than Solution + language 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.
actually no. this is called from clients who take the same AnalyzerRef (which might be in multiple projects) and try to get both the C# and VB descriptors. Those could pass projects, but it would take more effort on that side to keep track of the originating project. so i didn't do that for now.
|
|
||
| return allSettings.ToImmutableAndClear(); | ||
|
|
||
| Language ConvertToLanguage(ImmutableArray<string> languages) |
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.
Can we do static extension methods on the enum? (OK to not actually do this -- this code might be going away soon enough)
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 can. but i also don't mind this just being local here as it is the only place needed.
| /// Returns all the descriptors for all <see cref="DiagnosticAnalyzer"/>s defined within <paramref name="analyzerReference"/>. | ||
| /// The results are returned in a dictionary where the key is an <see cref="ImmutableArray{T}"/> of languages that descriptor | ||
| /// is defined for. This can be <c>[<see cref="LanguageNames.CSharp"/>]</c>, <c>[<see cref="LanguageNames.VisualBasic"/>]</c>, | ||
| /// or an array containing both languages if the descriptor is defined for both languages. |
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 the .editorconfig editor was the only thing that needed this crazy form, I'm content to say maybe we just tweak it to use this other form. I appreciate the comment but it's still a bit mind-bending!
If we do need to keep it around, maybe switching it to be a DiagnosticDescriptor -> array of languages it applies to) might make it clearer.
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 ok doing that later :)
my goals here were: get this OOPable, without changing semantics :)
i def thing later cleanup is a good idea.
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.
Agreed fully.
| public ImmutableDictionary<string, ImmutableArray<DiagnosticDescriptor>> GetDiagnosticDescriptorsPerReference(Project project) | ||
| => project.Solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(this._analyzerInfoCache, project); | ||
|
|
||
| private sealed class DiagnosticAnalyzerComparer : IEqualityComparer<DiagnosticAnalyzer> |
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.
Did you get any sense why this was being done this way versus just object identity?
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.
yeah. the more i think about it, the more this seems like nonsense.
src/VisualStudio/Core/Def/TaskList/ProjectExternalErrorReporter.cs
Outdated
Show resolved
Hide resolved
src/VisualStudio/Core/Def/TaskList/ProjectExternalErrorReporter.cs
Outdated
Show resolved
Hide resolved
…r.cs Co-authored-by: Jason Malinowski <jason@jason-m.com>
…/roslyn into hideAnalyzerCache
Followup to #79802.