Skip to content

Conversation

CyrusNajmabadi
Copy link
Member

@CyrusNajmabadi CyrusNajmabadi commented Sep 8, 2025

Followup to #80176

These filters meant we had to instantiate DiagnosticAnalyzers on the host, and pass those in memory objects back to callers. This clearly breaks our goal of only loading DiagAnalyzers OOP.

This moves us to a pure-data api where callers don't pass callbacks, but instead a simple enum controlling what they want. And only on OOP do we manipulate the DiagnosticAnalyzers.

@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner September 8, 2025 15:05
@CyrusNajmabadi CyrusNajmabadi marked this pull request as draft September 8, 2025 15:06
@CyrusNajmabadi CyrusNajmabadi marked this pull request as ready for review September 8, 2025 23:26
@@ -1060,7 +1060,7 @@ await VerifyCachedDiagnosticsAsync(
: root.DescendantNodes().OfType<CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax>().First().Span;

await analyzerService.GetDiagnosticsForIdsAsync(
sourceDocument.Project, [sourceDocument.Id], diagnosticIds: null, shouldIncludeAnalyzer: null,
sourceDocument.Project, [sourceDocument.Id], diagnosticIds: null, AnalyzerFilter.All,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

callback replaced with pure-data enum. 'null' means 'include everything'.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filter appears to be required and never nullable, or did I miss something

/// <param name="additionalFilter">An additional filter that can accept or reject analyzers that the default
/// rules have accepted.</param>
Func<DiagnosticAnalyzer, bool> GetDefaultAnalyzerFilter(
Project project, ImmutableHashSet<string>? diagnosticIds, Func<DiagnosticAnalyzer, bool>? additionalFilter = null);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filter callbacks removed from api, as ti requires processing by teh caller (which is on the VS side, not the OOP side).


var analyzersForProject = GetProjectAnalyzers(project);
return analyzersForProject.WhereAsArray(shouldIncludeAnalyzer);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these apis still exist. but because they can now immediately ccall over to OOP, they move into teh _RemoteOrLocalDispatch.cs file.

@@ -22,84 +22,81 @@ public async ValueTask<ImmutableArray<DiagnosticData>> ForceRunCodeAnalysisDiagn
//
// As such, we are very intentionally not calling into this.GetDefaultAnalyzerFilter
// here. We want to control the rules entirely when this is called.
var filter = GetDiagnosticAnalyzerFilter(project, _analyzerInfoCache);
var analyzers = GetProjectAnalyzers(project);
var filteredAnalyzers = analyzers.WhereAsArray(ShouldIncludeAnalyzer);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note, we are in an InProcessAsync method, so it's ok to call GetProjectAnalyzers and do this in-memory processing.

if (analyzer == FileContentLoadAnalyzer.Instance ||
analyzer == GeneratorDiagnosticsPlaceholderAnalyzer.Instance ||
analyzer.IsCompilerAnalyzer())
{
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a move.

}

static Func<DiagnosticAnalyzer, bool> GetDiagnosticAnalyzerFilter(
Project project, DiagnosticAnalyzerInfoCache infoCache)
bool ShouldIncludeAnalyzer(DiagnosticAnalyzer analyzer)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for callback form. we can just immediately filter the array.

{
if ((analyzerFilter & AnalyzerFilter.NonCompilerAnalyzer) == 0)
return false;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's below is the standard filtering logic from before. what's above is new.

internal async Task<ImmutableArray<DiagnosticData>> ProduceProjectDiagnosticsAsync(
public async Task<ImmutableArray<DiagnosticData>> GetDiagnosticsForIdsAsync(
Project project, ImmutableArray<DocumentId> documentIds, ImmutableHashSet<string>? diagnosticIds, AnalyzerFilter analyzerFilter, bool includeLocalDocumentDiagnostics, CancellationToken cancellationToken)
{
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this moved from original file to this dispatch file. Then it calls to the actual in proc impl at the bottom.

Copy link
Member Author

@CyrusNajmabadi CyrusNajmabadi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment

@@ -1060,7 +1060,7 @@ await VerifyCachedDiagnosticsAsync(
: root.DescendantNodes().OfType<CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax>().First().Span;

await analyzerService.GetDiagnosticsForIdsAsync(
sourceDocument.Project, [sourceDocument.Id], diagnosticIds: null, shouldIncludeAnalyzer: null,
sourceDocument.Project, [sourceDocument.Id], diagnosticIds: null, AnalyzerFilter.All,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filter appears to be required and never nullable, or did I miss something

@CyrusNajmabadi CyrusNajmabadi merged commit 161e4bf into dotnet:main Sep 9, 2025
24 of 25 checks passed
@CyrusNajmabadi CyrusNajmabadi deleted the diagnosticFilters branch September 9, 2025 10:10
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Sep 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants