diff --git a/eng/targets/Services.props b/eng/targets/Services.props
index 590cd0c2a1518..54114e7e60223 100644
--- a/eng/targets/Services.props
+++ b/eng/targets/Services.props
@@ -16,6 +16,7 @@
+
diff --git a/src/EditorFeatures/CSharp/CodeCleanup/CSharpCodeCleanupService.cs b/src/EditorFeatures/CSharp/CodeCleanup/CSharpCodeCleanupService.cs
index f00c77eb4d622..09e04eb4ca899 100644
--- a/src/EditorFeatures/CSharp/CodeCleanup/CSharpCodeCleanupService.cs
+++ b/src/EditorFeatures/CSharp/CodeCleanup/CSharpCodeCleanupService.cs
@@ -16,7 +16,8 @@ namespace Microsoft.CodeAnalysis.CSharp.CodeCleanup;
[ExportLanguageService(typeof(ICodeCleanupService), LanguageNames.CSharp), Shared]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
-internal class CSharpCodeCleanupService(ICodeFixService codeFixService, IDiagnosticAnalyzerService diagnosticAnalyzerService) : AbstractCodeCleanupService(codeFixService, diagnosticAnalyzerService)
+internal sealed class CSharpCodeCleanupService(ICodeFixService codeFixService)
+ : AbstractCodeCleanupService(codeFixService)
{
///
/// Maps format document code cleanup options to DiagnosticId[]
diff --git a/src/EditorFeatures/Core.Wpf/Copilot/CopilotWpfTextCreationListener.cs b/src/EditorFeatures/Core.Wpf/Copilot/CopilotWpfTextCreationListener.cs
new file mode 100644
index 0000000000000..8bdb1bfaf16db
--- /dev/null
+++ b/src/EditorFeatures/Core.Wpf/Copilot/CopilotWpfTextCreationListener.cs
@@ -0,0 +1,127 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// 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.ComponentModel.Composition;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Collections;
+using Microsoft.CodeAnalysis.Editor;
+using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
+using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
+using Microsoft.CodeAnalysis.Host.Mef;
+using Microsoft.CodeAnalysis.Options;
+using Microsoft.CodeAnalysis.Shared.TestHooks;
+using Microsoft.CodeAnalysis.Text;
+using Microsoft.CodeAnalysis.Threading;
+using Microsoft.VisualStudio.Language.Proposals;
+using Microsoft.VisualStudio.Language.Suggestions;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Utilities;
+
+namespace Microsoft.CodeAnalysis.Copilot;
+
+[Export(typeof(IWpfTextViewCreationListener))]
+[ContentType(ContentTypeNames.RoslynContentType)]
+[TextViewRole(PredefinedTextViewRoles.Document)]
+internal sealed class CopilotWpfTextViewCreationListener : IWpfTextViewCreationListener
+{
+ private readonly IGlobalOptionService _globalOptions;
+ private readonly IThreadingContext _threadingContext;
+ private readonly Lazy _suggestionServiceBase;
+ private readonly IAsynchronousOperationListener _listener;
+
+ private readonly AsyncBatchingWorkQueue<(bool accepted, ProposalBase proposal)> _completionWorkQueue;
+
+ private int _started;
+
+ [ImportingConstructor]
+ [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
+ public CopilotWpfTextViewCreationListener(
+ IGlobalOptionService globalOptions,
+ IThreadingContext threadingContext,
+ Lazy suggestionServiceBase,
+ IAsynchronousOperationListenerProvider listenerProvider)
+ {
+ _globalOptions = globalOptions;
+ _threadingContext = threadingContext;
+ _suggestionServiceBase = suggestionServiceBase;
+ _listener = listenerProvider.GetListener(FeatureAttribute.CopilotChangeAnalysis);
+
+ _completionWorkQueue = new AsyncBatchingWorkQueue<(bool accepted, ProposalBase proposal)>(
+ DelayTimeSpan.Idle,
+ ProcessCompletionEventsAsync,
+ _listener,
+ _threadingContext.DisposalToken);
+ }
+
+ public void TextViewCreated(IWpfTextView textView)
+ {
+ // On the first roslyn text view created, kick off work to hydrate the suggestion service and register to events
+ // from it.
+ if (Interlocked.CompareExchange(ref _started, 1, 0) == 0)
+ {
+ var token = _listener.BeginAsyncOperation(nameof(TextViewCreated));
+ Task.Run(() =>
+ {
+ var suggestionService = _suggestionServiceBase.Value;
+ suggestionService.SuggestionAccepted += OnCompletionSuggestionAccepted;
+ suggestionService.SuggestionDismissed += OnCompletionSuggestionDismissed;
+ }).CompletesAsyncOperation(token);
+ }
+ }
+
+ private void OnCompletionSuggestionAccepted(object sender, SuggestionAcceptedEventArgs e)
+ => OnCompletionSuggestionEvent(accepted: true, e.FinalProposal);
+
+ private void OnCompletionSuggestionDismissed(object sender, SuggestionDismissedEventArgs e)
+ => OnCompletionSuggestionEvent(accepted: false, e.FinalProposal);
+
+ private void OnCompletionSuggestionEvent(bool accepted, ProposalBase? proposal)
+ {
+ if (proposal is not { Edits.Count: > 0 })
+ return;
+
+ _completionWorkQueue.AddWork((accepted, proposal));
+ }
+
+ private async ValueTask ProcessCompletionEventsAsync(
+ ImmutableSegmentedList<(bool accepted, ProposalBase proposal)> list, CancellationToken cancellationToken)
+ {
+ // Ignore if analyzing changes is disabled for this user.
+ if (!_globalOptions.GetOption(CopilotOptions.AnalyzeCopilotChanges))
+ return;
+
+ foreach (var (accepted, proposal) in list)
+ await ProcessCompletionEventAsync(accepted, proposal, cancellationToken).ConfigureAwait(false);
+ }
+
+ private static async ValueTask ProcessCompletionEventAsync(
+ bool accepted, ProposalBase proposal, CancellationToken cancellationToken)
+ {
+ const string featureId = "Completion";
+ var proposalId = proposal.ProposalId;
+
+ foreach (var editGroup in proposal.Edits.GroupBy(e => e.Span.Snapshot))
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var snapshot = editGroup.Key;
+ var document = snapshot.GetOpenDocumentInCurrentContextWithChanges();
+
+ if (document is null)
+ continue;
+
+ using var _ = PooledObjects.ArrayBuilder.GetInstance(out var textChanges);
+ foreach (var edit in editGroup)
+ textChanges.Add(new TextChange(edit.Span.Span.ToTextSpan(), edit.ReplacementText));
+
+ await CopilotChangeAnalysisUtilities.AnalyzeCopilotChangeAsync(
+ document, accepted, featureId, proposalId, textChanges, cancellationToken).ConfigureAwait(false);
+ }
+ }
+}
diff --git a/src/EditorFeatures/Core.Wpf/InlineDiagnostics/AbstractDiagnosticsTaggerProvider.SingleDiagnosticKindPullTaggerProvider.cs b/src/EditorFeatures/Core.Wpf/InlineDiagnostics/AbstractDiagnosticsTaggerProvider.SingleDiagnosticKindPullTaggerProvider.cs
index d38f7a89b74eb..e58806e7b93f2 100644
--- a/src/EditorFeatures/Core.Wpf/InlineDiagnostics/AbstractDiagnosticsTaggerProvider.SingleDiagnosticKindPullTaggerProvider.cs
+++ b/src/EditorFeatures/Core.Wpf/InlineDiagnostics/AbstractDiagnosticsTaggerProvider.SingleDiagnosticKindPullTaggerProvider.cs
@@ -35,14 +35,12 @@ internal abstract partial class AbstractDiagnosticsTaggerProvider
///
private sealed class SingleDiagnosticKindPullTaggerProvider(
AbstractDiagnosticsTaggerProvider callback,
- IDiagnosticAnalyzerService analyzerService,
DiagnosticKind diagnosticKind,
TaggerHost taggerHost,
string featureName)
: AsynchronousTaggerProvider(taggerHost, featureName)
{
private readonly DiagnosticKind _diagnosticKind = diagnosticKind;
- private readonly IDiagnosticAnalyzerService _analyzerService = analyzerService;
// The following three fields are used to help calculate diagnostic performance for syntax errors upon file open.
// During TagsChanged notification for syntax errors, VSPlatform will check the buffer's property bag for a
@@ -104,7 +102,8 @@ private async Task ProduceTagsAsync(
var snapshot = documentSpanToTag.SnapshotSpan.Snapshot;
var project = document.Project;
- var workspace = project.Solution.Workspace;
+ var solution = project.Solution;
+ var workspace = solution.Workspace;
// See if we've marked any spans as those we want to suppress diagnostics for.
// This can happen for buffers used in the preview workspace where some feature
@@ -124,7 +123,8 @@ private async Task ProduceTagsAsync(
// NOTE: We pass 'includeSuppressedDiagnostics: true' to ensure that IDE0079 (unnecessary suppressions)
// are flagged and faded in the editor. IDE0079 analyzer requires all source suppressed diagnostics to
// be provided to it to function correctly.
- var diagnostics = await _analyzerService.GetDiagnosticsForSpanAsync(
+ var analyzerService = solution.Services.GetRequiredService();
+ var diagnostics = await analyzerService.GetDiagnosticsForSpanAsync(
document,
requestedSpan.Span.ToTextSpan(),
diagnosticKind: _diagnosticKind,
diff --git a/src/EditorFeatures/Core.Wpf/InlineDiagnostics/AbstractDiagnosticsTaggerProvider.cs b/src/EditorFeatures/Core.Wpf/InlineDiagnostics/AbstractDiagnosticsTaggerProvider.cs
index f9efa1398c4ca..3aaacb2c06c51 100644
--- a/src/EditorFeatures/Core.Wpf/InlineDiagnostics/AbstractDiagnosticsTaggerProvider.cs
+++ b/src/EditorFeatures/Core.Wpf/InlineDiagnostics/AbstractDiagnosticsTaggerProvider.cs
@@ -31,7 +31,6 @@ internal abstract partial class AbstractDiagnosticsTaggerProvider : ITagge
private readonly ImmutableArray _diagnosticsTaggerProviders;
public AbstractDiagnosticsTaggerProvider(
- IDiagnosticAnalyzerService analyzerService,
TaggerHost taggerHost,
string featureName)
{
@@ -48,7 +47,7 @@ public AbstractDiagnosticsTaggerProvider(
return;
SingleDiagnosticKindPullTaggerProvider CreateDiagnosticsTaggerProvider(DiagnosticKind diagnosticKind)
- => new(this, analyzerService, diagnosticKind, taggerHost, featureName);
+ => new(this, diagnosticKind, taggerHost, featureName);
}
// Functionality for subclasses to control how this diagnostic tagging operates. All the individual
diff --git a/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTaggerProvider.cs b/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTaggerProvider.cs
index 257c80587890c..e5e814ab7e1ab 100644
--- a/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTaggerProvider.cs
+++ b/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTaggerProvider.cs
@@ -25,15 +25,12 @@ namespace Microsoft.CodeAnalysis.Editor.InlineDiagnostics;
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal sealed class InlineDiagnosticsTaggerProvider(
- IDiagnosticAnalyzerService analyzerService,
TaggerHost taggerHost,
IEditorFormatMapService editorFormatMapService,
IClassificationFormatMapService classificationFormatMapService,
IClassificationTypeRegistryService classificationTypeRegistryService)
: AbstractDiagnosticsTaggerProvider(
- analyzerService,
- taggerHost,
- FeatureAttribute.ErrorSquiggles)
+ taggerHost, FeatureAttribute.ErrorSquiggles)
{
private readonly IEditorFormatMap _editorFormatMap = editorFormatMapService.GetEditorFormatMap("text");
private readonly IClassificationFormatMapService _classificationFormatMapService = classificationFormatMapService;
diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs
index 5939394e80816..ba0c0f51e2a55 100644
--- a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs
+++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs
@@ -24,11 +24,10 @@ public AnalyzerSettingsProvider(
string fileName,
AnalyzerSettingsUpdater settingsUpdater,
Workspace workspace,
- IDiagnosticAnalyzerService analyzerService,
IGlobalOptionService optionService)
: base(fileName, settingsUpdater, workspace, optionService)
{
- _analyzerService = analyzerService;
+ _analyzerService = workspace.Services.GetRequiredService();
Update();
}
diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProviderFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProviderFactory.cs
index 4a0dedbe75bb5..49de006cc6b58 100644
--- a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProviderFactory.cs
+++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProviderFactory.cs
@@ -11,12 +11,11 @@ namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Analyz
internal sealed class AnalyzerSettingsProviderFactory(
Workspace workspace,
- IDiagnosticAnalyzerService analyzerService,
IGlobalOptionService globalOptionService) : IWorkspaceSettingsProviderFactory
{
public ISettingsProvider GetForFile(string filePath)
{
var updater = new AnalyzerSettingsUpdater(workspace, filePath);
- return new AnalyzerSettingsProvider(filePath, updater, workspace, analyzerService, globalOptionService);
+ return new AnalyzerSettingsProvider(filePath, updater, workspace, globalOptionService);
}
}
diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsWorkspaceServiceFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsWorkspaceServiceFactory.cs
index 7945e987215b1..095d1a9d5624a 100644
--- a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsWorkspaceServiceFactory.cs
+++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsWorkspaceServiceFactory.cs
@@ -16,9 +16,8 @@ namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Analyz
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal sealed class AnalyzerSettingsWorkspaceServiceFactory(
- IDiagnosticAnalyzerService analyzerService,
IGlobalOptionService globalOptionService) : IWorkspaceServiceFactory
{
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
- => new AnalyzerSettingsProviderFactory(workspaceServices.Workspace, analyzerService, globalOptionService);
+ => new AnalyzerSettingsProviderFactory(workspaceServices.Workspace, globalOptionService);
}
diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptPullDiagnosticHandlerProvider.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptPullDiagnosticHandlerProvider.cs
index b5527e89596a0..7fbba09f1e8da 100644
--- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptPullDiagnosticHandlerProvider.cs
+++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptPullDiagnosticHandlerProvider.cs
@@ -17,10 +17,9 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript;
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal class VSTypeScriptDocumentPullDiagnosticHandlerFactory(
- IDiagnosticAnalyzerService analyzerService,
IDiagnosticSourceManager diagnosticSourceManager,
IDiagnosticsRefresher diagnosticsRefresher,
- IGlobalOptionService globalOptions) : DocumentPullDiagnosticHandlerFactory(analyzerService, diagnosticSourceManager, diagnosticsRefresher, globalOptions)
+ IGlobalOptionService globalOptions) : DocumentPullDiagnosticHandlerFactory(diagnosticSourceManager, diagnosticsRefresher, globalOptions)
{
}
@@ -29,9 +28,8 @@ internal class VSTypeScriptDocumentPullDiagnosticHandlerFactory(
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal class VSTypeScriptWorkspacePullDiagnosticHandler(
LspWorkspaceRegistrationService registrationService,
- IDiagnosticAnalyzerService analyzerService,
IDiagnosticSourceManager diagnosticSourceManager,
IDiagnosticsRefresher diagnosticsRefresher,
- IGlobalOptionService globalOptions) : WorkspacePullDiagnosticHandlerFactory(registrationService, analyzerService, diagnosticSourceManager, diagnosticsRefresher, globalOptions)
+ IGlobalOptionService globalOptions) : WorkspacePullDiagnosticHandlerFactory(registrationService, diagnosticSourceManager, diagnosticsRefresher, globalOptions)
{
}
diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs
index 33e6adf031c9b..960c6d7e229c1 100644
--- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs
+++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs
@@ -38,7 +38,6 @@ private sealed class StateMachine
private readonly IInlineRenameService _inlineRenameService;
private readonly IAsynchronousOperationListener _asyncListener;
- private readonly IDiagnosticAnalyzerService _diagnosticAnalyzerService;
// Store committed sessions so they can be restored on undo/redo. The undo transactions
// may live beyond the lifetime of the buffer tracked by this StateMachine, so storing
@@ -58,7 +57,6 @@ public StateMachine(
IThreadingContext threadingContext,
ITextBuffer buffer,
IInlineRenameService inlineRenameService,
- IDiagnosticAnalyzerService diagnosticAnalyzerService,
IGlobalOptionService globalOptions,
IAsynchronousOperationListener asyncListener)
{
@@ -67,7 +65,6 @@ public StateMachine(
Buffer.Changed += Buffer_Changed;
_inlineRenameService = inlineRenameService;
_asyncListener = asyncListener;
- _diagnosticAnalyzerService = diagnosticAnalyzerService;
GlobalOptions = globalOptions;
}
@@ -238,8 +235,8 @@ public bool ClearVisibleTrackingSession()
// provide a diagnostic/codefix, but nothing has changed in the workspace
// to trigger the diagnostic system to reanalyze, so we trigger it
// manually.
-
- _diagnosticAnalyzerService?.RequestDiagnosticRefresh();
+ var service = document.Project.Solution.Services.GetRequiredService();
+ service.RequestDiagnosticRefresh();
}
// Disallow the existing TrackingSession from triggering IdentifierFound.
diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.cs
index 8e4deef024bea..4fb1de3d67acc 100644
--- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.cs
+++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.cs
@@ -40,19 +40,17 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.RenameTracking;
internal sealed partial class RenameTrackingTaggerProvider(
IThreadingContext threadingContext,
IInlineRenameService inlineRenameService,
- IDiagnosticAnalyzerService diagnosticAnalyzerService,
IGlobalOptionService globalOptions,
IAsynchronousOperationListenerProvider listenerProvider) : ITaggerProvider
{
private readonly IThreadingContext _threadingContext = threadingContext;
private readonly IAsynchronousOperationListener _asyncListener = listenerProvider.GetListener(FeatureAttribute.RenameTracking);
private readonly IInlineRenameService _inlineRenameService = inlineRenameService;
- private readonly IDiagnosticAnalyzerService _diagnosticAnalyzerService = diagnosticAnalyzerService;
private readonly IGlobalOptionService _globalOptions = globalOptions;
public ITagger CreateTagger(ITextBuffer buffer) where T : ITag
{
- var stateMachine = buffer.Properties.GetOrCreateSingletonProperty(() => new StateMachine(_threadingContext, buffer, _inlineRenameService, _diagnosticAnalyzerService, _globalOptions, _asyncListener));
+ var stateMachine = buffer.Properties.GetOrCreateSingletonProperty(() => new StateMachine(_threadingContext, buffer, _inlineRenameService, _globalOptions, _asyncListener));
return new Tagger(stateMachine) as ITagger;
}
diff --git a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs
index 149dd06940b05..936e2318e1ba4 100644
--- a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs
+++ b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs
@@ -43,14 +43,14 @@ public async Task TestGetFirstDiagnosticWithFixAsync()
";
using var workspace = TestWorkspace.CreateCSharp(code, composition: s_compositionWithMockDiagnosticUpdateSourceRegistrationService, openDocuments: true);
- var diagnosticService = workspace.GetService();
+ var diagnosticService = workspace.Services.GetRequiredService();
var analyzerReference = new TestAnalyzerReferenceByLanguage(DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap());
workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference]));
var logger = SpecializedCollections.SingletonEnumerable(new Lazy(() => workspace.Services.GetRequiredService()));
var fixService = new CodeFixService(
- diagnosticService, logger, fixers, configurationProviders: []);
+ logger, fixers, configurationProviders: []);
var reference = new MockAnalyzerReference();
var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference);
@@ -323,7 +323,7 @@ private static async Task GetFirstDiagnosticWithFixWithExceptionValidationAsync(
Assert.True(errorReported);
}
- private static (EditorTestWorkspace workspace, IDiagnosticAnalyzerService analyzerService, CodeFixService codeFixService, IErrorLoggerService errorLogger) ServiceSetup(
+ private static (EditorTestWorkspace workspace, CodeFixService codeFixService, IErrorLoggerService errorLogger) ServiceSetup(
CodeFixProvider codefix,
bool includeConfigurationFixProviders = false,
bool throwExceptionInFixerCreation = false,
@@ -331,7 +331,7 @@ private static (EditorTestWorkspace workspace, IDiagnosticAnalyzerService analyz
string code = "class Program { }")
=> ServiceSetup([codefix], includeConfigurationFixProviders, throwExceptionInFixerCreation, additionalDocument, code);
- private static (EditorTestWorkspace workspace, IDiagnosticAnalyzerService analyzerService, CodeFixService codeFixService, IErrorLoggerService errorLogger) ServiceSetup(
+ private static (EditorTestWorkspace workspace, CodeFixService codeFixService, IErrorLoggerService errorLogger) ServiceSetup(
ImmutableArray codefixers,
bool includeConfigurationFixProviders = false,
bool throwExceptionInFixerCreation = false,
@@ -355,7 +355,7 @@ private static (EditorTestWorkspace workspace, IDiagnosticAnalyzerService analyz
var analyzerReference = new TestAnalyzerReferenceByLanguage(DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap());
workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference]));
- var diagnosticService = workspace.GetService();
+ var diagnosticService = workspace.Services.GetRequiredService();
var logger = SpecializedCollections.SingletonEnumerable(new Lazy(() => new TestErrorLogger()));
var errorLogger = logger.First().Value;
@@ -363,13 +363,8 @@ private static (EditorTestWorkspace workspace, IDiagnosticAnalyzerService analyz
? workspace.ExportProvider.GetExports()
: [];
- var fixService = new CodeFixService(
- diagnosticService,
- logger,
- fixers,
- configurationFixProviders);
-
- return (workspace, diagnosticService, fixService, errorLogger);
+ var fixService = new CodeFixService(logger, fixers, configurationFixProviders);
+ return (workspace, fixService, errorLogger);
}
private static void GetDocumentAndExtensionManager(
@@ -757,11 +752,10 @@ private static async Task> GetNuGetAndVsixCode
using var workspace = TestWorkspace.CreateCSharp(code, composition: s_compositionWithMockDiagnosticUpdateSourceRegistrationService, openDocuments: true);
- var diagnosticService = workspace.GetService();
+ var diagnosticService = workspace.Services.GetRequiredService();
var logger = SpecializedCollections.SingletonEnumerable(new Lazy(() => workspace.Services.GetRequiredService()));
- var fixService = new CodeFixService(
- diagnosticService, logger, vsixFixers, configurationProviders: []);
+ var fixService = new CodeFixService(logger, vsixFixers, configurationProviders: []);
diagnosticAnalyzer ??= new MockAnalyzerReference.MockDiagnosticAnalyzer();
var analyzers = ImmutableArray.Create(diagnosticAnalyzer);
@@ -1033,7 +1027,6 @@ void M()
var tuple = ServiceSetup(codeFix, code: code);
using var workspace = tuple.workspace;
- var analyzerService = tuple.analyzerService;
GetDocumentAndExtensionManager(workspace, out var document,
out var extensionManager, analyzerReference);
@@ -1047,6 +1040,7 @@ void M()
// We enable full solution analysis so the 'AnalyzeDocumentAsync' doesn't skip analysis based on whether the document is active/open.
workspace.GlobalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.FullSolution);
+ var analyzerService = workspace.Services.GetRequiredService();
var diagnostics = await analyzerService.ForceAnalyzeProjectAsync(sourceDocument.Project, CancellationToken.None);
await VerifyCachedDiagnosticsAsync(
sourceDocument, expectedCachedDiagnostic: diagnosticOnFixLineInPriorSnapshot, testSpan, diagnostics);
diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs
index 1cdbde9790790..6355aa95a0c64 100644
--- a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs
+++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs
@@ -61,9 +61,7 @@ public async Task TestHasSuccessfullyLoadedBeingFalse()
var document = GetDocumentFromIncompleteProject(workspace);
- var exportProvider = workspace.Services.SolutionServices.ExportProvider;
- var service = exportProvider.GetExportedValue();
- var globalOptions = exportProvider.GetExportedValue();
+ var service = workspace.Services.GetRequiredService();
var diagnostics = await service.GetDiagnosticsForIdsAsync(
workspace.CurrentSolution.Projects.Single(), documentId: null, diagnosticIds: null, shouldIncludeAnalyzer: null,
@@ -175,8 +173,7 @@ public async Task TestDisabledByDefaultAnalyzerEnabledWithEditorConfig(bool enab
var applied = workspace.TryApplyChanges(document.Project.Solution);
Assert.True(applied);
- var exportProvider = workspace.Services.SolutionServices.ExportProvider;
- var service = exportProvider.GetExportedValue();
+ var service = workspace.Services.GetRequiredService();
// listen to events
var syntaxDiagnostic = false;
@@ -215,9 +212,7 @@ private static async Task TestAnalyzerAsync(
Func, (bool, bool)> resultSetter,
bool expectedSyntax, bool expectedSemantic)
{
- var exportProvider = workspace.Services.SolutionServices.ExportProvider;
-
- var service = exportProvider.GetExportedValue();
+ var service = workspace.Services.GetRequiredService();
var syntax = false;
var semantic = false;
@@ -259,7 +254,7 @@ public async Task TestHostAnalyzerOrderingAsync()
"Dummy",
LanguageNames.CSharp));
- var service = Assert.IsType(exportProvider.GetExportedValue());
+ var service = Assert.IsType(workspace.Services.GetRequiredService());
var analyzers = await service.GetTestAccessor().GetAnalyzersAsync(project, CancellationToken.None).ConfigureAwait(false);
var analyzersArray = analyzers.ToArray();
@@ -307,8 +302,7 @@ public async Task TestHostAnalyzerErrorNotLeaking()
loader: TextLoader.From(TextAndVersion.Create(SourceText.From("class A {}"), VersionStamp.Create(), filePath: "test.cs")),
filePath: "test.cs")]));
- var exportProvider = workspace.Services.SolutionServices.ExportProvider;
- var service = exportProvider.GetExportedValue();
+ var service = workspace.Services.GetRequiredService();
var diagnostics = await service.ForceAnalyzeProjectAsync(project, CancellationToken.None);
Assert.NotEmpty(diagnostics);
@@ -392,8 +386,7 @@ private static AdhocWorkspace CreateWorkspaceWithProjectAndAnalyzer(DiagnosticAn
private static async Task TestFullSolutionAnalysisForProjectAsync(AdhocWorkspace workspace, Project project, bool expectAnalyzerExecuted)
{
- var exportProvider = workspace.Services.SolutionServices.ExportProvider;
- var service = exportProvider.GetExportedValue();
+ var service = workspace.Services.GetRequiredService();
var diagnostics = await service.ForceAnalyzeProjectAsync(project, CancellationToken.None);
@@ -438,8 +431,7 @@ internal async Task TestAdditionalFileAnalyzer(bool registerFromInitialize, bool
var applied = workspace.TryApplyChanges(project.Solution);
Assert.True(applied);
- var exportProvider = workspace.Services.SolutionServices.ExportProvider;
- var service = exportProvider.GetExportedValue();
+ var service = workspace.Services.GetRequiredService();
var firstAdditionalDocument = project.AdditionalDocuments.FirstOrDefault();
@@ -503,7 +495,7 @@ internal async Task TestDiagnosticSuppressor(bool includeAnalyzer, bool includeS
var project = workspace.CurrentSolution.Projects.Single();
var document = project.Documents.Single();
- var service = workspace.GetService();
+ var service = workspace.Services.GetRequiredService();
var globalOptions = workspace.GetService();
switch (analysisScope)
@@ -620,7 +612,7 @@ void M()
else
Assert.IsType(document);
- var service = workspace.GetService();
+ var service = workspace.Services.GetRequiredService();
var text = await document.GetTextAsync();
@@ -858,7 +850,7 @@ internal async Task TestGeneratorProducedDiagnostics(bool fullSolutionAnalysis,
workspace.OpenDocument(document.Id);
}
- var service = workspace.GetService();
+ var service = workspace.Services.GetRequiredService();
var diagnostics = await service.ForceAnalyzeProjectAsync(project, CancellationToken.None);
diff --git a/src/EditorFeatures/Test/RenameTracking/RenameTrackingTestState.cs b/src/EditorFeatures/Test/RenameTracking/RenameTrackingTestState.cs
index e74ee8de48d20..4c28368add087 100644
--- a/src/EditorFeatures/Test/RenameTracking/RenameTrackingTestState.cs
+++ b/src/EditorFeatures/Test/RenameTracking/RenameTrackingTestState.cs
@@ -98,7 +98,6 @@ public RenameTrackingTestState(
var tracker = new RenameTrackingTaggerProvider(
Workspace.GetService(),
Workspace.GetService(),
- Workspace.GetService(),
Workspace.GetService(),
Workspace.GetService());
diff --git a/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb b/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb
index 5176fb2119f8f..da7fef606b2a5 100644
--- a/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb
+++ b/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb
@@ -56,10 +56,9 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests
Dim project = workspace.CurrentSolution.Projects(0)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim logger = SpecializedCollections.SingletonEnumerable(New Lazy(Of IErrorLoggerService)(Function() workspace.Services.GetService(Of IErrorLoggerService)))
Dim codefixService = New CodeFixService(
- diagnosticService,
logger,
{New Lazy(Of CodeFixProvider, Mef.CodeChangeProviderMetadata)(
Function() workspaceCodeFixProvider,
@@ -127,10 +126,9 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests
Dim project = workspace.CurrentSolution.Projects(0)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim logger = SpecializedCollections.SingletonEnumerable(New Lazy(Of IErrorLoggerService)(Function() workspace.Services.GetService(Of IErrorLoggerService)))
Dim codefixService = New CodeFixService(
- diagnosticService,
logger,
{New Lazy(Of CodeFixProvider, Mef.CodeChangeProviderMetadata)(
Function() workspaceCodeFixProvider,
diff --git a/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb b/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb
index bbb8f0f4a8012..10b648744e280 100644
--- a/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb
+++ b/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb
@@ -290,7 +290,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
Dim analyzerReference = New TestAnalyzerReferenceByLanguage(compilerAnalyzersMap)
workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences({analyzerReference}))
- Dim analyzerService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim analyzerService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Return analyzerService
End Function
diff --git a/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb b/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb
index 9913c17cfea6b..416331a733318 100644
--- a/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb
+++ b/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb
@@ -86,7 +86,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
Dim hostAnalyzers = solution.SolutionState.Analyzers
Dim project = solution.Projects(0)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
' Verify available diagnostic descriptors/analyzers
Dim descriptorsMap = hostAnalyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
@@ -192,7 +192,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
Dim project = solution.Projects(0)
Dim hostAnalyzers = solution.SolutionState.Analyzers
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
' Add project analyzer reference with no analyzers.
Dim projectAnalyzersEmpty = ImmutableArray(Of DiagnosticAnalyzer).Empty
@@ -236,7 +236,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
Dim projectAnalyzerReference = New AnalyzerImageReference(
ImmutableArray.Create(Of DiagnosticAnalyzer)(New TestDiagnosticAnalyzer1(1)), display:=referenceName)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
project = project.WithAnalyzerReferences(ImmutableArray.Create(Of AnalyzerReference)(projectAnalyzerReference))
@@ -272,7 +272,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
Dim project = solution.Projects(0)
Dim hostAnalyzers = solution.SolutionState.Analyzers
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
' Verify available diagnostic descriptors/analyzers
Dim descriptorsMap = hostAnalyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
@@ -343,7 +343,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
SerializerService.TestAccessor.AddAnalyzerImageReferences(p2.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim hostAnalyzers = solution.SolutionState.Analyzers
Dim workspaceDescriptors = hostAnalyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache)
@@ -384,7 +384,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
Dim analyzerReference = New TestAnalyzerReferenceByLanguage(analyzersMap)
workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences({analyzerReference}))
- Dim diagnosticService2 = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService2 = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptors = workspace.CurrentSolution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService2.AnalyzerInfoCache)
Assert.Equal(1, descriptors.Count)
@@ -432,7 +432,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
Dim analyzerReference2 = CreateAnalyzerFileReference(Assembly.GetExecutingAssembly().Location)
project = project.AddAnalyzerReference(analyzerReference2)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptorsMap = workspace.CurrentSolution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
' Verify no duplicate diagnostics.
@@ -486,7 +486,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
Assert.Equal(1, descriptorsMap.Count)
@@ -521,7 +521,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
Assert.Equal(1, descriptorsMap.Count)
@@ -566,7 +566,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
project = project.AddAnalyzerReference(analyzerReference)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim span = (Await document.GetSyntaxRootAsync().ConfigureAwait(False)).FullSpan
Dim diagnostics = Await GetDiagnosticsForSpanAsync(diagnosticService, document, span).ConfigureAwait(False)
@@ -588,7 +588,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
Using workspace = TestWorkspace.CreateWorkspace(test, composition:=s_compositionWithMockDiagnosticUpdateSourceRegistrationService)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
For Each actionKind As OperationAnalyzer.ActionKind In [Enum].GetValues(GetType(OperationAnalyzer.ActionKind))
Dim solution = workspace.CurrentSolution
@@ -633,7 +633,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
Assert.Equal(1, descriptorsMap.Count)
@@ -667,7 +667,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics.UnitTests
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
' Ensure no duplicate diagnostics.
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
@@ -743,7 +743,7 @@ class AnonymousFunctions
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
' Ensure no duplicate diagnostics.
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
@@ -779,7 +779,7 @@ class AnonymousFunctions
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
Assert.Equal(1, descriptorsMap.Count)
@@ -942,7 +942,7 @@ class AnonymousFunctions
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
Assert.Equal(1, descriptorsMap.Count)
@@ -982,7 +982,7 @@ class AnonymousFunctions
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
Assert.Equal(1, descriptorsMap.Count)
@@ -1038,7 +1038,7 @@ class AnonymousFunctions
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
Assert.Equal(1, descriptorsMap.Count)
@@ -1090,7 +1090,7 @@ public class B
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
Assert.Equal(1, descriptorsMap.Count)
@@ -1133,7 +1133,7 @@ public class B
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
Assert.Equal(1, descriptorsMap.Count)
@@ -1176,7 +1176,7 @@ public class B
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
Assert.Equal(1, descriptorsMap.Count)
@@ -1227,7 +1227,7 @@ End Class
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
Assert.Equal(1, descriptorsMap.Count)
@@ -1290,7 +1290,7 @@ public class B
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
Assert.Equal(1, descriptorsMap.Count)
@@ -1337,7 +1337,7 @@ public class B
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
Assert.Equal(1, descriptorsMap.Count)
@@ -1408,7 +1408,7 @@ public class B
project = additionalDoc.Project
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Await TestCompilationAnalyzerWithAnalyzerOptionsCoreAsync(project, additionalDocText, diagnosticService)
@@ -1961,7 +1961,7 @@ End Class
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
Assert.Equal(1, descriptorsMap.Count)
@@ -2021,7 +2021,7 @@ namespace ConsoleApplication1
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
Assert.Equal(1, descriptorsMap.Count)
@@ -2088,7 +2088,7 @@ class MyClass
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
' Verify available diagnostic descriptors/analyzers
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
@@ -2127,7 +2127,7 @@ class MyClass
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
' Verify available diagnostic descriptors
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
@@ -2187,7 +2187,7 @@ class C
Dim span = localDecl.Span
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
' Verify diagnostics for span
Dim diagnostics = Await GetDiagnosticsForSpanAsync(diagnosticService, document, span)
@@ -2228,7 +2228,7 @@ class C
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
Assert.Equal(1, descriptorsMap.Count)
@@ -2273,7 +2273,7 @@ class MyClass
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
' Get diagnostics for span for the given DiagnosticKind
Dim document = project.Documents.Single()
@@ -2343,7 +2343,7 @@ class MyClass
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
' Get diagnostics for span for fine grained DiagnosticKind in random order
Dim document = project.Documents.Single()
@@ -2433,7 +2433,7 @@ public class C
SerializerService.TestAccessor.AddAnalyzerImageReferences(project.AnalyzerReferences)
Dim mefExportProvider = DirectCast(workspace.Services.HostServices, IMefHostExportProvider)
- Dim diagnosticService = workspace.GetService(Of IDiagnosticAnalyzerService)()
+ Dim diagnosticService = workspace.Services.GetRequiredService(Of IDiagnosticAnalyzerService)()
Dim descriptorsMap = solution.SolutionState.Analyzers.GetDiagnosticDescriptorsPerReference(diagnosticService.AnalyzerInfoCache, project)
Assert.Equal(1, descriptorsMap.Count)
diff --git a/src/EditorFeatures/Test2/Rename/RenameTestHelpers.vb b/src/EditorFeatures/Test2/Rename/RenameTestHelpers.vb
index 19f53caf23725..bf29cf35ecad4 100644
--- a/src/EditorFeatures/Test2/Rename/RenameTestHelpers.vb
+++ b/src/EditorFeatures/Test2/Rename/RenameTestHelpers.vb
@@ -109,7 +109,6 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename
Dim tracker = New RenameTrackingTaggerProvider(
workspace.GetService(Of IThreadingContext),
workspace.GetService(Of IInlineRenameService)(),
- workspace.GetService(Of IDiagnosticAnalyzerService)(),
workspace.GetService(Of IGlobalOptionService)(),
workspace.GetService(Of IAsynchronousOperationListenerProvider))
diff --git a/src/EditorFeatures/VisualBasic/CodeCleanup/VisualBasicCodeCleanupService.vb b/src/EditorFeatures/VisualBasic/CodeCleanup/VisualBasicCodeCleanupService.vb
index c23580a6824f3..f0c150f02a1e7 100644
--- a/src/EditorFeatures/VisualBasic/CodeCleanup/VisualBasicCodeCleanupService.vb
+++ b/src/EditorFeatures/VisualBasic/CodeCleanup/VisualBasicCodeCleanupService.vb
@@ -82,8 +82,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeCleanup
- Public Sub New(codeFixService As ICodeFixService, diagnosticAnalyzerService As IDiagnosticAnalyzerService)
- MyBase.New(codeFixService, diagnosticAnalyzerService)
+ Public Sub New(codeFixService As ICodeFixService)
+ MyBase.New(codeFixService)
End Sub
Protected Overrides ReadOnly Property OrganizeImportsDescription As String = VBFeaturesResources.Organize_Imports
diff --git a/src/Features/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs b/src/Features/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs
index 10a161b802860..2e3bd31b2d426 100644
--- a/src/Features/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs
+++ b/src/Features/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs
@@ -446,12 +446,11 @@ void Method()
var analyzerReference = new AnalyzerImageReference([new CSharpCompilerDiagnosticAnalyzer()]);
workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference]));
- var diagnosticService = workspace.ExportProvider.GetExportedValue();
+ var diagnosticService = workspace.Services.GetRequiredService();
var suppressionProvider = CreateDiagnosticProviderAndFixer(workspace).Item2;
var suppressionProviderFactory = new Lazy(() => suppressionProvider,
new CodeChangeProviderMetadata("SuppressionProvider", languages: [LanguageNames.CSharp]));
var fixService = new CodeFixService(
- diagnosticService,
loggers: [],
fixers: [],
[suppressionProviderFactory]);
diff --git a/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.FixAllDiagnosticProvider.cs b/src/Features/Core/Portable/CodeFixes/Service/CodeFixService.FixAllDiagnosticProvider.cs
similarity index 83%
rename from src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.FixAllDiagnosticProvider.cs
rename to src/Features/Core/Portable/CodeFixes/Service/CodeFixService.FixAllDiagnosticProvider.cs
index 46e18b82466e5..0a8648a8a5977 100644
--- a/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.FixAllDiagnosticProvider.cs
+++ b/src/Features/Core/Portable/CodeFixes/Service/CodeFixService.FixAllDiagnosticProvider.cs
@@ -18,14 +18,11 @@ internal partial class CodeFixService
{
private sealed class FixAllDiagnosticProvider : FixAllContext.SpanBasedDiagnosticProvider
{
- private readonly IDiagnosticAnalyzerService _diagnosticService;
private readonly ImmutableHashSet? _diagnosticIds;
private readonly bool _includeSuppressedDiagnostics;
- public FixAllDiagnosticProvider(IDiagnosticAnalyzerService diagnosticService, ImmutableHashSet diagnosticIds)
+ public FixAllDiagnosticProvider(ImmutableHashSet diagnosticIds)
{
- _diagnosticService = diagnosticService;
-
// When computing FixAll for unnecessary pragma suppression diagnostic,
// we need to include suppressed diagnostics, as well as reported compiler and analyzer diagnostics.
// A null value for '_diagnosticIds' ensures the latter.
@@ -46,7 +43,8 @@ private ImmutableArray Filter(ImmutableArray dia
public override async Task> GetDocumentDiagnosticsAsync(Document document, CancellationToken cancellationToken)
{
- var diagnostics = Filter(await _diagnosticService.GetDiagnosticsForIdsAsync(
+ var service = document.Project.Solution.Services.GetRequiredService();
+ var diagnostics = Filter(await service.GetDiagnosticsForIdsAsync(
document.Project, document.Id, _diagnosticIds, shouldIncludeAnalyzer: null, includeLocalDocumentDiagnostics: true, includeNonLocalDocumentDiagnostics: false, cancellationToken).ConfigureAwait(false));
Contract.ThrowIfFalse(diagnostics.All(d => d.DocumentId != null));
return await diagnostics.ToDiagnosticsAsync(document.Project, cancellationToken).ConfigureAwait(false);
@@ -55,7 +53,9 @@ public override async Task> GetDocumentDiagnosticsAsync(
public override async Task> GetDocumentSpanDiagnosticsAsync(Document document, TextSpan fixAllSpan, CancellationToken cancellationToken)
{
bool shouldIncludeDiagnostic(string id) => _diagnosticIds == null || _diagnosticIds.Contains(id);
- var diagnostics = Filter(await _diagnosticService.GetDiagnosticsForSpanAsync(
+
+ var service = document.Project.Solution.Services.GetRequiredService();
+ var diagnostics = Filter(await service.GetDiagnosticsForSpanAsync(
document, fixAllSpan, shouldIncludeDiagnostic,
priorityProvider: new DefaultCodeActionRequestPriorityProvider(),
DiagnosticKind.All, isExplicit: false, cancellationToken).ConfigureAwait(false));
@@ -66,7 +66,8 @@ public override async Task> GetDocumentSpanDiagnosticsAs
public override async Task> GetAllDiagnosticsAsync(Project project, CancellationToken cancellationToken)
{
// Get all diagnostics for the entire project, including document diagnostics.
- var diagnostics = Filter(await _diagnosticService.GetDiagnosticsForIdsAsync(
+ var service = project.Solution.Services.GetRequiredService();
+ var diagnostics = Filter(await service.GetDiagnosticsForIdsAsync(
project, documentId: null, _diagnosticIds, shouldIncludeAnalyzer: null, includeLocalDocumentDiagnostics: true, includeNonLocalDocumentDiagnostics: false, cancellationToken).ConfigureAwait(false));
return await diagnostics.ToDiagnosticsAsync(project, cancellationToken).ConfigureAwait(false);
}
@@ -74,7 +75,8 @@ public override async Task> GetAllDiagnosticsAsync(Proje
public override async Task> GetProjectDiagnosticsAsync(Project project, CancellationToken cancellationToken)
{
// Get all no-location diagnostics for the project, doesn't include document diagnostics.
- var diagnostics = Filter(await _diagnosticService.GetProjectDiagnosticsForIdsAsync(
+ var service = project.Solution.Services.GetRequiredService();
+ var diagnostics = Filter(await service.GetProjectDiagnosticsForIdsAsync(
project, _diagnosticIds, shouldIncludeAnalyzer: null, includeNonLocalDocumentDiagnostics: false, cancellationToken).ConfigureAwait(false));
Contract.ThrowIfFalse(diagnostics.All(d => d.DocumentId == null));
return await diagnostics.ToDiagnosticsAsync(project, cancellationToken).ConfigureAwait(false);
diff --git a/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.FixAllPredefinedDiagnosticProvider.cs b/src/Features/Core/Portable/CodeFixes/Service/CodeFixService.FixAllPredefinedDiagnosticProvider.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.FixAllPredefinedDiagnosticProvider.cs
rename to src/Features/Core/Portable/CodeFixes/Service/CodeFixService.FixAllPredefinedDiagnosticProvider.cs
diff --git a/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.ProjectCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/Service/CodeFixService.ProjectCodeFixProvider.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.ProjectCodeFixProvider.cs
rename to src/Features/Core/Portable/CodeFixes/Service/CodeFixService.ProjectCodeFixProvider.cs
diff --git a/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs b/src/Features/Core/Portable/CodeFixes/Service/CodeFixService.cs
similarity index 97%
rename from src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs
rename to src/Features/Core/Portable/CodeFixes/Service/CodeFixService.cs
index 1ffd392fbd3b1..43f05dd523d43 100644
--- a/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs
+++ b/src/Features/Core/Portable/CodeFixes/Service/CodeFixService.cs
@@ -28,7 +28,7 @@
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Telemetry;
using Microsoft.CodeAnalysis.Text;
-using Microsoft.VisualStudio.Threading;
+using Microsoft.CodeAnalysis.Threading;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CodeFixes
@@ -39,7 +39,6 @@ namespace Microsoft.CodeAnalysis.CodeFixes
[Export(typeof(ICodeFixService)), Shared]
internal partial class CodeFixService : ICodeFixService
{
- private readonly IDiagnosticAnalyzerService _diagnosticService;
private readonly ImmutableArray> _fixers;
private readonly ImmutableDictionary>> _fixersPerLanguageMap;
@@ -59,12 +58,10 @@ internal partial class CodeFixService : ICodeFixService
[ImportingConstructor]
[SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")]
public CodeFixService(
- IDiagnosticAnalyzerService diagnosticAnalyzerService,
[ImportMany] IEnumerable> loggers,
[ImportMany] IEnumerable> fixers,
[ImportMany] IEnumerable> configurationProviders)
{
- _diagnosticService = diagnosticAnalyzerService;
_errorLoggers = [.. loggers];
_fixers = [.. fixers];
@@ -103,11 +100,16 @@ public CodeFixService(
{
using var _ = TelemetryLogging.LogBlockTimeAggregatedHistogram(FunctionId.CodeFix_Summary, $"Pri{priorityProvider.Priority.GetPriorityInt()}.{nameof(GetMostSevereFixAsync)}");
+ // Ensure we yield here so the caller can continue on.
+ await Task.Yield().ConfigureAwait(false);
+
ImmutableArray allDiagnostics;
- using (TelemetryLogging.LogBlockTimeAggregatedHistogram(FunctionId.CodeFix_Summary, $"Pri{priorityProvider.Priority.GetPriorityInt()}.{nameof(GetMostSevereFixAsync)}.{nameof(_diagnosticService.GetDiagnosticsForSpanAsync)}"))
+ using (TelemetryLogging.LogBlockTimeAggregatedHistogram(
+ FunctionId.CodeFix_Summary, $"Pri{priorityProvider.Priority.GetPriorityInt()}.{nameof(GetMostSevereFixAsync)}.{nameof(IDiagnosticAnalyzerService.GetDiagnosticsForSpanAsync)}"))
{
- allDiagnostics = await _diagnosticService.GetDiagnosticsForSpanAsync(
+ var service = document.Project.Solution.Services.GetRequiredService();
+ allDiagnostics = await service.GetDiagnosticsForSpanAsync(
document, range, GetShouldIncludeDiagnosticPredicate(document, priorityProvider),
priorityProvider, DiagnosticKind.All, isExplicit: false, cancellationToken).ConfigureAwait(false);
@@ -157,7 +159,7 @@ public CodeFixService(
CancellationToken cancellationToken)
{
// Ensure we yield here so the caller can continue on.
- await TaskScheduler.Default.SwitchTo(alwaysYield: true);
+ await Task.Yield().ConfigureAwait(false);
await foreach (var collection in StreamFixesAsync(
document, spanToDiagnostics, fixAllForInSpan: false,
@@ -195,9 +197,11 @@ public async IAsyncEnumerable StreamFixesAsync(
// user-invoked diagnostic requests, for example, user invoked Ctrl + Dot operation for lightbulb.
ImmutableArray diagnostics;
- using (TelemetryLogging.LogBlockTimeAggregatedHistogram(FunctionId.CodeFix_Summary, $"Pri{priorityProvider.Priority.GetPriorityInt()}.{nameof(_diagnosticService.GetDiagnosticsForSpanAsync)}"))
+ using (TelemetryLogging.LogBlockTimeAggregatedHistogram(
+ FunctionId.CodeFix_Summary, $"Pri{priorityProvider.Priority.GetPriorityInt()}.{nameof(IDiagnosticAnalyzerService.GetDiagnosticsForSpanAsync)}"))
{
- diagnostics = await _diagnosticService.GetDiagnosticsForSpanAsync(
+ var service = document.Project.Solution.Services.GetRequiredService();
+ diagnostics = await service.GetDiagnosticsForSpanAsync(
document, range, GetShouldIncludeDiagnosticPredicate(document, priorityProvider),
priorityProvider, DiagnosticKind.All, isExplicit: true, cancellationToken).ConfigureAwait(false);
if (!includeSuppressionFixes)
@@ -295,9 +299,11 @@ private static SortedDictionary> ConvertToMap(
using var _ = TelemetryLogging.LogBlockTimeAggregatedHistogram(FunctionId.CodeFix_Summary, $"{nameof(GetDocumentFixAllForIdInSpanAsync)}");
ImmutableArray diagnostics;
- using (TelemetryLogging.LogBlockTimeAggregatedHistogram(FunctionId.CodeFix_Summary, $"{nameof(GetDocumentFixAllForIdInSpanAsync)}.{nameof(_diagnosticService.GetDiagnosticsForSpanAsync)}"))
+ using (TelemetryLogging.LogBlockTimeAggregatedHistogram(
+ FunctionId.CodeFix_Summary, $"{nameof(GetDocumentFixAllForIdInSpanAsync)}.{nameof(IDiagnosticAnalyzerService.GetDiagnosticsForSpanAsync)}"))
{
- diagnostics = await _diagnosticService.GetDiagnosticsForSpanAsync(
+ var service = document.Project.Solution.Services.GetRequiredService();
+ diagnostics = await service.GetDiagnosticsForSpanAsync(
document, range, diagnosticId, priorityProvider: new DefaultCodeActionRequestPriorityProvider(),
DiagnosticKind.All, isExplicit: false, cancellationToken).ConfigureAwait(false);
@@ -313,9 +319,9 @@ private static SortedDictionary> ConvertToMap(
using var resultDisposer = ArrayBuilder.GetInstance(out var result);
var spanToDiagnostics = new SortedDictionary>
- {
- { range, diagnostics.ToList() },
- };
+ {
+ { range, diagnostics.ToList() },
+ };
await foreach (var collection in StreamFixesAsync(
document, spanToDiagnostics, fixAllForInSpan: true, new DefaultCodeActionRequestPriorityProvider(),
@@ -785,7 +791,7 @@ await diagnosticsWithSameSpan.OrderByDescending(d => d.Severity)
var diagnosticProvider = fixAllForInSpan
? new FixAllPredefinedDiagnosticProvider(allDiagnostics)
- : (FixAllContext.DiagnosticProvider)new FixAllDiagnosticProvider(_diagnosticService, diagnosticIds);
+ : (FixAllContext.DiagnosticProvider)new FixAllDiagnosticProvider(diagnosticIds);
var codeFixProvider = (fixer as CodeFixProvider) ?? new WrapperCodeFixProvider((IConfigurationFixProvider)fixer, diagnostics.Select(d => d.Id));
diff --git a/src/LanguageServer/Protocol/Features/CodeFixes/ICodeFixService.cs b/src/Features/Core/Portable/CodeFixes/Service/ICodeFixService.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/CodeFixes/ICodeFixService.cs
rename to src/Features/Core/Portable/CodeFixes/Service/ICodeFixService.cs
diff --git a/src/Features/Core/Portable/Copilot/CopilotChangeAnalysis.cs b/src/Features/Core/Portable/Copilot/CopilotChangeAnalysis.cs
new file mode 100644
index 0000000000000..8df5f9a04b589
--- /dev/null
+++ b/src/Features/Core/Portable/Copilot/CopilotChangeAnalysis.cs
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// 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.Runtime.Serialization;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace Microsoft.CodeAnalysis.Copilot;
+
+/// Total time to do all analysis (including diagnostics, code fixes, and application).
+/// Total time to do all diagnostic computation over all diagnostic kinds.
+[DataContract]
+internal readonly record struct CopilotChangeAnalysis(
+ [property: DataMember(Order = 0)] bool Succeeded,
+ [property: DataMember(Order = 1)] int OldDocumentLength,
+ [property: DataMember(Order = 2)] int NewDocumentLength,
+ [property: DataMember(Order = 3)] int TextChangeDelta,
+ [property: DataMember(Order = 4)] int ProjectDocumentCount,
+ [property: DataMember(Order = 5)] int ProjectSourceGeneratedDocumentCount,
+ [property: DataMember(Order = 6)] int ProjectConeCount,
+ [property: DataMember(Order = 7)] TimeSpan TotalAnalysisTime,
+ [property: DataMember(Order = 8)] TimeSpan ForkingTime,
+ [property: DataMember(Order = 9)] TimeSpan TotalDiagnosticComputationTime,
+ [property: DataMember(Order = 10)] ImmutableArray DiagnosticAnalyses,
+ [property: DataMember(Order = 11)] CopilotCodeFixAnalysis CodeFixAnalysis);
+
+/// What diagnostic kind this is analysis data for.
+/// How long it took to produce the diagnostics for this diagnostic kind.
+/// Mapping from to the number of diagnostics produced for that id.
+/// Mapping from to the number of diagnostics produced for that category.
+/// Mapping from to the number of diagnostics produced for that severity.
+[DataContract]
+internal readonly record struct CopilotDiagnosticAnalysis(
+ [property: DataMember(Order = 0)] DiagnosticKind Kind,
+ [property: DataMember(Order = 1)] TimeSpan ComputationTime,
+ [property: DataMember(Order = 2)] Dictionary IdToCount,
+ [property: DataMember(Order = 3)] Dictionary CategoryToCount,
+ [property: DataMember(Order = 4)] Dictionary SeverityToCount);
+
+/// Total time to compute code fixes for the changed regions.
+/// Total time to apply code fixes for the changed regions.
+/// Mapping from diagnostic id to to how many diagnostics with that id had fixes.
+/// Mapping from diagnostic id to the total time taken to fix diagnostics with that id.
+/// Mapping from diagnostic id to the name of the provider that provided the fix.
+/// Mapping from provider name to the total time taken to fix diagnostics with that provider.
+/// Mapping from provider name to whether or not that provider conflicted with another provider in producing a fix.
+[DataContract]
+internal readonly record struct CopilotCodeFixAnalysis(
+ [property: DataMember(Order = 0)] TimeSpan TotalComputationTime,
+ [property: DataMember(Order = 1)] TimeSpan TotalApplicationTime,
+ [property: DataMember(Order = 2)] Dictionary DiagnosticIdToCount,
+ [property: DataMember(Order = 3)] Dictionary DiagnosticIdToApplicationTime,
+ [property: DataMember(Order = 4)] Dictionary> DiagnosticIdToProviderName,
+ [property: DataMember(Order = 5)] Dictionary ProviderNameToApplicationTime,
+ [property: DataMember(Order = 6)] Dictionary ProviderNameToHasConflict);
diff --git a/src/Features/Core/Portable/Copilot/CopilotChangeAnalysisUtilities.cs b/src/Features/Core/Portable/Copilot/CopilotChangeAnalysisUtilities.cs
new file mode 100644
index 0000000000000..664136fd80f4b
--- /dev/null
+++ b/src/Features/Core/Portable/Copilot/CopilotChangeAnalysisUtilities.cs
@@ -0,0 +1,139 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// 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 System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Internal.Log;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Microsoft.CodeAnalysis.Copilot;
+
+internal static class CopilotChangeAnalysisUtilities
+{
+ ///
+ /// Analyzes and collects interesting data about an edit made by some copilot feature, and reports that back as
+ /// telemetry to help inform what automatic fixing features we should invest in.
+ ///
+ /// The document being edited. The document should represent the contents of hte file
+ /// prior to the being applied.
+ /// Whether or not the user accepted the copilot suggestion, or rejected it. Used to
+ /// determine if there are interesting issues occurring that might be leading to the user rejecting the change
+ /// (for example, excessive syntax errors).
+ /// The name of the feature making the text change. For example 'Completion'. Used
+ /// to bucket information by feature area in case certain feature produce different sets of diagnostics or
+ /// fixes commonly.
+ /// Copilot proposal id (generally a stringified ). Used to be able
+ /// to map from one of these proposed edits to any additional telemetry stored in other tables about this copilot
+ /// interaction.
+ /// The actual text changes to make. The text changes do not have to be normalized.
+ /// Though they should not overlap. If they overlap, this request will be ignored. These would be the changes
+ /// passed to for the text snapshot corresponding to
+ /// .
+ public static async Task AnalyzeCopilotChangeAsync(
+ Document document,
+ bool accepted,
+ string featureId,
+ string proposalId,
+ IEnumerable textChanges,
+ CancellationToken cancellationToken)
+ {
+ // Currently we do not support analyzing languges other than C# and VB. This is because we only want to do
+ // this analsis in our OOP process to avoid perf impact on the VS process. And we don't have OOP for other
+ // languages yet.
+ if (!document.SupportsSemanticModel)
+ return;
+
+ var normalizedEdits = Normalize(textChanges);
+ if (normalizedEdits.IsDefaultOrEmpty)
+ return;
+
+ var changeAnalysisService = document.Project.Solution.Services.GetRequiredService();
+ var analysisResult = await changeAnalysisService.AnalyzeChangeAsync(
+ document, normalizedEdits, cancellationToken).ConfigureAwait(false);
+
+ CopilotChangeAnalysisUtilities.LogCopilotChangeAnalysis(
+ featureId, accepted, proposalId, analysisResult, cancellationToken).Dispose();
+ }
+
+ private static ImmutableArray Normalize(IEnumerable textChanges)
+ {
+ using var _ = PooledObjects.ArrayBuilder.GetInstance(out var builder);
+ foreach (var textChange in textChanges)
+ builder.Add(textChange);
+
+ // Ensure everything is sorted.
+ builder.Sort(static (c1, c2) => c1.Span.Start - c2.Span.Start);
+
+ // Now, go through and make sure no edit overlaps another.
+ for (int i = 1, n = builder.Count; i < n; i++)
+ {
+ var lastEdit = builder[i - 1];
+ var currentEdit = builder[i];
+
+ if (lastEdit.Span.OverlapsWith(currentEdit.Span))
+ return default;
+ }
+
+ // Things look good. Can process these sorted edits.
+ return builder.ToImmutableAndClear();
+ }
+
+ public static IDisposable LogCopilotChangeAnalysis(
+ string featureId, bool accepted, string proposalId, CopilotChangeAnalysis analysisResult, CancellationToken cancellationToken)
+ {
+ return Logger.LogBlock(FunctionId.Copilot_AnalyzeChange, KeyValueLogMessage.Create(d =>
+ {
+ d["Accepted"] = accepted;
+ d["FeatureId"] = featureId;
+ d["ProposalId"] = proposalId;
+
+ d["Succeeded"] = analysisResult.Succeeded;
+
+ d["OldDocumentLength"] = analysisResult.OldDocumentLength;
+ d["NewDocumentLength"] = analysisResult.NewDocumentLength;
+ d["TextChangeDelta"] = analysisResult.TextChangeDelta;
+
+ d["ProjectDocumentCount"] = analysisResult.ProjectDocumentCount;
+ d["ProjectSourceGeneratedDocumentCount"] = analysisResult.ProjectSourceGeneratedDocumentCount;
+ d["ProjectConeCount"] = analysisResult.ProjectConeCount;
+
+ foreach (var diagnosticAnalysis in analysisResult.DiagnosticAnalyses)
+ {
+ var keyPrefix = $"DiagnosticAnalysis_{diagnosticAnalysis.Kind}";
+
+ d[$"{keyPrefix}_ComputationTime"] = Stringify(diagnosticAnalysis.ComputationTime);
+ d[$"{keyPrefix}_IdToCount"] = StringifyDictionary(diagnosticAnalysis.IdToCount);
+ d[$"{keyPrefix}_CategoryToCount"] = StringifyDictionary(diagnosticAnalysis.CategoryToCount);
+ d[$"{keyPrefix}_SeverityToCount"] = StringifyDictionary(diagnosticAnalysis.SeverityToCount);
+ }
+
+ d["CodeFixAnalysis_TotalComputationTime"] = Stringify(analysisResult.CodeFixAnalysis.TotalComputationTime);
+ d["CodeFixAnalysis_TotalApplicationTime"] = Stringify(analysisResult.CodeFixAnalysis.TotalApplicationTime);
+ d["CodeFixAnalysis_DiagnosticIdToCount"] = StringifyDictionary(analysisResult.CodeFixAnalysis.DiagnosticIdToCount);
+ d["CodeFixAnalysis_DiagnosticIdToApplicationTime"] = StringifyDictionary(analysisResult.CodeFixAnalysis.DiagnosticIdToApplicationTime);
+ d["CodeFixAnalysis_DiagnosticIdToProviderName"] = StringifyDictionary(analysisResult.CodeFixAnalysis.DiagnosticIdToProviderName);
+ d["CodeFixAnalysis_ProviderNameToApplicationTime"] = StringifyDictionary(analysisResult.CodeFixAnalysis.ProviderNameToApplicationTime);
+ d["CodeFixAnalysis_ProviderNameToHasConflict"] = StringifyDictionary(analysisResult.CodeFixAnalysis.ProviderNameToHasConflict);
+ }),
+ cancellationToken);
+ }
+
+ private static string StringifyDictionary(Dictionary dictionary) where TKey : notnull where TValue : notnull
+ => string.Join(",", dictionary.Select(kvp => FormattableString.Invariant($"{kvp.Key}_{Stringify(kvp.Value)}")).OrderBy(v => v));
+
+ private static string Stringify(TValue value) where TValue : notnull
+ {
+ if (value is IEnumerable strings)
+ return string.Join(":", strings.OrderBy(v => v));
+
+ if (value is TimeSpan timeSpan)
+ return timeSpan.TotalMilliseconds.ToString("G17");
+
+ return value.ToString() ?? "";
+ }
+}
diff --git a/src/Features/Core/Portable/Copilot/CopilotOptions.cs b/src/Features/Core/Portable/Copilot/CopilotOptions.cs
new file mode 100644
index 0000000000000..e5d68f2f3b96d
--- /dev/null
+++ b/src/Features/Core/Portable/Copilot/CopilotOptions.cs
@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.CodeAnalysis.Options;
+
+namespace Microsoft.CodeAnalysis.Copilot;
+
+internal static class CopilotOptions
+{
+ public static Option2 AnalyzeCopilotChanges { get; } = new Option2("dotnet_analyze_copilot_changes", defaultValue: false);
+}
diff --git a/src/Features/Core/Portable/Copilot/ICopilotChangeAnalysisService.cs b/src/Features/Core/Portable/Copilot/ICopilotChangeAnalysisService.cs
new file mode 100644
index 0000000000000..f4e4f8e626e36
--- /dev/null
+++ b/src/Features/Core/Portable/Copilot/ICopilotChangeAnalysisService.cs
@@ -0,0 +1,367 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// 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.Composition;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Host;
+using Microsoft.CodeAnalysis.Host.Mef;
+using Microsoft.CodeAnalysis.PooledObjects;
+using Microsoft.CodeAnalysis.Remote;
+using Microsoft.CodeAnalysis.Shared;
+using Microsoft.CodeAnalysis.Shared.Collections;
+using Microsoft.CodeAnalysis.Shared.Extensions;
+using Microsoft.CodeAnalysis.Shared.Utilities;
+using Microsoft.CodeAnalysis.Text;
+using Microsoft.CodeAnalysis.Threading;
+using Roslyn.Utilities;
+
+namespace Microsoft.CodeAnalysis.Copilot;
+
+internal interface ICopilotChangeAnalysisService : IWorkspaceService
+{
+ ///
+ /// Kicks of work to analyze a change that copilot suggested making to a document. is
+ /// the state of the document prior to the edits, and are the changes Copilot wants to
+ /// make to it. must be sorted and normalized before calling this.
+ ///
+ Task AnalyzeChangeAsync(
+ Document document, ImmutableArray changes, CancellationToken cancellationToken);
+}
+
+[ExportWorkspaceService(typeof(ICopilotChangeAnalysisService)), Shared]
+[method: ImportingConstructor]
+[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
+internal sealed class DefaultCopilotChangeAnalysisService(
+ ICodeFixService codeFixService) : ICopilotChangeAnalysisService
+{
+ private const string RoslynPrefix = "Microsoft.CodeAnalysis.";
+
+ private readonly ICodeFixService _codeFixService = codeFixService;
+
+ private static bool IsSorted(ImmutableArray array, Comparison comparison)
+ => array.IsSorted(Comparer.Create(comparison));
+
+ public async Task AnalyzeChangeAsync(
+ Document document,
+ ImmutableArray changes,
+ CancellationToken cancellationToken)
+ {
+ Contract.ThrowIfFalse(document.SupportsSemanticModel);
+
+ Contract.ThrowIfTrue(!IsSorted(changes, static (c1, c2) => c1.Span.Start - c2.Span.Start), "'changes' was not sorted.");
+ Contract.ThrowIfTrue(new NormalizedTextSpanCollection(changes.Select(c => c.Span)).Count != changes.Length, "'changes' was not normalized.");
+
+ var client = await RemoteHostClient.TryGetClientAsync(document.Project, cancellationToken).ConfigureAwait(false);
+
+ if (client != null)
+ {
+ var value = await client.TryInvokeAsync(
+ // Don't need to sync the entire solution over. Just the cone of projects this document it contained within.
+ document.Project,
+ (service, checksum, cancellationToken) => service.AnalyzeChangeAsync(
+ checksum, document.Id, changes, cancellationToken),
+ cancellationToken).ConfigureAwait(false);
+ return value.HasValue ? value.Value : default;
+ }
+ else
+ {
+ return await AnalyzeChangeInCurrentProcessAsync(
+ document, changes, cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ private async Task AnalyzeChangeInCurrentProcessAsync(
+ Document document,
+ ImmutableArray changes,
+ CancellationToken cancellationToken)
+ {
+ // Keep track of how long our analysis takes entirely.
+ var totalAnalysisTimeStopWatch = SharedStopwatch.StartNew();
+
+ var forkingTimeStopWatch = SharedStopwatch.StartNew();
+
+ // Fork the starting document with the changes copilot wants to make. Keep track of where the edited spans
+ // move to in the forked doucment, as that is what we will want to analyze.
+ var oldText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
+ var newText = oldText.WithChanges(changes);
+
+ var newDocument = document.WithText(newText);
+
+ // Get the semantic model and keep it alive so none of the work we do causes it to be dropped.
+ var semanticModel = await newDocument.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
+ var forkingTime = forkingTimeStopWatch.Elapsed;
+
+ var totalDelta = 0;
+ using var _ = ArrayBuilder.GetInstance(out var newSpans);
+
+ foreach (var change in changes)
+ {
+ var newTextLength = change.NewText!.Length;
+
+ newSpans.Add(new TextSpan(change.Span.Start + totalDelta, newTextLength));
+ totalDelta += newTextLength - change.Span.Length;
+ }
+
+ // First, determine the diagnostics produced in the edits that copilot makes. Done non-concurrently with
+ // ComputeCodeFixAnalysisAsync as we want good data on just how long it takes to even compute the varying
+ // types of diagnostics, without contending with the code fix analysis.
+ var totalDiagnosticComputationTimeStopWatch = SharedStopwatch.StartNew();
+ var diagnosticAnalyses = await ComputeAllDiagnosticAnalysesAsync(
+ newDocument, newSpans, cancellationToken).ConfigureAwait(false);
+ var totalDiagnosticComputationTime = totalDiagnosticComputationTimeStopWatch.Elapsed;
+
+ // After computing diagnostics, do another analysis pass to see if we would have been able to fixup any of
+ // the code copilot produced.
+ var codeFixAnalysis = await ComputeCodeFixAnalysisAsync(
+ newDocument, newSpans, cancellationToken).ConfigureAwait(false);
+
+ var totalAnalysisTime = totalAnalysisTimeStopWatch.Elapsed;
+
+ var sourceGeneratedDocuments = await newDocument.Project.GetSourceGeneratedDocumentsAsync(cancellationToken).ConfigureAwait(false);
+
+ var projectDocumentCount = newDocument.Project.DocumentIds.Count;
+ var projectSourceGeneratedDocumentCount = sourceGeneratedDocuments.Count();
+ var projectConeCount = 1 + document.Project.Solution
+ .GetProjectDependencyGraph()
+ .GetProjectsThatThisProjectTransitivelyDependsOn(document.Project.Id).Count;
+
+ GC.KeepAlive(semanticModel);
+
+ return new CopilotChangeAnalysis(
+ Succeeded: true,
+ OldDocumentLength: oldText.Length,
+ NewDocumentLength: newText.Length,
+ TextChangeDelta: totalDelta,
+ ProjectDocumentCount: projectDocumentCount,
+ ProjectSourceGeneratedDocumentCount: projectSourceGeneratedDocumentCount,
+ ProjectConeCount: projectConeCount,
+ TotalAnalysisTime: totalAnalysisTime,
+ ForkingTime: forkingTime,
+ TotalDiagnosticComputationTime: totalDiagnosticComputationTime,
+ diagnosticAnalyses,
+ codeFixAnalysis);
+ }
+
+ private static CodeAction GetFirstAction(CodeFix codeFix)
+ {
+ var action = codeFix.Action;
+ while (action is { NestedCodeActions: [var nestedAction, ..] })
+ action = nestedAction;
+
+ return action;
+ }
+
+ private static void IncrementCount(Dictionary map, TKey key) where TKey : notnull
+ {
+ map.TryGetValue(key, out var idCount);
+ map[key] = idCount + 1;
+ }
+
+ private static void IncrementElapsedTime(Dictionary map, TKey key, TimeSpan elapsed) where TKey : notnull
+ {
+ map.TryGetValue(key, out var currentElapsed);
+ map[key] = currentElapsed + elapsed;
+ }
+
+ private static Task> ComputeAllDiagnosticAnalysesAsync(
+ Document newDocument,
+ ArrayBuilder newSpans,
+ CancellationToken cancellationToken)
+ {
+ // Compute the data in parallel for each diagnostic kind.
+ return ProducerConsumer.RunParallelAsync(
+ [DiagnosticKind.CompilerSyntax, DiagnosticKind.CompilerSemantic, DiagnosticKind.AnalyzerSyntax, DiagnosticKind.AnalyzerSemantic],
+ static async (diagnosticKind, callback, args, cancellationToken) =>
+ {
+ var (newDocument, newSpans) = args;
+
+ var computationTime = SharedStopwatch.StartNew();
+
+ // Compute the diagnostics.
+ var diagnostics = await ComputeDiagnosticsAsync(
+ newDocument, newSpans, diagnosticKind, cancellationToken).ConfigureAwait(false);
+
+ // Collect the data to report as telemetry.
+ var idToCount = new Dictionary();
+ var categoryToCount = new Dictionary();
+ var severityToCount = new Dictionary();
+
+ foreach (var diagnostic in diagnostics)
+ {
+ IncrementCount(idToCount, diagnostic.Id);
+ IncrementCount(categoryToCount, diagnostic.Category);
+ IncrementCount(severityToCount, diagnostic.Severity);
+ }
+
+ callback(new CopilotDiagnosticAnalysis(
+ diagnosticKind,
+ computationTime.Elapsed,
+ idToCount,
+ categoryToCount,
+ severityToCount));
+ },
+ args: (newDocument, newSpans),
+ cancellationToken);
+
+ static Task> ComputeDiagnosticsAsync(
+ Document newDocument,
+ ArrayBuilder newSpans,
+ DiagnosticKind diagnosticKind,
+ CancellationToken cancellationToken)
+ {
+ // Get diagnostics in parallel for all edited spans, for the desired diagnostic kind.
+ return ProducerConsumer.RunParallelAsync(
+ newSpans,
+ static async (span, callback, args, cancellationToken) =>
+ {
+ var (newDocument, diagnosticKind) = args;
+ var diagnosticAnalyzerService = newDocument.Project.Solution.Services.GetRequiredService();
+ var diagnostics = await diagnosticAnalyzerService.GetDiagnosticsForSpanAsync(
+ newDocument, span, diagnosticKind, cancellationToken).ConfigureAwait(false);
+ foreach (var diagnostic in diagnostics)
+ {
+ // Ignore supressed and hidden diagnostics. These are things the user has said they do not
+ // care about and would then have no interest in being auto fixed.
+ if (IsVisibleDiagnostic(diagnostic.IsSuppressed, diagnostic.Severity))
+ callback(diagnostic);
+ }
+ },
+ args: (newDocument, diagnosticKind),
+ cancellationToken);
+ }
+ }
+
+ private static bool IsVisibleDiagnostic(bool isSuppressed, DiagnosticSeverity severity)
+ => !isSuppressed && severity != DiagnosticSeverity.Hidden;
+
+ private async Task ComputeCodeFixAnalysisAsync(
+ Document newDocument,
+ ArrayBuilder newSpans,
+ CancellationToken cancellationToken)
+ {
+ // Determine how long it would be to even compute code fixes for these changed regions.
+ var totalComputationStopWatch = SharedStopwatch.StartNew();
+ var codeFixCollections = await ComputeCodeFixCollectionsAsync().ConfigureAwait(false);
+ var totalComputationTime = totalComputationStopWatch.Elapsed;
+
+ var diagnosticIdToCount = new Dictionary();
+ var diagnosticIdToApplicationTime = new Dictionary();
+ var diagnosticIdToProviderName = new Dictionary>();
+ var providerNameToApplicationTime = new Dictionary();
+ var providerNameToHasConflict = new Dictionary();
+
+ var totalApplicationTimeStopWatch = SharedStopwatch.StartNew();
+ await ProducerConsumer<(CodeFixCollection collection, TimeSpan elapsedTime)>.RunParallelAsync(
+ codeFixCollections,
+ produceItems: static async (codeFixCollection, callback, args, cancellationToken) =>
+ {
+ var (@this, solution, _, _, _, _, _) = args;
+ var firstAction = GetFirstAction(codeFixCollection.Fixes[0]);
+
+ var applicationTimeStopWatch = SharedStopwatch.StartNew();
+ var result = await firstAction.GetPreviewOperationsAsync(solution, cancellationToken).ConfigureAwait(false);
+ callback((codeFixCollection, applicationTimeStopWatch.Elapsed));
+ },
+ consumeItems: static async (values, args, cancellationToken) =>
+ {
+ var (@this, solution, diagnosticIdToCount, diagnosticIdToApplicationTime, diagnosticIdToProviderName, providerNameToApplicationTime, providerNameToHasConflict) = args;
+
+ // Track which text span each code fix says it will be fixing. We can use this to efficiently determine
+ // which codefixes 'conflict' with some other codefix (in that that multiple features think they can fix
+ // the same span of code). We would need some mechanism to determine which we would prefer to take in
+ // order to have a good experience in such a case.
+ var intervalTree = new SimpleMutableIntervalTree(new CodeFixCollectionIntervalIntrospector());
+
+ await foreach (var (codeFixCollection, applicationTime) in values)
+ {
+ var diagnosticId = codeFixCollection.FirstDiagnostic.Id;
+ var providerName = GetProviderName(codeFixCollection);
+
+ IncrementCount(diagnosticIdToCount, diagnosticId);
+ IncrementElapsedTime(diagnosticIdToApplicationTime, diagnosticId, applicationTime);
+ diagnosticIdToProviderName.MultiAdd(diagnosticId, providerName);
+ IncrementElapsedTime(providerNameToApplicationTime, providerName, applicationTime);
+
+ intervalTree.AddIntervalInPlace(codeFixCollection);
+ }
+
+ // Now go over the fixed spans and see which intersect with other spans
+ using var intersectingCollections = TemporaryArray.Empty;
+ foreach (var codeFixCollection in intervalTree)
+ {
+ intersectingCollections.Clear();
+ intervalTree.FillWithIntervalsThatIntersectWith(
+ codeFixCollection.TextSpan.Start,
+ codeFixCollection.TextSpan.Length,
+ ref intersectingCollections.AsRef());
+
+ var providerName = GetProviderName(codeFixCollection);
+
+ // >= 2 because we want to see how many total fixers fix a particular span, and we only care if
+ // we're seeing multiple.
+ var newHasConflictValue = intersectingCollections.Count >= 2;
+ var storedHasConflictValue = providerNameToHasConflict.TryGetValue(providerName, out var currentHasConflictValue) && currentHasConflictValue;
+
+ providerNameToHasConflict[providerName] = storedHasConflictValue || newHasConflictValue;
+ }
+ },
+ args: (@this: this, newDocument.Project.Solution, diagnosticIdToCount, diagnosticIdToApplicationTime, diagnosticIdToProviderName, providerNameToApplicationTime, providerNameToHasConflict),
+ cancellationToken).ConfigureAwait(false);
+ var totalApplicationTime = totalApplicationTimeStopWatch.Elapsed;
+
+ return new CopilotCodeFixAnalysis(
+ totalComputationTime,
+ totalApplicationTime,
+ diagnosticIdToCount,
+ diagnosticIdToApplicationTime,
+ diagnosticIdToProviderName,
+ providerNameToApplicationTime,
+ providerNameToHasConflict);
+
+ Task> ComputeCodeFixCollectionsAsync()
+ {
+ return ProducerConsumer.RunParallelAsync(
+ newSpans,
+ static async (span, callback, args, cancellationToken) =>
+ {
+ var (@this, newDocument) = args;
+ await foreach (var codeFixCollection in @this._codeFixService.StreamFixesAsync(
+ newDocument, span, cancellationToken).ConfigureAwait(false))
+ {
+ // Ignore the suppress/configure codefixes that are almost always present.
+ // We would not ever want to apply those to a copilot change.
+ if (codeFixCollection is
+ {
+ Provider: not IConfigurationFixProvider,
+ Fixes: [var codeFix, ..],
+ } &&
+ IsVisibleDiagnostic(codeFix.PrimaryDiagnostic.IsSuppressed, codeFix.PrimaryDiagnostic.Severity) &&
+ (codeFixCollection.Provider.GetType().Namespace ?? "").StartsWith(RoslynPrefix))
+ {
+ callback(codeFixCollection);
+ }
+ }
+ },
+ args: (@this: this, newDocument),
+ cancellationToken);
+ }
+
+ static string GetProviderName(CodeFixCollection codeFixCollection)
+ => codeFixCollection.Provider.GetType().FullName![RoslynPrefix.Length..];
+ }
+
+ private readonly struct CodeFixCollectionIntervalIntrospector : IIntervalIntrospector
+ {
+ public TextSpan GetSpan(CodeFixCollection value)
+ => value.TextSpan;
+ }
+}
diff --git a/src/Features/Core/Portable/Copilot/IRemoteCopilotChangeAnalysisService.cs b/src/Features/Core/Portable/Copilot/IRemoteCopilotChangeAnalysisService.cs
new file mode 100644
index 0000000000000..d7cb6a1305e19
--- /dev/null
+++ b/src/Features/Core/Portable/Copilot/IRemoteCopilotChangeAnalysisService.cs
@@ -0,0 +1,20 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// 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.Immutable;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Host;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Microsoft.CodeAnalysis.Copilot;
+
+/// Remote version of
+internal interface IRemoteCopilotChangeAnalysisService : IWorkspaceService
+{
+ ///
+ ValueTask AnalyzeChangeAsync(
+ Checksum solutionChecksum, DocumentId documentId, ImmutableArray edits, CancellationToken cancellationToken);
+}
diff --git a/src/Features/Core/Portable/Diagnostics/CodeAnalysisDiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/CodeAnalysisDiagnosticAnalyzerService.cs
index 6776c555c1283..fcff353750e2e 100644
--- a/src/Features/Core/Portable/Diagnostics/CodeAnalysisDiagnosticAnalyzerService.cs
+++ b/src/Features/Core/Portable/Diagnostics/CodeAnalysisDiagnosticAnalyzerService.cs
@@ -22,10 +22,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics;
internal sealed class CodeAnalysisDiagnosticAnalyzerServiceFactory() : IWorkspaceServiceFactory
{
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
- {
- var diagnosticAnalyzerService = workspaceServices.SolutionServices.ExportProvider.GetExports().Single().Value;
- return new CodeAnalysisDiagnosticAnalyzerService(diagnosticAnalyzerService, workspaceServices.Workspace);
- }
+ => new CodeAnalysisDiagnosticAnalyzerService(workspaceServices.Workspace);
private sealed class CodeAnalysisDiagnosticAnalyzerService : ICodeAnalysisDiagnosticAnalyzerService
{
@@ -49,11 +46,10 @@ private sealed class CodeAnalysisDiagnosticAnalyzerService : ICodeAnalysisDiagno
private readonly ConcurrentSet _clearedProjectIds = [];
public CodeAnalysisDiagnosticAnalyzerService(
- IDiagnosticAnalyzerService diagnosticAnalyzerService,
Workspace workspace)
{
- _diagnosticAnalyzerService = diagnosticAnalyzerService;
_workspace = workspace;
+ _diagnosticAnalyzerService = _workspace.Services.GetRequiredService();
_workspace.WorkspaceChanged += OnWorkspaceChanged;
}
diff --git a/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs
index 3ce287befb209..1a9e32b133d80 100644
--- a/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs
+++ b/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs
@@ -7,11 +7,12 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Diagnostics;
-internal interface IDiagnosticAnalyzerService
+internal interface IDiagnosticAnalyzerService : IWorkspaceService
{
///
/// Provides and caches analyzer information.
diff --git a/src/Features/Core/Portable/Diagnostics/IDiagnosticsRefresher.cs b/src/Features/Core/Portable/Diagnostics/IDiagnosticsRefresher.cs
index e185068a39c34..dbfce0abd2433 100644
--- a/src/Features/Core/Portable/Diagnostics/IDiagnosticsRefresher.cs
+++ b/src/Features/Core/Portable/Diagnostics/IDiagnosticsRefresher.cs
@@ -3,6 +3,9 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Composition;
+using System.Threading;
+using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.CodeAnalysis.Diagnostics;
@@ -26,3 +29,27 @@ internal interface IDiagnosticsRefresher
///
int GlobalStateVersion { get; }
}
+
+[Export(typeof(IDiagnosticsRefresher)), Shared]
+[method: ImportingConstructor]
+[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
+internal sealed class DefaultDiagnosticsRefresher() : IDiagnosticsRefresher
+{
+ ///
+ /// Incremented every time a refresh is requested.
+ ///
+ private int _globalStateVersion;
+
+ public event Action? WorkspaceRefreshRequested;
+
+ public void RequestWorkspaceRefresh()
+ {
+ // bump version before sending the request to the client:
+ Interlocked.Increment(ref _globalStateVersion);
+
+ WorkspaceRefreshRequested?.Invoke();
+ }
+
+ public int GlobalStateVersion
+ => _globalStateVersion;
+}
diff --git a/src/LanguageServer/Protocol/Features/Options/DiagnosticOptionsStorage.cs b/src/Features/Core/Portable/Diagnostics/Options/DiagnosticOptionsStorage.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/Options/DiagnosticOptionsStorage.cs
rename to src/Features/Core/Portable/Diagnostics/Options/DiagnosticOptionsStorage.cs
diff --git a/src/LanguageServer/Protocol/Features/Options/SolutionCrawlerOptionsStorage.cs b/src/Features/Core/Portable/Diagnostics/Options/SolutionCrawlerOptionsStorage.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/Options/SolutionCrawlerOptionsStorage.cs
rename to src/Features/Core/Portable/Diagnostics/Options/SolutionCrawlerOptionsStorage.cs
diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/Service/DiagnosticAnalyzerService.cs
similarity index 64%
rename from src/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs
rename to src/Features/Core/Portable/Diagnostics/Service/DiagnosticAnalyzerService.cs
index d70c50f09b744..0586c1bbe6bc4 100644
--- a/src/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs
+++ b/src/Features/Core/Portable/Diagnostics/Service/DiagnosticAnalyzerService.cs
@@ -5,22 +5,41 @@
using System;
using System.Collections.Immutable;
using System.Composition;
-using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeStyle;
+using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.CodeAnalysis.Text;
-using Microsoft.VisualStudio.Threading;
+using Microsoft.CodeAnalysis.Threading;
namespace Microsoft.CodeAnalysis.Diagnostics
{
- [Export(typeof(IDiagnosticAnalyzerService)), Shared]
- internal partial class DiagnosticAnalyzerService : IDiagnosticAnalyzerService
+ [ExportWorkspaceServiceFactory(typeof(IDiagnosticAnalyzerService)), Shared]
+ [method: ImportingConstructor]
+ [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
+ internal sealed class DiagnosticAnalyzerServiceFactory(
+ IGlobalOptionService globalOptions,
+ IDiagnosticsRefresher diagnosticsRefresher,
+ DiagnosticAnalyzerInfoCache.SharedGlobalCache globalCache,
+ [Import(AllowDefault = true)] IAsynchronousOperationListenerProvider? listenerProvider) : IWorkspaceServiceFactory
+ {
+ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
+ {
+ return new DiagnosticAnalyzerService(
+ globalOptions,
+ diagnosticsRefresher,
+ globalCache,
+ listenerProvider,
+ workspaceServices.Workspace);
+ }
+ }
+
+ internal sealed partial class DiagnosticAnalyzerService : IDiagnosticAnalyzerService
{
private static readonly Option2 s_crashOnAnalyzerException = new("dotnet_crash_on_analyzer_exception", defaultValue: false);
@@ -29,23 +48,21 @@ internal partial class DiagnosticAnalyzerService : IDiagnosticAnalyzerService
public IAsynchronousOperationListener Listener { get; }
private IGlobalOptionService GlobalOptions { get; }
- private readonly ConditionalWeakTable _map = new();
- private readonly ConditionalWeakTable.CreateValueCallback _createIncrementalAnalyzer;
private readonly IDiagnosticsRefresher _diagnosticsRefresher;
+ private readonly DiagnosticIncrementalAnalyzer _incrementalAnalyzer;
- [ImportingConstructor]
- [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public DiagnosticAnalyzerService(
- IAsynchronousOperationListenerProvider listenerProvider,
- DiagnosticAnalyzerInfoCache.SharedGlobalCache globalCache,
IGlobalOptionService globalOptions,
- IDiagnosticsRefresher diagnosticsRefresher)
+ IDiagnosticsRefresher diagnosticsRefresher,
+ DiagnosticAnalyzerInfoCache.SharedGlobalCache globalCache,
+ IAsynchronousOperationListenerProvider? listenerProvider,
+ Workspace workspace)
{
AnalyzerInfoCache = globalCache.AnalyzerInfoCache;
- Listener = listenerProvider.GetListener(FeatureAttribute.DiagnosticService);
+ Listener = listenerProvider?.GetListener(FeatureAttribute.DiagnosticService) ?? AsynchronousOperationListenerProvider.NullListener;
GlobalOptions = globalOptions;
_diagnosticsRefresher = diagnosticsRefresher;
- _createIncrementalAnalyzer = CreateIncrementalAnalyzerCallback;
+ _incrementalAnalyzer = new DiagnosticIncrementalAnalyzer(this, AnalyzerInfoCache, this.GlobalOptions);
globalOptions.AddOptionChangedHandler(this, (_, _, e) =>
{
@@ -54,6 +71,10 @@ public DiagnosticAnalyzerService(
RequestDiagnosticRefresh();
}
});
+
+ // When the workspace changes what context a document is in (when a user picks a different tfm to view the
+ // document in), kick off a refresh so that diagnostics properly update in the task list and editor.
+ workspace.DocumentActiveContextChanged += (_, _) => RequestDiagnosticRefresh();
}
public static Task GetDiagnosticVersionAsync(Project project, CancellationToken cancellationToken)
@@ -87,27 +108,21 @@ public async Task> GetDiagnosticsForSpanAsync(
bool isExplicit,
CancellationToken cancellationToken)
{
- var analyzer = CreateIncrementalAnalyzer(document.Project.Solution.Workspace);
-
// always make sure that analyzer is called on background thread.
- await TaskScheduler.Default;
+ await Task.Yield().ConfigureAwait(false);
priorityProvider ??= new DefaultCodeActionRequestPriorityProvider();
- return await analyzer.GetDiagnosticsForSpanAsync(
+ return await _incrementalAnalyzer.GetDiagnosticsForSpanAsync(
document, range, shouldIncludeDiagnostic, priorityProvider, diagnosticKinds, isExplicit, cancellationToken).ConfigureAwait(false);
}
- public async Task> ForceAnalyzeProjectAsync(Project project, CancellationToken cancellationToken)
- {
- var analyzer = CreateIncrementalAnalyzer(project.Solution.Workspace);
- return await analyzer.ForceAnalyzeProjectAsync(project, cancellationToken).ConfigureAwait(false);
- }
+ public Task> ForceAnalyzeProjectAsync(Project project, CancellationToken cancellationToken)
+ => _incrementalAnalyzer.ForceAnalyzeProjectAsync(project, cancellationToken);
public Task> GetDiagnosticsForIdsAsync(
Project project, DocumentId? documentId, ImmutableHashSet? diagnosticIds, Func? shouldIncludeAnalyzer, bool includeLocalDocumentDiagnostics, bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken)
{
- var analyzer = CreateIncrementalAnalyzer(project.Solution.Workspace);
- return analyzer.GetDiagnosticsForIdsAsync(project, documentId, diagnosticIds, shouldIncludeAnalyzer, includeLocalDocumentDiagnostics, includeNonLocalDocumentDiagnostics, cancellationToken);
+ return _incrementalAnalyzer.GetDiagnosticsForIdsAsync(project, documentId, diagnosticIds, shouldIncludeAnalyzer, includeLocalDocumentDiagnostics, includeNonLocalDocumentDiagnostics, cancellationToken);
}
public Task> GetProjectDiagnosticsForIdsAsync(
@@ -115,8 +130,7 @@ public Task> GetProjectDiagnosticsForIdsAsync(
Func? shouldIncludeAnalyzer,
bool includeNonLocalDocumentDiagnostics, CancellationToken cancellationToken)
{
- var analyzer = CreateIncrementalAnalyzer(project.Solution.Workspace);
- return analyzer.GetProjectDiagnosticsForIdsAsync(project, diagnosticIds, shouldIncludeAnalyzer, includeNonLocalDocumentDiagnostics, cancellationToken);
+ return _incrementalAnalyzer.GetProjectDiagnosticsForIdsAsync(project, diagnosticIds, shouldIncludeAnalyzer, includeNonLocalDocumentDiagnostics, cancellationToken);
}
public TestAccessor GetTestAccessor()
@@ -125,9 +139,7 @@ public TestAccessor GetTestAccessor()
public readonly struct TestAccessor(DiagnosticAnalyzerService service)
{
public Task> GetAnalyzersAsync(Project project, CancellationToken cancellationToken)
- {
- return service.CreateIncrementalAnalyzer(project.Solution.Workspace).GetAnalyzersForTestingPurposesOnlyAsync(project, cancellationToken);
- }
+ => service._incrementalAnalyzer.GetAnalyzersForTestingPurposesOnlyAsync(project, cancellationToken);
}
}
}
diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/DocumentAnalysisExecutor.cs b/src/Features/Core/Portable/Diagnostics/Service/DocumentAnalysisExecutor.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/Diagnostics/DocumentAnalysisExecutor.cs
rename to src/Features/Core/Portable/Diagnostics/Service/DocumentAnalysisExecutor.cs
diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/DocumentAnalysisExecutor_Helpers.cs b/src/Features/Core/Portable/Diagnostics/Service/DocumentAnalysisExecutor_Helpers.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/Diagnostics/DocumentAnalysisExecutor_Helpers.cs
rename to src/Features/Core/Portable/Diagnostics/Service/DocumentAnalysisExecutor_Helpers.cs
diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.CompilationManager.cs b/src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.CompilationManager.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.CompilationManager.cs
rename to src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.CompilationManager.cs
diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs b/src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs
rename to src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs
diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.HostAnalyzerInfo.cs b/src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.HostAnalyzerInfo.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.HostAnalyzerInfo.cs
rename to src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.HostAnalyzerInfo.cs
diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer.cs b/src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer.cs
rename to src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer.cs
diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer_MemberSpans.cs b/src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer_MemberSpans.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer_MemberSpans.cs
rename to src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer_MemberSpans.cs
diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.ProjectStates.cs b/src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.ProjectStates.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.ProjectStates.cs
rename to src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.ProjectStates.cs
diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.cs b/src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.cs
rename to src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.StateManager.cs
diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs b/src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs
rename to src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer.cs
diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs b/src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs
rename to src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnostics.cs
diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs b/src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs
rename to src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs
diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs b/src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs
rename to src/Features/Core/Portable/Diagnostics/Service/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs
diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/InProcOrRemoteHostAnalyzerRunner.cs b/src/Features/Core/Portable/Diagnostics/Service/EngineV2/InProcOrRemoteHostAnalyzerRunner.cs
similarity index 100%
rename from src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/InProcOrRemoteHostAnalyzerRunner.cs
rename to src/Features/Core/Portable/Diagnostics/Service/EngineV2/InProcOrRemoteHostAnalyzerRunner.cs
diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptDiagnosticAnalyzerService.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptDiagnosticAnalyzerService.cs
index 305b32beb9fdd..7f5f386c57b96 100644
--- a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptDiagnosticAnalyzerService.cs
+++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptDiagnosticAnalyzerService.cs
@@ -3,22 +3,19 @@
// See the LICENSE file in the project root for more information.
using System;
-using System.Composition;
-using Microsoft.CodeAnalysis.Host.Mef;
-using Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api;
using System.Collections.Generic;
+using System.Composition;
using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api;
+using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript;
-[Shared]
-[Export(typeof(IVSTypeScriptDiagnosticAnalyzerService))]
+[Export(typeof(IVSTypeScriptDiagnosticAnalyzerService)), Shared]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
-internal sealed class VSTypeScriptAnalyzerService(IDiagnosticAnalyzerService service) : IVSTypeScriptDiagnosticAnalyzerService
+internal sealed class VSTypeScriptAnalyzerService(IDiagnosticsRefresher refresher) : IVSTypeScriptDiagnosticAnalyzerService
{
- private readonly IDiagnosticAnalyzerService _service = service;
-
public void Reanalyze(Workspace? workspace, IEnumerable? projectIds, IEnumerable? documentIds, bool highPriority)
- => _service.RequestDiagnosticRefresh();
+ => refresher.RequestWorkspaceRefresh();
}
diff --git a/src/LanguageServer/Protocol.TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs b/src/LanguageServer/Protocol.TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs
index 7dd8669e53a19..2eebf43a6fd47 100644
--- a/src/LanguageServer/Protocol.TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs
+++ b/src/LanguageServer/Protocol.TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs
@@ -25,9 +25,7 @@ public class TestDiagnosticAnalyzerDriver
public TestDiagnosticAnalyzerDriver(Workspace workspace, bool includeSuppressedDiagnostics = false, bool includeNonLocalDocumentDiagnostics = false)
{
- var mefServices = workspace.Services.SolutionServices.ExportProvider;
-
- _diagnosticAnalyzerService = mefServices.GetExportedValue();
+ _diagnosticAnalyzerService = workspace.Services.GetRequiredService();
_includeSuppressedDiagnostics = includeSuppressedDiagnostics;
_includeNonLocalDocumentDiagnostics = includeNonLocalDocumentDiagnostics;
}
diff --git a/src/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs b/src/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs
index 67409f355e2ae..ef20bcf28d4f8 100644
--- a/src/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs
+++ b/src/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs
@@ -19,258 +19,252 @@
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
-namespace Microsoft.CodeAnalysis.CodeCleanup
+namespace Microsoft.CodeAnalysis.CodeCleanup;
+
+internal abstract class AbstractCodeCleanupService(ICodeFixService codeFixService) : ICodeCleanupService
{
- internal abstract class AbstractCodeCleanupService : ICodeCleanupService
- {
- private readonly ICodeFixService _codeFixService;
- private readonly IDiagnosticAnalyzerService _diagnosticService;
+ private readonly ICodeFixService _codeFixService = codeFixService;
+
+ protected abstract string OrganizeImportsDescription { get; }
+ protected abstract ImmutableArray GetDiagnosticSets();
- protected AbstractCodeCleanupService(ICodeFixService codeFixService, IDiagnosticAnalyzerService diagnosticAnalyzerService)
+ public async Task CleanupAsync(
+ Document document,
+ EnabledDiagnosticOptions enabledDiagnostics,
+ IProgress progressTracker,
+ CancellationToken cancellationToken)
+ {
+ // add one item for the code fixers we get from nuget, we'll do last
+ var thirdPartyDiagnosticIdsAndTitles = ImmutableArray<(string diagnosticId, string? title)>.Empty;
+ if (enabledDiagnostics.RunThirdPartyFixers)
{
- _codeFixService = codeFixService;
- _diagnosticService = diagnosticAnalyzerService;
+ thirdPartyDiagnosticIdsAndTitles = await GetThirdPartyDiagnosticIdsAndTitlesAsync(document, cancellationToken).ConfigureAwait(false);
+ progressTracker.AddItems(thirdPartyDiagnosticIdsAndTitles.Length);
}
- protected abstract string OrganizeImportsDescription { get; }
- protected abstract ImmutableArray GetDiagnosticSets();
+ // add one item for the 'format' action
+ if (enabledDiagnostics.FormatDocument)
+ {
+ progressTracker.AddItems(1);
+ }
- public async Task CleanupAsync(
- Document document,
- EnabledDiagnosticOptions enabledDiagnostics,
- IProgress progressTracker,
- CancellationToken cancellationToken)
+ // and one for 'remove/sort usings' if we're going to run that.
+ var organizeUsings = enabledDiagnostics.OrganizeUsings.IsRemoveUnusedImportEnabled ||
+ enabledDiagnostics.OrganizeUsings.IsSortImportsEnabled;
+ if (organizeUsings)
{
- // add one item for the code fixers we get from nuget, we'll do last
- var thirdPartyDiagnosticIdsAndTitles = ImmutableArray<(string diagnosticId, string? title)>.Empty;
- if (enabledDiagnostics.RunThirdPartyFixers)
- {
- thirdPartyDiagnosticIdsAndTitles = await GetThirdPartyDiagnosticIdsAndTitlesAsync(document, cancellationToken).ConfigureAwait(false);
- progressTracker.AddItems(thirdPartyDiagnosticIdsAndTitles.Length);
- }
+ progressTracker.AddItems(1);
+ }
- // add one item for the 'format' action
- if (enabledDiagnostics.FormatDocument)
- {
- progressTracker.AddItems(1);
- }
+ if (enabledDiagnostics.Diagnostics.Any())
+ {
+ progressTracker.AddItems(enabledDiagnostics.Diagnostics.Length);
+ }
- // and one for 'remove/sort usings' if we're going to run that.
- var organizeUsings = enabledDiagnostics.OrganizeUsings.IsRemoveUnusedImportEnabled ||
- enabledDiagnostics.OrganizeUsings.IsSortImportsEnabled;
- if (organizeUsings)
- {
- progressTracker.AddItems(1);
- }
+ document = await ApplyCodeFixesAsync(
+ document, enabledDiagnostics.Diagnostics, progressTracker, cancellationToken).ConfigureAwait(false);
- if (enabledDiagnostics.Diagnostics.Any())
- {
- progressTracker.AddItems(enabledDiagnostics.Diagnostics.Length);
- }
+ if (enabledDiagnostics.RunThirdPartyFixers)
+ {
+ document = await ApplyThirdPartyCodeFixesAsync(
+ document, thirdPartyDiagnosticIdsAndTitles, progressTracker, cancellationToken).ConfigureAwait(false);
+ }
- document = await ApplyCodeFixesAsync(
- document, enabledDiagnostics.Diagnostics, progressTracker, cancellationToken).ConfigureAwait(false);
+ // do the remove usings after code fix, as code fix might remove some code which can results in unused usings.
+ if (organizeUsings)
+ {
+ progressTracker.Report(CodeAnalysisProgress.Description(this.OrganizeImportsDescription));
+ document = await RemoveSortUsingsAsync(
+ document, enabledDiagnostics.OrganizeUsings, cancellationToken).ConfigureAwait(false);
+ progressTracker.ItemCompleted();
+ }
- if (enabledDiagnostics.RunThirdPartyFixers)
- {
- document = await ApplyThirdPartyCodeFixesAsync(
- document, thirdPartyDiagnosticIdsAndTitles, progressTracker, cancellationToken).ConfigureAwait(false);
- }
+ if (enabledDiagnostics.FormatDocument)
+ {
+ var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false);
- // do the remove usings after code fix, as code fix might remove some code which can results in unused usings.
- if (organizeUsings)
+ progressTracker.Report(CodeAnalysisProgress.Description(FeaturesResources.Formatting_document));
+ using (Logger.LogBlock(FunctionId.CodeCleanup_Format, cancellationToken))
{
- progressTracker.Report(CodeAnalysisProgress.Description(this.OrganizeImportsDescription));
- document = await RemoveSortUsingsAsync(
- document, enabledDiagnostics.OrganizeUsings, cancellationToken).ConfigureAwait(false);
+ document = await Formatter.FormatAsync(document, formattingOptions, cancellationToken).ConfigureAwait(false);
progressTracker.ItemCompleted();
}
+ }
- if (enabledDiagnostics.FormatDocument)
- {
- var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false);
+ if (enabledDiagnostics.RunThirdPartyFixers)
+ {
+ document = await ApplyThirdPartyCodeFixesAsync(
+ document, thirdPartyDiagnosticIdsAndTitles, progressTracker, cancellationToken).ConfigureAwait(false);
+ }
- progressTracker.Report(CodeAnalysisProgress.Description(FeaturesResources.Formatting_document));
- using (Logger.LogBlock(FunctionId.CodeCleanup_Format, cancellationToken))
- {
- document = await Formatter.FormatAsync(document, formattingOptions, cancellationToken).ConfigureAwait(false);
- progressTracker.ItemCompleted();
- }
- }
+ return document;
+ }
- if (enabledDiagnostics.RunThirdPartyFixers)
+ private static async Task RemoveSortUsingsAsync(
+ Document document, OrganizeUsingsSet organizeUsingsSet, CancellationToken cancellationToken)
+ {
+ if (organizeUsingsSet.IsRemoveUnusedImportEnabled &&
+ document.GetLanguageService() is { } removeUsingsService)
+ {
+ using (Logger.LogBlock(FunctionId.CodeCleanup_RemoveUnusedImports, cancellationToken))
{
- document = await ApplyThirdPartyCodeFixesAsync(
- document, thirdPartyDiagnosticIdsAndTitles, progressTracker, cancellationToken).ConfigureAwait(false);
+ var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false);
+ document = await removeUsingsService.RemoveUnnecessaryImportsAsync(document, cancellationToken).ConfigureAwait(false);
}
-
- return document;
}
- private static async Task RemoveSortUsingsAsync(
- Document document, OrganizeUsingsSet organizeUsingsSet, CancellationToken cancellationToken)
+ if (organizeUsingsSet.IsSortImportsEnabled &&
+ document.GetLanguageService() is { } organizeImportsService)
{
- if (organizeUsingsSet.IsRemoveUnusedImportEnabled &&
- document.GetLanguageService() is { } removeUsingsService)
+ using (Logger.LogBlock(FunctionId.CodeCleanup_SortImports, cancellationToken))
{
- using (Logger.LogBlock(FunctionId.CodeCleanup_RemoveUnusedImports, cancellationToken))
- {
- var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false);
- document = await removeUsingsService.RemoveUnnecessaryImportsAsync(document, cancellationToken).ConfigureAwait(false);
- }
+ var organizeOptions = await document.GetOrganizeImportsOptionsAsync(cancellationToken).ConfigureAwait(false);
+ document = await organizeImportsService.OrganizeImportsAsync(document, organizeOptions, cancellationToken).ConfigureAwait(false);
}
-
- if (organizeUsingsSet.IsSortImportsEnabled &&
- document.GetLanguageService() is { } organizeImportsService)
- {
- using (Logger.LogBlock(FunctionId.CodeCleanup_SortImports, cancellationToken))
- {
- var organizeOptions = await document.GetOrganizeImportsOptionsAsync(cancellationToken).ConfigureAwait(false);
- document = await organizeImportsService.OrganizeImportsAsync(document, organizeOptions, cancellationToken).ConfigureAwait(false);
- }
- }
-
- return document;
}
- private async Task ApplyCodeFixesAsync(
- Document document, ImmutableArray enabledDiagnosticSets,
- IProgress progressTracker, CancellationToken cancellationToken)
- {
- // Add a progressTracker item for each enabled option we're going to fixup.
- foreach (var diagnosticSet in enabledDiagnosticSets)
- {
- cancellationToken.ThrowIfCancellationRequested();
+ return document;
+ }
- progressTracker.Report(CodeAnalysisProgress.Description(diagnosticSet.Description));
- document = await ApplyCodeFixesForSpecificDiagnosticIdsAsync(
- document, diagnosticSet.DiagnosticIds, diagnosticSet.IsAnyDiagnosticIdExplicitlyEnabled, progressTracker, cancellationToken).ConfigureAwait(false);
+ private async Task ApplyCodeFixesAsync(
+ Document document, ImmutableArray enabledDiagnosticSets,
+ IProgress progressTracker, CancellationToken cancellationToken)
+ {
+ // Add a progressTracker item for each enabled option we're going to fixup.
+ foreach (var diagnosticSet in enabledDiagnosticSets)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
- // Mark this option as being completed.
- progressTracker.ItemCompleted();
- }
+ progressTracker.Report(CodeAnalysisProgress.Description(diagnosticSet.Description));
+ document = await ApplyCodeFixesForSpecificDiagnosticIdsAsync(
+ document, diagnosticSet.DiagnosticIds, diagnosticSet.IsAnyDiagnosticIdExplicitlyEnabled, progressTracker, cancellationToken).ConfigureAwait(false);
- return document;
+ // Mark this option as being completed.
+ progressTracker.ItemCompleted();
}
- private async Task ApplyCodeFixesForSpecificDiagnosticIdsAsync(
- Document document, ImmutableArray diagnosticIds, bool isAnyDiagnosticIdExplicitlyEnabled, IProgress progressTracker, CancellationToken cancellationToken)
- {
- // Enable fixes for all diagnostic severities if any of the diagnostic IDs has been explicitly enabled in Code Cleanup.
- // Otherwise, only enable fixes for Warning and Error severity diagnostics.
- var minimumSeverity = isAnyDiagnosticIdExplicitlyEnabled ? DiagnosticSeverity.Hidden : DiagnosticSeverity.Warning;
-
- foreach (var diagnosticId in diagnosticIds)
- {
- using (Logger.LogBlock(FunctionId.CodeCleanup_ApplyCodeFixesAsync, diagnosticId, cancellationToken))
- {
- document = await ApplyCodeFixesForSpecificDiagnosticIdAsync(
- document, diagnosticId, minimumSeverity, progressTracker, cancellationToken).ConfigureAwait(false);
- }
- }
+ return document;
+ }
- return document;
- }
+ private async Task ApplyCodeFixesForSpecificDiagnosticIdsAsync(
+ Document document, ImmutableArray diagnosticIds, bool isAnyDiagnosticIdExplicitlyEnabled, IProgress progressTracker, CancellationToken cancellationToken)
+ {
+ // Enable fixes for all diagnostic severities if any of the diagnostic IDs has been explicitly enabled in Code Cleanup.
+ // Otherwise, only enable fixes for Warning and Error severity diagnostics.
+ var minimumSeverity = isAnyDiagnosticIdExplicitlyEnabled ? DiagnosticSeverity.Hidden : DiagnosticSeverity.Warning;
- private async Task ApplyCodeFixesForSpecificDiagnosticIdAsync(
- Document document, string diagnosticId, DiagnosticSeverity minimumSeverity, IProgress progressTracker, CancellationToken cancellationToken)
+ foreach (var diagnosticId in diagnosticIds)
{
- var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
- var textSpan = new TextSpan(0, tree.Length);
-
- var fixCollection = await _codeFixService.GetDocumentFixAllForIdInSpanAsync(
- document, textSpan, diagnosticId, minimumSeverity, cancellationToken).ConfigureAwait(false);
- if (fixCollection == null)
+ using (Logger.LogBlock(FunctionId.CodeCleanup_ApplyCodeFixesAsync, diagnosticId, cancellationToken))
{
- return document;
+ document = await ApplyCodeFixesForSpecificDiagnosticIdAsync(
+ document, diagnosticId, minimumSeverity, progressTracker, cancellationToken).ConfigureAwait(false);
}
+ }
- var fixAllService = document.Project.Solution.Services.GetRequiredService();
-
- var solution = await fixAllService.GetFixAllChangedSolutionAsync(
- new FixAllContext(fixCollection.FixAllState!, progressTracker, cancellationToken)).ConfigureAwait(false);
- Contract.ThrowIfNull(solution);
+ return document;
+ }
- return solution.GetDocument(document.Id) ?? throw new NotSupportedException(FeaturesResources.Removal_of_document_not_supported);
- }
+ private async Task ApplyCodeFixesForSpecificDiagnosticIdAsync(
+ Document document, string diagnosticId, DiagnosticSeverity minimumSeverity, IProgress progressTracker, CancellationToken cancellationToken)
+ {
+ var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
+ var textSpan = new TextSpan(0, tree.Length);
- private async Task> GetThirdPartyDiagnosticIdsAndTitlesAsync(Document document, CancellationToken cancellationToken)
+ var fixCollection = await _codeFixService.GetDocumentFixAllForIdInSpanAsync(
+ document, textSpan, diagnosticId, minimumSeverity, cancellationToken).ConfigureAwait(false);
+ if (fixCollection == null)
{
- var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
- var range = new TextSpan(0, tree.Length);
+ return document;
+ }
- // Compute diagnostics for everything that is not an IDE analyzer
- var diagnostics = await _diagnosticService.GetDiagnosticsForSpanAsync(document, range,
- shouldIncludeDiagnostic: static diagnosticId => !(IDEDiagnosticIdToOptionMappingHelper.IsKnownIDEDiagnosticId(diagnosticId)),
- priorityProvider: new DefaultCodeActionRequestPriorityProvider(),
- DiagnosticKind.All, isExplicit: false,
- cancellationToken).ConfigureAwait(false);
+ var fixAllService = document.Project.Solution.Services.GetRequiredService();
- // We don't want code cleanup automatically cleaning suppressed diagnostics.
- diagnostics = diagnostics.WhereAsArray(d => !d.IsSuppressed);
+ var solution = await fixAllService.GetFixAllChangedSolutionAsync(
+ new FixAllContext(fixCollection.FixAllState!, progressTracker, cancellationToken)).ConfigureAwait(false);
+ Contract.ThrowIfNull(solution);
- // ensure more than just known diagnostics were returned
- if (!diagnostics.Any())
- {
- return [];
- }
+ return solution.GetDocument(document.Id) ?? throw new NotSupportedException(FeaturesResources.Removal_of_document_not_supported);
+ }
- return diagnostics.SelectAsArray(static d => (d.Id, d.Title)).Distinct();
+ private async Task> GetThirdPartyDiagnosticIdsAndTitlesAsync(
+ Document document, CancellationToken cancellationToken)
+ {
+ var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
+ var range = new TextSpan(0, tree.Length);
+
+ // Compute diagnostics for everything that is not an IDE analyzer
+ var diagnosticService = document.Project.Solution.Services.GetRequiredService();
+ var diagnostics = await diagnosticService.GetDiagnosticsForSpanAsync(document, range,
+ shouldIncludeDiagnostic: static diagnosticId => !(IDEDiagnosticIdToOptionMappingHelper.IsKnownIDEDiagnosticId(diagnosticId)),
+ priorityProvider: new DefaultCodeActionRequestPriorityProvider(),
+ DiagnosticKind.All, isExplicit: false,
+ cancellationToken).ConfigureAwait(false);
+
+ // We don't want code cleanup automatically cleaning suppressed diagnostics.
+ diagnostics = diagnostics.WhereAsArray(d => !d.IsSuppressed);
+
+ // ensure more than just known diagnostics were returned
+ if (!diagnostics.Any())
+ {
+ return [];
}
- private async Task ApplyThirdPartyCodeFixesAsync(
- Document document,
- ImmutableArray<(string diagnosticId, string? title)> diagnosticIds,
- IProgress progressTracker,
- CancellationToken cancellationToken)
+ return diagnostics.SelectAsArray(static d => (d.Id, d.Title)).Distinct();
+ }
+
+ private async Task ApplyThirdPartyCodeFixesAsync(
+ Document document,
+ ImmutableArray<(string diagnosticId, string? title)> diagnosticIds,
+ IProgress progressTracker,
+ CancellationToken cancellationToken)
+ {
+ foreach (var (diagnosticId, title) in diagnosticIds)
{
- foreach (var (diagnosticId, title) in diagnosticIds)
+ cancellationToken.ThrowIfCancellationRequested();
+
+ progressTracker.Report(CodeAnalysisProgress.Description(string.Format(FeaturesResources.Fixing_0, title ?? diagnosticId)));
+ // Apply codefixes for diagnostics with a severity of warning or higher
+ var updatedDocument = await _codeFixService.ApplyCodeFixesForSpecificDiagnosticIdAsync(
+ document, diagnosticId, DiagnosticSeverity.Warning, progressTracker, cancellationToken).ConfigureAwait(false);
+
+ // If changes were made to the solution snap shot outside the current document discard the changes.
+ // The assumption here is that if we are applying a third party code fix to a document it only affects the document.
+ // Symbol renames and other complex refactorings we do not want to include in code cleanup.
+ // We can revisit this if we get feedback to the contrary
+ if (!ChangesMadeOutsideDocument(document, updatedDocument))
{
- cancellationToken.ThrowIfCancellationRequested();
-
- progressTracker.Report(CodeAnalysisProgress.Description(string.Format(FeaturesResources.Fixing_0, title ?? diagnosticId)));
- // Apply codefixes for diagnostics with a severity of warning or higher
- var updatedDocument = await _codeFixService.ApplyCodeFixesForSpecificDiagnosticIdAsync(
- document, diagnosticId, DiagnosticSeverity.Warning, progressTracker, cancellationToken).ConfigureAwait(false);
-
- // If changes were made to the solution snap shot outside the current document discard the changes.
- // The assumption here is that if we are applying a third party code fix to a document it only affects the document.
- // Symbol renames and other complex refactorings we do not want to include in code cleanup.
- // We can revisit this if we get feedback to the contrary
- if (!ChangesMadeOutsideDocument(document, updatedDocument))
- {
- document = updatedDocument;
- }
-
- progressTracker.ItemCompleted();
+ document = updatedDocument;
}
- return document;
+ progressTracker.ItemCompleted();
+ }
- static bool ChangesMadeOutsideDocument(Document currentDocument, Document updatedDocument)
- {
- var solutionChanges = updatedDocument.Project.Solution.GetChanges(currentDocument.Project.Solution);
- return
- solutionChanges.GetAddedProjects().Any() ||
- solutionChanges.GetRemovedProjects().Any() ||
- solutionChanges.GetAddedAnalyzerReferences().Any() ||
- solutionChanges.GetRemovedAnalyzerReferences().Any() ||
- solutionChanges.GetProjectChanges().Any(
- projectChanges => projectChanges.GetAddedProjectReferences().Any() ||
- projectChanges.GetRemovedProjectReferences().Any() ||
- projectChanges.GetAddedMetadataReferences().Any() ||
- projectChanges.GetRemovedMetadataReferences().Any() ||
- projectChanges.GetAddedAnalyzerReferences().Any() ||
- projectChanges.GetRemovedAnalyzerReferences().Any() ||
- projectChanges.GetAddedDocuments().Any() ||
- projectChanges.GetAddedAdditionalDocuments().Any() ||
- projectChanges.GetAddedAnalyzerConfigDocuments().Any() ||
- projectChanges.GetChangedDocuments().Any(documentId => documentId != updatedDocument.Id) ||
- projectChanges.GetChangedAdditionalDocuments().Any(documentId => documentId != updatedDocument.Id) ||
- projectChanges.GetChangedAnalyzerConfigDocuments().Any(documentId => documentId != updatedDocument.Id));
- }
+ return document;
+
+ static bool ChangesMadeOutsideDocument(Document currentDocument, Document updatedDocument)
+ {
+ var solutionChanges = updatedDocument.Project.Solution.GetChanges(currentDocument.Project.Solution);
+ return
+ solutionChanges.GetAddedProjects().Any() ||
+ solutionChanges.GetRemovedProjects().Any() ||
+ solutionChanges.GetAddedAnalyzerReferences().Any() ||
+ solutionChanges.GetRemovedAnalyzerReferences().Any() ||
+ solutionChanges.GetProjectChanges().Any(
+ projectChanges => projectChanges.GetAddedProjectReferences().Any() ||
+ projectChanges.GetRemovedProjectReferences().Any() ||
+ projectChanges.GetAddedMetadataReferences().Any() ||
+ projectChanges.GetRemovedMetadataReferences().Any() ||
+ projectChanges.GetAddedAnalyzerReferences().Any() ||
+ projectChanges.GetRemovedAnalyzerReferences().Any() ||
+ projectChanges.GetAddedDocuments().Any() ||
+ projectChanges.GetAddedAdditionalDocuments().Any() ||
+ projectChanges.GetAddedAnalyzerConfigDocuments().Any() ||
+ projectChanges.GetChangedDocuments().Any(documentId => documentId != updatedDocument.Id) ||
+ projectChanges.GetChangedAdditionalDocuments().Any(documentId => documentId != updatedDocument.Id) ||
+ projectChanges.GetChangedAnalyzerConfigDocuments().Any(documentId => documentId != updatedDocument.Id));
}
- public EnabledDiagnosticOptions GetAllDiagnostics()
- => new(FormatDocument: true, RunThirdPartyFixers: true, Diagnostics: GetDiagnosticSets(), OrganizeUsings: new OrganizeUsingsSet(isRemoveUnusedImportEnabled: true, isSortImportsEnabled: true));
}
+ public EnabledDiagnosticOptions GetAllDiagnostics()
+ => new(FormatDocument: true, RunThirdPartyFixers: true, Diagnostics: GetDiagnosticSets(), OrganizeUsings: new OrganizeUsingsSet(isRemoveUnusedImportEnabled: true, isSortImportsEnabled: true));
}
diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService_IncrementalAnalyzer.cs b/src/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService_IncrementalAnalyzer.cs
deleted file mode 100644
index 9a0b3fa16fdb9..0000000000000
--- a/src/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService_IncrementalAnalyzer.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace Microsoft.CodeAnalysis.Diagnostics;
-
-internal partial class DiagnosticAnalyzerService
-{
- private DiagnosticIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace)
- {
- return _map.GetValue(workspace, _createIncrementalAnalyzer);
- }
-
- private DiagnosticIncrementalAnalyzer CreateIncrementalAnalyzerCallback(Workspace workspace)
- {
- // subscribe to active context changed event for new workspace
- workspace.DocumentActiveContextChanged += OnDocumentActiveContextChanged;
-
- return new DiagnosticIncrementalAnalyzer(this, AnalyzerInfoCache, this.GlobalOptions);
- }
-
- private void OnDocumentActiveContextChanged(object? sender, DocumentActiveContextChangedEventArgs e)
- => RequestDiagnosticRefresh();
-}
diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractDocumentPullDiagnosticHandler.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractDocumentPullDiagnosticHandler.cs
index 106d2dc6bfc78..21c18891297be 100644
--- a/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractDocumentPullDiagnosticHandler.cs
+++ b/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractDocumentPullDiagnosticHandler.cs
@@ -14,12 +14,10 @@
namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics;
internal abstract class AbstractDocumentPullDiagnosticHandler(
- IDiagnosticAnalyzerService diagnosticAnalyzerService,
IDiagnosticsRefresher diagnosticRefresher,
IDiagnosticSourceManager diagnosticSourceManager,
IGlobalOptionService globalOptions)
: AbstractPullDiagnosticHandler(
- diagnosticAnalyzerService,
diagnosticRefresher,
globalOptions), ITextDocumentIdentifierHandler
where TDiagnosticsParams : IPartialResultParams
diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs
index d1f6ead2e0d06..bd4cba8018918 100644
--- a/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs
+++ b/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs
@@ -26,7 +26,6 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics;
/// The LSP type that is reported via IProgress
/// The LSP type that is returned on completion of the request.
internal abstract partial class AbstractPullDiagnosticHandler(
- IDiagnosticAnalyzerService diagnosticAnalyzerService,
IDiagnosticsRefresher diagnosticRefresher,
IGlobalOptionService globalOptions)
: ILspServiceRequestHandler
@@ -43,7 +42,6 @@ internal abstract partial class AbstractPullDiagnosticHandler
/// Map of diagnostic category to the diagnostics cache for that category.
diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractWorkspacePullDiagnosticsHandler.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractWorkspacePullDiagnosticsHandler.cs
index df726f111c6c4..7b1b18d6a84fe 100644
--- a/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractWorkspacePullDiagnosticsHandler.cs
+++ b/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractWorkspacePullDiagnosticsHandler.cs
@@ -37,10 +37,9 @@ internal abstract class AbstractWorkspacePullDiagnosticsHandler true;
@@ -26,7 +26,7 @@ public ValueTask> CreateDiagnosticSourcesAsync
{
if (context.GetTrackedDocument() is { } document)
{
- return new([new DocumentDiagnosticSource(diagnosticAnalyzerService, kind, document)]);
+ return new([new DocumentDiagnosticSource(kind, document)]);
}
return new([]);
@@ -35,8 +35,8 @@ public ValueTask> CreateDiagnosticSourcesAsync
[Export(typeof(IDiagnosticSourceProvider)), Shared]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
- private sealed class DocumentCompilerSyntaxDiagnosticSourceProvider([Import] IDiagnosticAnalyzerService diagnosticAnalyzerService)
- : AbstractDocumentSyntaxAndSemanticDiagnosticSourceProvider(diagnosticAnalyzerService,
+ private sealed class DocumentCompilerSyntaxDiagnosticSourceProvider()
+ : AbstractDocumentSyntaxAndSemanticDiagnosticSourceProvider(
DiagnosticKind.CompilerSyntax, PullDiagnosticCategories.DocumentCompilerSyntax)
{
}
@@ -44,17 +44,17 @@ private sealed class DocumentCompilerSyntaxDiagnosticSourceProvider([Import] IDi
[Export(typeof(IDiagnosticSourceProvider)), Shared]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
- private sealed class DocumentCompilerSemanticDiagnosticSourceProvider([Import] IDiagnosticAnalyzerService diagnosticAnalyzerService)
+ private sealed class DocumentCompilerSemanticDiagnosticSourceProvider()
: AbstractDocumentSyntaxAndSemanticDiagnosticSourceProvider(
- diagnosticAnalyzerService, DiagnosticKind.CompilerSemantic, PullDiagnosticCategories.DocumentCompilerSemantic)
+ DiagnosticKind.CompilerSemantic, PullDiagnosticCategories.DocumentCompilerSemantic)
{
}
[Export(typeof(IDiagnosticSourceProvider)), Shared]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
- private sealed class DocumentAnalyzerSyntaxDiagnosticSourceProvider([Import] IDiagnosticAnalyzerService diagnosticAnalyzerService)
- : AbstractDocumentSyntaxAndSemanticDiagnosticSourceProvider(diagnosticAnalyzerService,
+ private sealed class DocumentAnalyzerSyntaxDiagnosticSourceProvider()
+ : AbstractDocumentSyntaxAndSemanticDiagnosticSourceProvider(
DiagnosticKind.AnalyzerSyntax, PullDiagnosticCategories.DocumentAnalyzerSyntax)
{
}
@@ -62,8 +62,8 @@ private sealed class DocumentAnalyzerSyntaxDiagnosticSourceProvider([Import] IDi
[Export(typeof(IDiagnosticSourceProvider)), Shared]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
- private sealed class DocumentAnalyzerSemanticDiagnosticSourceProvider([Import] IDiagnosticAnalyzerService diagnosticAnalyzerService)
- : AbstractDocumentSyntaxAndSemanticDiagnosticSourceProvider(diagnosticAnalyzerService,
+ private sealed class DocumentAnalyzerSemanticDiagnosticSourceProvider()
+ : AbstractDocumentSyntaxAndSemanticDiagnosticSourceProvider(
DiagnosticKind.AnalyzerSemantic, PullDiagnosticCategories.DocumentAnalyzerSemantic)
{
}
diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSourceProviders/WorkspaceDocumentsAndProjectDiagnosticSourceProvider.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSourceProviders/WorkspaceDocumentsAndProjectDiagnosticSourceProvider.cs
index e18ca39e8f871..573f414478133 100644
--- a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSourceProviders/WorkspaceDocumentsAndProjectDiagnosticSourceProvider.cs
+++ b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSourceProviders/WorkspaceDocumentsAndProjectDiagnosticSourceProvider.cs
@@ -21,7 +21,6 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics;
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal sealed class WorkspaceDocumentsAndProjectDiagnosticSourceProvider(
- [Import] IDiagnosticAnalyzerService diagnosticAnalyzerService,
[Import] IGlobalOptionService globalOptions)
: IDiagnosticSourceProvider
{
@@ -59,11 +58,11 @@ public async ValueTask> CreateDiagnosticSource
var codeAnalysisService = solution.Services.GetRequiredService();
foreach (var project in WorkspaceDiagnosticSourceHelpers.GetProjectsInPriorityOrder(solution, context.SupportedLanguages))
- await AddDocumentsAndProjectAsync(project, diagnosticAnalyzerService, cancellationToken).ConfigureAwait(false);
+ await AddDocumentsAndProjectAsync(project, cancellationToken).ConfigureAwait(false);
return result.ToImmutableAndClear();
- async Task AddDocumentsAndProjectAsync(Project project, IDiagnosticAnalyzerService diagnosticAnalyzerService, CancellationToken cancellationToken)
+ async Task AddDocumentsAndProjectAsync(Project project, CancellationToken cancellationToken)
{
var fullSolutionAnalysisEnabled = globalOptions.IsFullSolutionAnalysisEnabled(project.Language, out var compilerFullSolutionAnalysisEnabled, out var analyzersFullSolutionAnalysisEnabled);
if (!fullSolutionAnalysisEnabled && !codeAnalysisService.HasProjectBeenAnalyzed(project.Id))
@@ -95,7 +94,7 @@ void AddDocumentSources(IEnumerable documents)
{
// Add the appropriate FSA or CodeAnalysis document source to get document diagnostics.
var documentDiagnosticSource = fullSolutionAnalysisEnabled
- ? AbstractWorkspaceDocumentDiagnosticSource.CreateForFullSolutionAnalysisDiagnostics(document, diagnosticAnalyzerService, shouldIncludeAnalyzer)
+ ? AbstractWorkspaceDocumentDiagnosticSource.CreateForFullSolutionAnalysisDiagnostics(document, shouldIncludeAnalyzer)
: AbstractWorkspaceDocumentDiagnosticSource.CreateForCodeAnalysisDiagnostics(document, codeAnalysisService);
result.Add(documentDiagnosticSource);
}
@@ -105,7 +104,7 @@ void AddDocumentSources(IEnumerable documents)
void AddProjectSource()
{
var projectDiagnosticSource = fullSolutionAnalysisEnabled
- ? AbstractProjectDiagnosticSource.CreateForFullSolutionAnalysisDiagnostics(project, diagnosticAnalyzerService, shouldIncludeAnalyzer)
+ ? AbstractProjectDiagnosticSource.CreateForFullSolutionAnalysisDiagnostics(project, shouldIncludeAnalyzer)
: AbstractProjectDiagnosticSource.CreateForCodeAnalysisDiagnostics(project, codeAnalysisService);
result.Add(projectDiagnosticSource);
}
diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractDocumentDiagnosticSource.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractDocumentDiagnosticSource.cs
index f88810864a7bb..03a37330ae190 100644
--- a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractDocumentDiagnosticSource.cs
+++ b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractDocumentDiagnosticSource.cs
@@ -14,6 +14,7 @@ internal abstract class AbstractDocumentDiagnosticSource(TDocument do
where TDocument : TextDocument
{
public TDocument Document { get; } = document;
+ public Solution Solution => this.Document.Project.Solution;
public abstract bool IsLiveSource();
diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractProjectDiagnosticSource.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractProjectDiagnosticSource.cs
index 18fc22f98ca51..d814da265f1d5 100644
--- a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractProjectDiagnosticSource.cs
+++ b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractProjectDiagnosticSource.cs
@@ -15,9 +15,10 @@ internal abstract class AbstractProjectDiagnosticSource(Project project)
: IDiagnosticSource
{
protected Project Project => project;
+ protected Solution Solution => this.Project.Solution;
- public static AbstractProjectDiagnosticSource CreateForFullSolutionAnalysisDiagnostics(Project project, IDiagnosticAnalyzerService diagnosticAnalyzerService, Func? shouldIncludeAnalyzer)
- => new FullSolutionAnalysisDiagnosticSource(project, diagnosticAnalyzerService, shouldIncludeAnalyzer);
+ public static AbstractProjectDiagnosticSource CreateForFullSolutionAnalysisDiagnostics(Project project, Func? shouldIncludeAnalyzer)
+ => new FullSolutionAnalysisDiagnosticSource(project, shouldIncludeAnalyzer);
public static AbstractProjectDiagnosticSource CreateForCodeAnalysisDiagnostics(Project project, ICodeAnalysisDiagnosticAnalyzerService codeAnalysisService)
=> new CodeAnalysisDiagnosticSource(project, codeAnalysisService);
@@ -33,7 +34,7 @@ public static AbstractProjectDiagnosticSource CreateForCodeAnalysisDiagnostics(P
: null;
public string ToDisplayString() => Project.Name;
- private sealed class FullSolutionAnalysisDiagnosticSource(Project project, IDiagnosticAnalyzerService diagnosticAnalyzerService, Func? shouldIncludeAnalyzer)
+ private sealed class FullSolutionAnalysisDiagnosticSource(Project project, Func? shouldIncludeAnalyzer)
: AbstractProjectDiagnosticSource(project)
{
///
@@ -50,7 +51,8 @@ public override async Task> GetDiagnosticsAsync(
// we're passing in. If information is already cached for that snapshot, it will be returned. Otherwise,
// it will be computed on demand. Because it is always accurate as per this snapshot, all spans are correct
// and do not need to be adjusted.
- var diagnostics = await diagnosticAnalyzerService.GetProjectDiagnosticsForIdsAsync(
+ var service = this.Solution.Services.GetRequiredService();
+ var diagnostics = await service.GetProjectDiagnosticsForIdsAsync(
Project, diagnosticIds: null, shouldIncludeAnalyzer, includeNonLocalDocumentDiagnostics: false, cancellationToken).ConfigureAwait(false);
// TODO(cyrusn): In the future we could consider reporting these, but with a flag on the diagnostic mentioning
diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractWorkspaceDocumentDiagnosticSource.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractWorkspaceDocumentDiagnosticSource.cs
index 7777dba417737..9e0a50253403e 100644
--- a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractWorkspaceDocumentDiagnosticSource.cs
+++ b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractWorkspaceDocumentDiagnosticSource.cs
@@ -15,13 +15,14 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics;
internal abstract class AbstractWorkspaceDocumentDiagnosticSource(TextDocument document) : AbstractDocumentDiagnosticSource(document)
{
- public static AbstractWorkspaceDocumentDiagnosticSource CreateForFullSolutionAnalysisDiagnostics(TextDocument document, IDiagnosticAnalyzerService diagnosticAnalyzerService, Func? shouldIncludeAnalyzer)
- => new FullSolutionAnalysisDiagnosticSource(document, diagnosticAnalyzerService, shouldIncludeAnalyzer);
+ public static AbstractWorkspaceDocumentDiagnosticSource CreateForFullSolutionAnalysisDiagnostics(TextDocument document, Func? shouldIncludeAnalyzer)
+ => new FullSolutionAnalysisDiagnosticSource(document, shouldIncludeAnalyzer);
public static AbstractWorkspaceDocumentDiagnosticSource CreateForCodeAnalysisDiagnostics(TextDocument document, ICodeAnalysisDiagnosticAnalyzerService codeAnalysisService)
=> new CodeAnalysisDiagnosticSource(document, codeAnalysisService);
- private sealed class FullSolutionAnalysisDiagnosticSource(TextDocument document, IDiagnosticAnalyzerService diagnosticAnalyzerService, Func? shouldIncludeAnalyzer)
+ private sealed class FullSolutionAnalysisDiagnosticSource(
+ TextDocument document, Func? shouldIncludeAnalyzer)
: AbstractWorkspaceDocumentDiagnosticSource(document)
{
///
@@ -44,20 +45,20 @@ public override async Task> GetDiagnosticsAsync(
if (Document is SourceGeneratedDocument sourceGeneratedDocument)
{
// Unfortunately GetDiagnosticsForIdsAsync returns nothing for source generated documents.
- var documentDiagnostics = await diagnosticAnalyzerService.GetDiagnosticsForSpanAsync(
+ var service = this.Solution.Services.GetRequiredService();
+ var documentDiagnostics = await service.GetDiagnosticsForSpanAsync(
sourceGeneratedDocument, range: null, DiagnosticKind.All, cancellationToken).ConfigureAwait(false);
documentDiagnostics = documentDiagnostics.WhereAsArray(d => !d.IsSuppressed);
return documentDiagnostics;
}
else
{
- var projectDiagnostics = await GetProjectDiagnosticsAsync(diagnosticAnalyzerService, cancellationToken).ConfigureAwait(false);
+ var projectDiagnostics = await GetProjectDiagnosticsAsync(cancellationToken).ConfigureAwait(false);
return projectDiagnostics.WhereAsArray(d => d.DocumentId == Document.Id);
}
}
- private async ValueTask> GetProjectDiagnosticsAsync(
- IDiagnosticAnalyzerService diagnosticAnalyzerService, CancellationToken cancellationToken)
+ private async ValueTask> GetProjectDiagnosticsAsync(CancellationToken cancellationToken)
{
if (!s_projectToDiagnostics.TryGetValue(Document.Project, out var lazyDiagnostics))
{
@@ -75,7 +76,8 @@ AsyncLazy> GetLazyDiagnostics()
_ => AsyncLazy.Create(
async cancellationToken =>
{
- var allDiagnostics = await diagnosticAnalyzerService.GetDiagnosticsForIdsAsync(
+ var service = this.Solution.Services.GetRequiredService();
+ var allDiagnostics = await service.GetDiagnosticsForIdsAsync(
Document.Project, documentId: null, diagnosticIds: null, shouldIncludeAnalyzer,
includeLocalDocumentDiagnostics: true, includeNonLocalDocumentDiagnostics: true, cancellationToken).ConfigureAwait(false);
diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/DocumentDiagnosticSource.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/DocumentDiagnosticSource.cs
index 34203462a17d3..9960d4dc5a7e5 100644
--- a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/DocumentDiagnosticSource.cs
+++ b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/DocumentDiagnosticSource.cs
@@ -10,7 +10,7 @@
namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics;
-internal sealed class DocumentDiagnosticSource(IDiagnosticAnalyzerService diagnosticAnalyzerService, DiagnosticKind diagnosticKind, TextDocument document)
+internal sealed class DocumentDiagnosticSource(DiagnosticKind diagnosticKind, TextDocument document)
: AbstractDocumentDiagnosticSource(document)
{
public DiagnosticKind DiagnosticKind { get; } = diagnosticKind;
@@ -27,7 +27,8 @@ public override async Task> GetDiagnosticsAsync(
// We call GetDiagnosticsForSpanAsync here instead of GetDiagnosticsForIdsAsync as it has faster perf
// characteristics. GetDiagnosticsForIdsAsync runs analyzers against the entire compilation whereas
// GetDiagnosticsForSpanAsync will only run analyzers against the request document.
- var allSpanDiagnostics = await diagnosticAnalyzerService.GetDiagnosticsForSpanAsync(
+ var service = this.Solution.Services.GetRequiredService();
+ var allSpanDiagnostics = await service.GetDiagnosticsForSpanAsync(
Document, range: null, diagnosticKind: this.DiagnosticKind, cancellationToken).ConfigureAwait(false);
// Note: we do not filter our suppressed diagnostics we we want unnecessary suppressions to be reported.
diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/NonLocalDocumentDiagnosticSource.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/NonLocalDocumentDiagnosticSource.cs
index b089870386125..2551c6592a82b 100644
--- a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/NonLocalDocumentDiagnosticSource.cs
+++ b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/NonLocalDocumentDiagnosticSource.cs
@@ -10,7 +10,8 @@
namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics;
-internal sealed class NonLocalDocumentDiagnosticSource(TextDocument document, IDiagnosticAnalyzerService diagnosticAnalyzerService, Func? shouldIncludeAnalyzer)
+internal sealed class NonLocalDocumentDiagnosticSource(
+ TextDocument document, Func