diff --git a/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs
index 990d405cd3d4d..efeaa71523050 100644
--- a/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs
+++ b/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs
@@ -22,9 +22,7 @@ internal interface IDiagnosticAnalyzerService : IWorkspaceService
///
void RequestDiagnosticRefresh();
- ///
- /// Force analyzes the given project by running all applicable analyzers on the project.
- ///
+ ///
Task> ForceAnalyzeProjectAsync(Project project, CancellationToken cancellationToken);
///
diff --git a/src/Features/Core/Portable/Diagnostics/Service/DiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/Service/DiagnosticAnalyzerService.cs
index 69624bb5d1e44..221d23597afde 100644
--- a/src/Features/Core/Portable/Diagnostics/Service/DiagnosticAnalyzerService.cs
+++ b/src/Features/Core/Portable/Diagnostics/Service/DiagnosticAnalyzerService.cs
@@ -58,6 +58,7 @@ internal sealed partial class DiagnosticAnalyzerService : IDiagnosticAnalyzerSer
private readonly IDiagnosticsRefresher _diagnosticsRefresher;
private readonly DiagnosticIncrementalAnalyzer _incrementalAnalyzer;
private readonly DiagnosticAnalyzerInfoCache _analyzerInfoCache;
+ private readonly StateManager _stateManager;
public DiagnosticAnalyzerService(
IGlobalOptionService globalOptions,
@@ -71,6 +72,7 @@ public DiagnosticAnalyzerService(
GlobalOptions = globalOptions;
_diagnosticsRefresher = diagnosticsRefresher;
_incrementalAnalyzer = new DiagnosticIncrementalAnalyzer(this, _analyzerInfoCache, this.GlobalOptions);
+ _stateManager = new StateManager(_analyzerInfoCache);
globalOptions.AddOptionChangedHandler(this, (_, _, e) =>
{
@@ -122,8 +124,22 @@ public async Task> GetDiagnosticsForSpanAsync(
document, range, shouldIncludeDiagnostic, priorityProvider, diagnosticKinds, cancellationToken).ConfigureAwait(false);
}
- public Task> ForceAnalyzeProjectAsync(Project project, CancellationToken cancellationToken)
- => _incrementalAnalyzer.ForceAnalyzeProjectAsync(project, cancellationToken);
+ public async Task> ForceAnalyzeProjectAsync(Project project, CancellationToken cancellationToken)
+ {
+ var client = await RemoteHostClient.TryGetClientAsync(project, cancellationToken).ConfigureAwait(false);
+ if (client is not null)
+ {
+ var result = await client.TryInvokeAsync>(
+ project,
+ (service, solution, cancellationToken) => service.ForceAnalyzeProjectAsync(solution, project.Id, cancellationToken),
+ cancellationToken).ConfigureAwait(false);
+
+ return result.HasValue ? result.Value : [];
+ }
+
+ // No OOP connection. Compute in proc.
+ return await _incrementalAnalyzer.ForceAnalyzeProjectAsync(project, cancellationToken).ConfigureAwait(false);
+ }
public Task> GetDiagnosticsForIdsAsync(
Project project, DocumentId? documentId, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken)
diff --git a/src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.HostAnalyzerInfo.cs b/src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.HostAnalyzerInfo.cs
index beb57d39e625b..2c7481fe353d9 100644
--- a/src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.HostAnalyzerInfo.cs
+++ b/src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.HostAnalyzerInfo.cs
@@ -2,95 +2,90 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.PooledObjects;
-using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Diagnostics;
internal sealed partial class DiagnosticAnalyzerService
{
- private sealed partial class DiagnosticIncrementalAnalyzer
+ private sealed partial class StateManager
{
- private sealed partial class StateManager
+ private HostAnalyzerInfo GetOrCreateHostAnalyzerInfo(
+ SolutionState solution, ProjectState project, ProjectAnalyzerInfo projectAnalyzerInfo)
{
- private HostAnalyzerInfo GetOrCreateHostAnalyzerInfo(
- SolutionState solution, ProjectState project, ProjectAnalyzerInfo projectAnalyzerInfo)
+ var key = new HostAnalyzerInfoKey(project.Language, project.HasSdkCodeStyleAnalyzers, solution.Analyzers.HostAnalyzerReferences);
+ // Some Host Analyzers may need to be treated as Project Analyzers so that they do not have access to the
+ // Host fallback options. These ids will be used when building up the Host and Project analyzer collections.
+ var referenceIdsToRedirect = GetReferenceIdsToRedirectAsProjectAnalyzers(solution, project);
+ var hostAnalyzerInfo = ImmutableInterlocked.GetOrAdd(ref _hostAnalyzerStateMap, key, CreateLanguageSpecificAnalyzerMap, (solution.Analyzers, referenceIdsToRedirect));
+ return hostAnalyzerInfo.WithExcludedAnalyzers(projectAnalyzerInfo.SkippedAnalyzersInfo.SkippedAnalyzers);
+
+ static HostAnalyzerInfo CreateLanguageSpecificAnalyzerMap(HostAnalyzerInfoKey arg, (HostDiagnosticAnalyzers HostAnalyzers, ImmutableHashSet