Remove CompilationPair abstraction in diagnostic analyzer subsystem#80141
Conversation
|
|
||
| namespace A | ||
| { | ||
| using System; |
There was a problem hiding this comment.
this is the correct behavior. The test here is testing " 'usings' should be INSIDE the namespace, and it is an ERROR otherwise". So it was a bug this wasn't moving in in CodeCleanup.
Note: this differs from teh tests taht validate that nothing change when the option suggestions the change, but the severity is set to 'hidden'. in that case we do not make any change.
There was a problem hiding this comment.
Do you have a sense why this changed? (I agree the behavior looks right, but this means we had a bug somewhere...)
There was a problem hiding this comment.
When i was debugging through, teh wrong options were coming through, and it meant that the default severity was getting pulled in (which is 'hidden'). Because of this, the codecleanup layer doesn't actually want to make a change due to 'hidden' effectively being equivalent to 'the user didn't actually set anything themselves'.
|
Draft until API is reviewed and approved. |
| { | ||
| // No specific options factory. Can use the shared context. | ||
| if (_analyzerToCachedOptions is null) | ||
| return context; |
There was a problem hiding this comment.
note: this is the common case for those not referencing hte roslyn sdk. So there should be almost no overhead in that common case.
| internal SymbolAnalysisContext WithOptions(AnalyzerOptions options) | ||
| => this.Options == options | ||
| ? this | ||
| : new(this.Symbol, this.Compilation, options, _reportDiagnostic, _isSupportedDiagnostic, this.IsGeneratedCode, this.FilterTree, this.FilterSpan, this.CancellationToken); |
There was a problem hiding this comment.
note: these context types are structs. So this is not actually allocating a new instance on the heap. Just returning a tweaked version with the right options to pass along.
| /// from the shared instance provided in <see cref="Options"/>. If <see langword="null"/> then <see cref="Options"/> | ||
| /// will be used for all analyzers. | ||
| /// </summary> | ||
| public Func<DiagnosticAnalyzer, AnalyzerOptions>? AnalyzerSpecificOptionsFactory |
There was a problem hiding this comment.
note: this prop doesn't need to be public (though that matches the reest here). The API review covers if we should expose this (since it was a constructor param) or if we should keep it internally since we hvve no actual public consumers.
| bool logAnalyzerExecutionTime, | ||
| bool reportSuppressedDiagnostics, | ||
| Func<Exception, bool>? analyzerExceptionFilter, | ||
| Func<DiagnosticAnalyzer, AnalyzerOptions>? analyzerSpecificOptionsFactory) |
There was a problem hiding this comment.
new public API that needs API review.
| analyzerExceptionFilter: exceptionFilter, | ||
| analyzerSpecificOptionsFactory)); | ||
|
|
||
| (AnalyzerOptions sharedOptions, Func<DiagnosticAnalyzer, AnalyzerOptions>? analyzerSpecificOptionsFactory) GetOptions() |
There was a problem hiding this comment.
this is hte meat of the change on the IDE side.
src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzersOptions.cs
Outdated
Show resolved
Hide resolved
.../Core/Portable/Diagnostics/Service/DiagnosticAnalyzerService_CompilationWithAnalyzersPair.cs
Outdated
Show resolved
Hide resolved
| var map = new Dictionary<DiagnosticAnalyzer, AnalyzerOptions>(ReferenceEqualityComparer.Instance); | ||
|
|
||
| // Deduping map for the distinct AnalyzerConfigOptionsProvider we get back from analyzerSpecificOptionsFactory | ||
| var optionsProviderToOptions = new Dictionary<AnalyzerConfigOptionsProvider, AnalyzerOptions>(ReferenceEqualityComparer.Instance); |
There was a problem hiding this comment.
note: this deduping is tested. we make sure that if two analyzers return the same AnalyzerConfigOptionsProvider that they will then get passed the exact same AnalyzerOptions instance in callbacks.
|
API change was approved. @jasonmalinowski @dotnet/roslyn-compiler for eyes. |
| diagnostics.Verify(Diagnostic("ID0001", "B").WithLocation(1, 8)); | ||
| } | ||
|
|
||
| private sealed class OptionsOverrideDiagnosticAnalyzer(AnalyzerConfigOptionsProvider customOptions) : DiagnosticAnalyzer |
There was a problem hiding this comment.
these tests validate that we see the different options through all the callbacks.
| Microsoft.CodeAnalysis.CommandLineResource.LinkedResourceFileName.get -> string? | ||
| Microsoft.CodeAnalysis.CommandLineResource.ResourceName.get -> string! | ||
| Microsoft.CodeAnalysis.Compilation.EmitDifference(Microsoft.CodeAnalysis.Emit.EmitBaseline! baseline, System.Collections.Generic.IEnumerable<Microsoft.CodeAnalysis.Emit.SemanticEdit>! edits, System.Func<Microsoft.CodeAnalysis.ISymbol!, bool>! isAddedSymbol, System.IO.Stream! metadataStream, System.IO.Stream! ilStream, System.IO.Stream! pdbStream, Microsoft.CodeAnalysis.Emit.EmitDifferenceOptions options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.Emit.EmitDifferenceResult! | ||
| Microsoft.CodeAnalysis.Diagnostics.CompilationWithAnalyzersOptions.CompilationWithAnalyzersOptions(Microsoft.CodeAnalysis.Diagnostics.AnalyzerOptions? options, System.Action<System.Exception!, Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer!, Microsoft.CodeAnalysis.Diagnostic!>? onAnalyzerException, bool concurrentAnalysis, bool logAnalyzerExecutionTime, bool reportSuppressedDiagnostics, System.Func<System.Exception!, bool>? analyzerExceptionFilter, System.Func<Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer!, Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptionsProvider!>? getAnalyzerConfigOptionsProvider) -> void |
There was a problem hiding this comment.
only public change is this one constructor.
src/Tools/SemanticSearch/ReferenceAssemblies/Apis/Microsoft.CodeAnalysis.txt
Outdated
Show resolved
Hide resolved
.../Core/Portable/Diagnostics/Service/DiagnosticAnalyzerService_CompilationWithAnalyzersPair.cs
Show resolved
Hide resolved
There was a problem hiding this comment.
I assume you'll be renaming the file as a follow-up.
There was a problem hiding this comment.
Yup. I'm even working on making the "make filename match type" fixer able to fix-all. So i can do these in bulk.
.../Core/Portable/Diagnostics/Service/DiagnosticAnalyzerService_CompilationWithAnalyzersPair.cs
Outdated
Show resolved
Hide resolved
.../Core/Portable/Diagnostics/Service/DiagnosticAnalyzerService_CompilationWithAnalyzersPair.cs
Outdated
Show resolved
Hide resolved
.../Core/Portable/Diagnostics/Service/DiagnosticAnalyzerService_CompilationWithAnalyzersPair.cs
Show resolved
Hide resolved
src/Features/Core/Portable/Diagnostics/Service/DocumentAnalysisExecutor.cs
Outdated
Show resolved
Hide resolved
| CancellationToken cancellationToken) | ||
| { | ||
| var hostAnalyzers = documentAnalysisScope?.HostAnalyzers ?? compilationWithAnalyzers.HostAnalyzers; | ||
| var hostAnalyzers = documentAnalysisScope?.Analyzers ?? compilationWithAnalyzers.Analyzers; |
There was a problem hiding this comment.
Not sure if local needs a rename, because it's suspicious it was 'hostAnalyzers' before?
There was a problem hiding this comment.
will do. i agree it's suspicious. can you think of a reason we'd only be using hostanalyzers for suppression analyzers? @mavasani do you perhaps knows?
i'm tempted to leave this as is (with the rename). but if there's a sound reason for only using host analyzers, we could always filter these down to those.
Unfortunately, we don't have any tests indicating if this is intentional or errant.
|
|
||
| namespace A | ||
| { | ||
| using System; |
There was a problem hiding this comment.
Do you have a sense why this changed? (I agree the behavior looks right, but this means we had a bug somewhere...)
…zerService_CompilationWithAnalyzersPair.cs Co-authored-by: Jason Malinowski <jason@jason-m.com>
…yrusNajmabadi/roslyn into noCompilationPairWithApiChange
src/Features/Core/Portable/Diagnostics/Service/DocumentAnalysisExecutor.cs
Outdated
Show resolved
Hide resolved
| RoslynDebug.Assert(AnalysisScope.TextDocument is Document); | ||
| Contract.ThrowIfFalse(analyzer.IsCompilerAnalyzer()); | ||
| Contract.ThrowIfNull(_compilationWithAnalyzers); | ||
| Contract.ThrowIfFalse(_compilationBasedAnalyzersInAnalysisScope.Contains(analyzer)); |
There was a problem hiding this comment.
we even already had this assert here. so it massively simplifies the code below.
jasonmalinowski
left a comment
There was a problem hiding this comment.
I sign off; obviously that question is still pending but I'm not sure I can figure that one out...
| filteredHostAnalyzers = filteredHostAnalyzers.AddRange(filteredProjectSuppressors); | ||
| // Ensure we filter out DocumentDiagnosticAnalyzers (they're used to get diagnostics, without involving a | ||
| // compilation), and also ensure the list has no duplicates. | ||
| analyzers = analyzers.WhereAsArray(static a => !a.IsWorkspaceDiagnosticAnalyzer()).Distinct(); |
Followup to #80200
API change request is here: #80143
Build: https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=12380432&view=results
PR: https://dev.azure.com/devdiv/DevDiv/_git/VS/pullrequest/670048