From bd67d0bc118c46256c4139e8f673f832f1192cea Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 May 2021 12:24:19 -0700 Subject: [PATCH 01/53] Initial stubs for async lightbulbs --- .../Suggestions/SuggestedActionsSource.cs | 123 ++++++++++++++++-- 1 file changed, 111 insertions(+), 12 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 00858a6e4b200..2049a86af4fce 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -186,6 +186,80 @@ public bool TryGetTelemetryId(out Guid telemetryId) } } + public async IAsyncEnumerable? GetSuggestedActionsAsync( + ISuggestedActionCategorySet requestedActionCategories, + SnapshotSpan range, + IUIThreadOperationContext operationContext) + { + AssertIsForeground(); + var cancellationToken = operationContext.UserCancellationToken; + + if (IsDisposed) + yield break; + + if (_workspaceStatusService != null) + { + using (operationContext.AddScope(allowCancellation: true, description: EditorFeaturesResources.Gathering_Suggestions_Waiting_for_the_solution_to_fully_load)) + { + await _workspaceStatusService.WaitUntilFullyLoadedAsync(cancellationToken).ConfigureAwait(true); + } + } + + using (Logger.LogBlock(FunctionId.SuggestedActions_GetSuggestedActions, cancellationToken)) + { + var document = range.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); + if (document == null) + yield break; + + var highPriSet = await GetCodeFixesAndRefactoringsAsync( + requestedActionCategories, document, range, AddOperationScope, highPriority: true, cancellationToken).ConfigureAwait(false); + foreach (var set in highPriSet) + yield return set; + + var lowPriSet = await GetCodeFixesAndRefactoringsAsync( + requestedActionCategories, document, range, AddOperationScope, highPriority: false, cancellationToken).ConfigureAwait(false); + foreach (var set in lowPriSet) + yield return set; + } + + IDisposable? AddOperationScope(string description) + { + return operationContext.AddScope(allowCancellation: true, string.Format(EditorFeaturesResources.Gathering_Suggestions_0, description)); + } + } + + private async Task> GetCodeFixesAndRefactoringsAsync( + ISuggestedActionCategorySet requestedActionCategories, + Document document, + SnapshotSpan range, + Func addOperationScope, + bool highPriority, + CancellationToken cancellationToken) + { + var workspace = document.Project.Solution.Workspace; + var supportsFeatureService = workspace.Services.GetRequiredService(); + + var selection = TryGetCodeRefactoringSelection(range); + + var fixesTask = GetCodeFixesAsync( + supportsFeatureService, requestedActionCategories, workspace, document, range, + addOperationScope, isBlocking: false, cancellationToken); + var refactoringsTask = GetRefactoringsAsync( + supportsFeatureService, requestedActionCategories, workspace, document, selection, + addOperationScope, isBlocking: false, cancellationToken); + + await Task.WhenAll(fixesTask, refactoringsTask).ConfigureAwait(false); + + var fixes = await fixesTask.ConfigureAwait(false); + var refactorings = await refactoringsTask.ConfigureAwait(false); + + var filteredSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets(fixes, refactorings, selection); + if (!filteredSets.HasValue) + return SpecializedCollections.EmptyEnumerable(); + + return filteredSets.Value.Select(s => ConvertToSuggestedActionSet(s)).WhereNotNull(); + } + [return: NotNullIfNotNull("unifiedSuggestedActionSet")] private SuggestedActionSet? ConvertToSuggestedActionSet(UnifiedSuggestedActionSet? unifiedSuggestedActionSet, SuggestedActionsSourceProvider owner, ITextBuffer subjectBuffer) { @@ -252,8 +326,23 @@ private ImmutableArray GetCodeFixes( { this.AssertIsForeground(); - if (state.Target.Owner._codeFixService == null || - !supportsFeatureService.SupportsCodeFixes(state.Target.SubjectBuffer) || + return GetCodeFixesAsync( + supportsFeatureService, requestedActionCategories, workspace, document, range, + addOperationScope, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); + } + + private async Task> GetCodeFixesAsync( + ITextBufferSupportsFeatureService supportsFeatureService, + ISuggestedActionCategorySet requestedActionCategories, + Workspace workspace, + Document document, + SnapshotSpan range, + Func addOperationScope, + bool isBlocking, + CancellationToken cancellationToken) + { + if (_owner._codeFixService == null || + !supportsFeatureService.SupportsCodeFixes(_subjectBuffer) || !requestedActionCategories.Contains(PredefinedSuggestedActionCategoryNames.CodeFix)) { return ImmutableArray.Empty; @@ -263,9 +352,9 @@ private ImmutableArray GetCodeFixes( // See https://github.com/dotnet/roslyn/issues/29589 const bool includeSuppressionFixes = true; - return UnifiedSuggestedActionsSource.GetFilterAndOrderCodeFixesAsync( - workspace, state.Target.Owner._codeFixService, document, range.Span.ToTextSpan(), - includeSuppressionFixes, isBlocking: true, addOperationScope, cancellationToken).WaitAndGetResult(cancellationToken); + return await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeFixesAsync( + workspace, _owner._codeFixService, document, range.Span.ToTextSpan(), + includeSuppressionFixes, isBlocking, addOperationScope, cancellationToken).ConfigureAwait(false); } private static string GetFixCategory(DiagnosticSeverity severity) @@ -294,13 +383,23 @@ private ImmutableArray GetRefactorings( CancellationToken cancellationToken) { this.AssertIsForeground(); + return GetRefactoringsAsync( + supportsFeatureService, requestedActionCategories, workspace, document, selection, + addOperationScope, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); + } + private async Task> GetRefactoringsAsync( + ITextBufferSupportsFeatureService supportsFeatureService, + ISuggestedActionCategorySet requestedActionCategories, + Workspace workspace, + Document document, + TextSpan? selection, + Func addOperationScope, + bool isBlocking, + CancellationToken cancellationToken) + { if (!selection.HasValue) - { - // this is here to fail test and see why it is failed. - Trace.WriteLine("given range is not current"); return ImmutableArray.Empty; - } if (!workspace.Options.GetOption(EditorComponentOnOffOptions.CodeRefactorings) || state.Target.Owner._codeRefactoringService == null || @@ -313,9 +412,9 @@ private ImmutableArray GetRefactorings( // then we want to filter out refactorings outside the selection span. var filterOutsideSelection = !requestedActionCategories.Contains(PredefinedSuggestedActionCategoryNames.Refactoring); - return UnifiedSuggestedActionsSource.GetFilterAndOrderCodeRefactoringsAsync( - workspace, state.Target.Owner._codeRefactoringService, document, selection.Value, isBlocking: true, - addOperationScope, filterOutsideSelection, cancellationToken).WaitAndGetResult(cancellationToken); + return await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeRefactoringsAsync( + workspace, _owner._codeRefactoringService, document, selection.Value, isBlocking, + addOperationScope, filterOutsideSelection, cancellationToken).ConfigureAwait(false); } public Task HasSuggestedActionsAsync( From 25b6bba124a13fa65878d135d5e0f67f05d7efbc Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 May 2021 12:37:20 -0700 Subject: [PATCH 02/53] Add parameter --- .../Suggestions/SuggestedActionsSource.cs | 16 +++++++++------- .../Core/Portable/CodeFixes/ICodeFixService.cs | 4 ++-- .../UnifiedSuggestedActionsSource.cs | 4 +++- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 2049a86af4fce..1314e286597e2 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -186,7 +186,7 @@ public bool TryGetTelemetryId(out Guid telemetryId) } } - public async IAsyncEnumerable? GetSuggestedActionsAsync( + public async IAsyncEnumerable GetSuggestedActionsAsync( ISuggestedActionCategorySet requestedActionCategories, SnapshotSpan range, IUIThreadOperationContext operationContext) @@ -243,10 +243,10 @@ private async Task> GetCodeFixesAndRefactoringsA var fixesTask = GetCodeFixesAsync( supportsFeatureService, requestedActionCategories, workspace, document, range, - addOperationScope, isBlocking: false, cancellationToken); + addOperationScope, highPriority, isBlocking: false, cancellationToken); var refactoringsTask = GetRefactoringsAsync( supportsFeatureService, requestedActionCategories, workspace, document, selection, - addOperationScope, isBlocking: false, cancellationToken); + addOperationScope, highPriority, isBlocking: false, cancellationToken); await Task.WhenAll(fixesTask, refactoringsTask).ConfigureAwait(false); @@ -328,7 +328,7 @@ private ImmutableArray GetCodeFixes( return GetCodeFixesAsync( supportsFeatureService, requestedActionCategories, workspace, document, range, - addOperationScope, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); + addOperationScope, highPriority: null, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); } private async Task> GetCodeFixesAsync( @@ -338,6 +338,7 @@ private async Task> GetCodeFixesAsync( Document document, SnapshotSpan range, Func addOperationScope, + bool? highPriority, bool isBlocking, CancellationToken cancellationToken) { @@ -354,7 +355,7 @@ private async Task> GetCodeFixesAsync( return await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeFixesAsync( workspace, _owner._codeFixService, document, range.Span.ToTextSpan(), - includeSuppressionFixes, isBlocking, addOperationScope, cancellationToken).ConfigureAwait(false); + includeSuppressionFixes, highPriority, isBlocking, addOperationScope, cancellationToken).ConfigureAwait(false); } private static string GetFixCategory(DiagnosticSeverity severity) @@ -385,7 +386,7 @@ private ImmutableArray GetRefactorings( this.AssertIsForeground(); return GetRefactoringsAsync( supportsFeatureService, requestedActionCategories, workspace, document, selection, - addOperationScope, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); + addOperationScope, highPriority: null, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); } private async Task> GetRefactoringsAsync( @@ -395,6 +396,7 @@ private async Task> GetRefactoringsAsy Document document, TextSpan? selection, Func addOperationScope, + bool? highPriority, bool isBlocking, CancellationToken cancellationToken) { @@ -413,7 +415,7 @@ private async Task> GetRefactoringsAsy var filterOutsideSelection = !requestedActionCategories.Contains(PredefinedSuggestedActionCategoryNames.Refactoring); return await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeRefactoringsAsync( - workspace, _owner._codeRefactoringService, document, selection.Value, isBlocking, + workspace, _owner._codeRefactoringService, document, selection.Value, highPriority, isBlocking, addOperationScope, filterOutsideSelection, cancellationToken).ConfigureAwait(false); } diff --git a/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs b/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs index 37de9af843d8f..cf09aa0507f59 100644 --- a/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs +++ b/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.CodeFixes { internal interface ICodeFixService { - Task> GetFixesAsync(Document document, TextSpan textSpan, bool includeSuppressionFixes, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken); + Task> GetFixesAsync(Document document, TextSpan textSpan, bool includeSuppressionFixes, bool? highPriority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken); Task GetDocumentFixAllForIdInSpanAsync(Document document, TextSpan textSpan, string diagnosticId, CancellationToken cancellationToken); Task ApplyCodeFixesForSpecificDiagnosticIdAsync(Document document, string diagnosticId, IProgressTracker progressTracker, CancellationToken cancellationToken); CodeFixProvider? GetSuppressionFixer(string language, IEnumerable diagnosticIds); @@ -27,6 +27,6 @@ public static Task> GetFixesAsync(this ICodeFi => service.GetFixesAsync(document, range, includeConfigurationFixes, isBlocking: false, cancellationToken); public static Task> GetFixesAsync(this ICodeFixService service, Document document, TextSpan range, bool includeConfigurationFixes, bool isBlocking, CancellationToken cancellationToken) - => service.GetFixesAsync(document, range, includeConfigurationFixes, isBlocking, addOperationScope: _ => null, cancellationToken); + => service.GetFixesAsync(document, range, includeConfigurationFixes, highPriority: null, isBlocking, addOperationScope: _ => null, cancellationToken); } } diff --git a/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs b/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs index c42109db9f6a8..2818c9b9b31d3 100644 --- a/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs +++ b/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs @@ -35,6 +35,7 @@ public static async Task> GetFilterAnd Document document, TextSpan selection, bool includeSuppressionFixes, + bool? highPriority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken) @@ -45,7 +46,7 @@ public static async Task> GetFilterAnd // the UI thread. var fixes = await Task.Run( () => codeFixService.GetFixesAsync( - document, selection, includeSuppressionFixes, isBlocking, + document, selection, includeSuppressionFixes, highPriority, isBlocking, addOperationScope, cancellationToken), cancellationToken).ConfigureAwait(false); var filteredFixes = fixes.WhereAsArray(c => c.Fixes.Length > 0); @@ -393,6 +394,7 @@ public static async Task> GetFilterAnd ICodeRefactoringService codeRefactoringService, Document document, TextSpan selection, + bool? highPriority, bool isBlocking, Func addOperationScope, bool filterOutsideSelection, From 5e4b103ce4e2e1871981bd682457974ac555ee1b Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 May 2021 12:57:10 -0700 Subject: [PATCH 03/53] Thread through priority information --- .../Portable/CodeRefactorings/CodeRefactoringService.cs | 7 +++++-- .../Portable/CodeRefactorings/CodeRefactoringProvider.cs | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs index c26e0e590aa75..e221190ed845e 100644 --- a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs @@ -108,6 +108,7 @@ public async Task HasRefactoringsAsync( public async Task> GetRefactoringsAsync( Document document, TextSpan state, + bool? highPriority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken) @@ -119,8 +120,10 @@ public async Task> GetRefactoringsAsync( foreach (var provider in GetProviders(document)) { - tasks.Add(Task.Run( - () => + if (highPriority != null && highPriority != provider.IsHighPriority) + continue; + + tasks.Add(Task.Run(() => { var providerName = provider.GetType().Name; RefactoringToMetadataMap.TryGetValue(provider, out var providerMetadata); diff --git a/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringProvider.cs b/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringProvider.cs index d32cd928a8aa2..6610058b63a8e 100644 --- a/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringProvider.cs +++ b/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringProvider.cs @@ -16,5 +16,7 @@ public abstract class CodeRefactoringProvider /// Computes one or more refactorings for the specified . /// public abstract Task ComputeRefactoringsAsync(CodeRefactoringContext context); + + internal virtual bool IsHighPriority => false; } } From b5ad99fbeb5828b7b241f85a5ce7a70a719b7284 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 May 2021 13:58:22 -0700 Subject: [PATCH 04/53] Thread through value. --- .../RenameTrackingCodeRefactoringProvider.cs | 7 +++ .../AbstractAddImportCodeFixProvider.cs | 2 + .../Core/Portable/CodeFixes/CodeFixService.cs | 27 ++++++---- .../Diagnostics/DiagnosticAnalyzerService.cs | 12 ++++- ...crementalAnalyzer_GetDiagnosticsForSpan.cs | 53 ++++++++++++++++--- .../Diagnostics/IDiagnosticAnalyzerService.cs | 8 ++- .../CodeActions/CodeActionPriority.cs | 27 +++++----- .../Portable/CodeFixes/CodeFixProvider.cs | 6 +++ .../CodeRefactoringProvider.cs | 4 ++ .../Core/Diagnostics/IBuiltInAnalyzer.cs | 6 +++ 10 files changed, 120 insertions(+), 32 deletions(-) diff --git a/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingCodeRefactoringProvider.cs b/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingCodeRefactoringProvider.cs index 8202b911ebd16..612c601979513 100644 --- a/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingCodeRefactoringProvider.cs +++ b/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingCodeRefactoringProvider.cs @@ -40,5 +40,12 @@ public override Task ComputeRefactoringsAsync(CodeRefactoringContext context) return Task.CompletedTask; } + + /// + /// This is a high priority refactoring that we want to run first so that the user can quickly + /// change the name of something and pop up the lightbulb without having to wait for the rest to + /// compute. + /// + internal override bool IsHighPriority => true; } } diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs index 46c8e1f92c7c8..53da9bb8770e8 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs @@ -31,6 +31,8 @@ protected AbstractAddImportCodeFixProvider( _symbolSearchService = symbolSearchService; } + internal override bool IsHighPriority => true; + public sealed override FixAllProvider GetFixAllProvider() { // Currently Fix All is not supported for this provider diff --git a/src/Features/Core/Portable/CodeFixes/CodeFixService.cs b/src/Features/Core/Portable/CodeFixes/CodeFixService.cs index a9243437f33bf..2c805d0bcd132 100644 --- a/src/Features/Core/Portable/CodeFixes/CodeFixService.cs +++ b/src/Features/Core/Portable/CodeFixes/CodeFixService.cs @@ -151,7 +151,14 @@ public async Task GetMostSevereFixableDiagnosticAsync( return null; } - public async Task> GetFixesAsync(Document document, TextSpan range, bool includeConfigurationFixes, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken) + public async Task> GetFixesAsync( + Document document, + TextSpan range, + bool includeConfigurationFixes, + bool? highPriority, + bool isBlocking, + Func addOperationScope, + CancellationToken cancellationToken) { // REVIEW: this is the first and simplest design. basically, when ctrl+. is pressed, it asks diagnostic service to give back // current diagnostics for the given span, and it will use that to get fixes. internally diagnostic service will either return cached information @@ -164,12 +171,12 @@ public async Task> GetFixesAsync(Document docu // invariant: later code gathers & runs CodeFixProviders for diagnostics with one identical diagnostics span (that gets set later as CodeFixCollection's TextSpan) // order diagnostics by span. SortedDictionary>? aggregatedDiagnostics = null; - foreach (var diagnostic in await _diagnosticService.GetDiagnosticsForSpanAsync(document, range, diagnosticIdOpt: null, includeConfigurationFixes, addOperationScope, cancellationToken).ConfigureAwait(false)) + var diagnostics = await _diagnosticService.GetDiagnosticsForSpanAsync( + document, range, diagnosticIdOpt: null, includeConfigurationFixes, addOperationScope, cancellationToken).ConfigureAwait(false); + foreach (var diagnostic in diagnostics) { if (diagnostic.IsSuppressed) - { continue; - } cancellationToken.ThrowIfCancellationRequested(); @@ -178,9 +185,7 @@ public async Task> GetFixesAsync(Document docu } if (aggregatedDiagnostics == null) - { return ImmutableArray.Empty; - } // Order diagnostics by DiagnosticId so the fixes are in a deterministic order. foreach (var diagnosticsWithSpan in aggregatedDiagnostics.Values) @@ -193,8 +198,8 @@ public async Task> GetFixesAsync(Document docu foreach (var spanAndDiagnostic in aggregatedDiagnostics) { await AppendFixesAsync( - document, spanAndDiagnostic.Key, spanAndDiagnostic.Value, fixAllForInSpan: false, isBlocking, - result, addOperationScope, cancellationToken).ConfigureAwait(false); + document, spanAndDiagnostic.Key, spanAndDiagnostic.Value, fixAllForInSpan: false, + highPriority, isBlocking, result, addOperationScope, cancellationToken).ConfigureAwait(false); } if (result.Count > 0 && TryGetWorkspaceFixersPriorityMap(document, out var fixersForLanguage)) @@ -234,7 +239,7 @@ await AppendConfigurationsAsync( } using var resultDisposer = ArrayBuilder.GetInstance(out var result); - await AppendFixesAsync(document, range, diagnostics, fixAllForInSpan: true, isBlocking: false, result, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); + await AppendFixesAsync(document, range, diagnostics, fixAllForInSpan: true, highPriority: null, isBlocking: false, result, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); // TODO: Just get the first fix for now until we have a way to config user's preferred fix // https://github.com/dotnet/roslyn/issues/27066 @@ -328,6 +333,7 @@ private async Task AppendFixesAsync( TextSpan span, IEnumerable diagnostics, bool fixAllForInSpan, + bool? highPriority, bool isBlocking, ArrayBuilder result, Func addOperationScope, @@ -392,6 +398,9 @@ private async Task AppendFixesAsync( { cancellationToken.ThrowIfCancellationRequested(); + if (highPriority != null && highPriority != fixer.IsHighPriority) + continue; + await AppendFixesOrConfigurationsAsync( document, span, diagnostics, fixAllForInSpan, result, fixer, hasFix: d => this.GetFixableDiagnosticIds(fixer, extensionManager).Contains(d.Id), diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs index 3e18d4b153625..4ccafd0b57907 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs @@ -75,12 +75,20 @@ public Task TryAppendDiagnosticsForSpanAsync(Document document, TextSpan r return SpecializedTasks.False; } - public Task> GetDiagnosticsForSpanAsync(Document document, TextSpan range, string? diagnosticId = null, bool includeSuppressedDiagnostics = false, Func? addOperationScope = null, CancellationToken cancellationToken = default) + public Task> GetDiagnosticsForSpanAsync( + Document document, TextSpan range, + string? diagnosticId, + bool includeSuppressedDiagnostics, + bool? highPriority, + Func? addOperationScope, + CancellationToken cancellationToken) { if (_map.TryGetValue(document.Project.Solution.Workspace, out var analyzer)) { // always make sure that analyzer is called on background thread. - return Task.Run(() => analyzer.GetDiagnosticsForSpanAsync(document, range, diagnosticId, includeSuppressedDiagnostics, blockForData: true, addOperationScope, cancellationToken), cancellationToken); + return Task.Run(() => analyzer.GetDiagnosticsForSpanAsync( + document, range, diagnosticId, includeSuppressedDiagnostics, highPriority, + blockForData: true, addOperationScope, cancellationToken), cancellationToken); } return SpecializedTasks.EmptyImmutableArray(); diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs index 399553f0d052a..29d5ded4bc18c 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs @@ -19,16 +19,31 @@ namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 { internal partial class DiagnosticIncrementalAnalyzer { - public async Task TryAppendDiagnosticsForSpanAsync(Document document, TextSpan range, ArrayBuilder result, string? diagnosticId, bool includeSuppressedDiagnostics, bool blockForData, Func? addOperationScope, CancellationToken cancellationToken) + public async Task TryAppendDiagnosticsForSpanAsync( + Document document, TextSpan range, ArrayBuilder result, string? diagnosticId, + bool includeSuppressedDiagnostics, bool? highPriority, bool blockForData, + Func? addOperationScope, CancellationToken cancellationToken) { - var getter = await LatestDiagnosticsForSpanGetter.CreateAsync(this, document, range, blockForData, addOperationScope, includeSuppressedDiagnostics, diagnosticId, cancellationToken).ConfigureAwait(false); + var getter = await LatestDiagnosticsForSpanGetter.CreateAsync( + this, document, range, blockForData, addOperationScope, includeSuppressedDiagnostics, + highPriority, diagnosticId, cancellationToken).ConfigureAwait(false); return await getter.TryGetAsync(result, cancellationToken).ConfigureAwait(false); } - public async Task> GetDiagnosticsForSpanAsync(Document document, TextSpan range, string? diagnosticId, bool includeSuppressedDiagnostics, bool blockForData, Func? addOperationScope, CancellationToken cancellationToken) + public async Task> GetDiagnosticsForSpanAsync( + Document document, + TextSpan range, + string? diagnosticId, + bool includeSuppressedDiagnostics, + bool? highPriority, + bool blockForData, + Func? addOperationScope, + CancellationToken cancellationToken) { using var _ = ArrayBuilder.GetInstance(out var list); - var result = await TryAppendDiagnosticsForSpanAsync(document, range, list, diagnosticId, includeSuppressedDiagnostics, blockForData, addOperationScope, cancellationToken).ConfigureAwait(false); + var result = await TryAppendDiagnosticsForSpanAsync( + document, range, list, diagnosticId, includeSuppressedDiagnostics, + highPriority, blockForData, addOperationScope, cancellationToken).ConfigureAwait(false); Debug.Assert(result); return list.ToImmutable(); } @@ -47,6 +62,7 @@ private sealed class LatestDiagnosticsForSpanGetter private readonly TextSpan _range; private readonly bool _blockForData; private readonly bool _includeSuppressedDiagnostics; + private readonly bool? _highPriority; private readonly string? _diagnosticId; private readonly Func? _addOperationScope; @@ -59,6 +75,7 @@ public static async Task CreateAsync( bool blockForData, Func? addOperationScope, bool includeSuppressedDiagnostics, + bool? highPriority, string? diagnosticId, CancellationToken cancellationToken) { @@ -73,7 +90,9 @@ public static async Task CreateAsync( var compilationWithAnalyzers = await CreateCompilationWithAnalyzersAsync(document.Project, stateSets, includeSuppressedDiagnostics, cancellationToken).ConfigureAwait(false); - return new LatestDiagnosticsForSpanGetter(owner, compilationWithAnalyzers, document, stateSets, diagnosticId, range, blockForData, addOperationScope, includeSuppressedDiagnostics); + return new LatestDiagnosticsForSpanGetter( + owner, compilationWithAnalyzers, document, stateSets, diagnosticId, range, + blockForData, addOperationScope, includeSuppressedDiagnostics, highPriority); } private LatestDiagnosticsForSpanGetter( @@ -85,7 +104,8 @@ private LatestDiagnosticsForSpanGetter( TextSpan range, bool blockForData, Func? addOperationScope, - bool includeSuppressedDiagnostics) + bool includeSuppressedDiagnostics, + bool? highPriority) { _owner = owner; _compilationWithAnalyzers = compilationWithAnalyzers; @@ -96,6 +116,7 @@ private LatestDiagnosticsForSpanGetter( _blockForData = blockForData; _addOperationScope = addOperationScope; _includeSuppressedDiagnostics = includeSuppressedDiagnostics; + _highPriority = highPriority; } public async Task TryGetAsync(ArrayBuilder list, CancellationToken cancellationToken) @@ -184,10 +205,9 @@ private async Task ComputeDocumentDiagnosticsAsync( ArrayBuilder list, CancellationToken cancellationToken) { + analyzers = analyzers.WhereAsArray(a => MatchesPriority(a)); if (analyzers.IsEmpty) - { return; - } var analysisScope = new DocumentAnalysisScope(_document, span, analyzers, kind); var executor = new DocumentAnalysisExecutor(analysisScope, _compilationWithAnalyzers, _owner._diagnosticAnalyzerRunner, logPerformanceInfo: false); @@ -209,6 +229,23 @@ private async Task ComputeDocumentDiagnosticsAsync( } } + private bool MatchesPriority(DiagnosticAnalyzer analyzer) + { + // If caller isn't asking for prioritized result, then run all analyzers. + if (_highPriority == null) + return true; + + // Even if the caller is asking for prioritized results, we always need to + // run the compiler analyzer to get the basic set of diagnostics that analyzers + // need to process. + if (analyzer.IsCompilerAnalyzer()) + return true; + + // Otherwise, check our special internal flag to tell. + var analyzerIsHighPri = analyzer is IBuiltInAnalyzer { IsHighPriority: true }; + return analyzerIsHighPri == _highPriority; + } + private bool ShouldInclude(DiagnosticData diagnostic) { return diagnostic.DocumentId == _document.Id && _range.IntersectsWith(diagnostic.GetTextSpan()) diff --git a/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs index 7d2e2ce009854..555689bddf73c 100644 --- a/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs +++ b/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs @@ -76,6 +76,12 @@ internal interface IDiagnosticAnalyzerService /// This can be expensive since it is force analyzing diagnostics if it doesn't have up-to-date one yet. /// If diagnosticIdOpt is not null, it gets diagnostics only for this given diagnosticIdOpt value /// - Task> GetDiagnosticsForSpanAsync(Document document, TextSpan range, string? diagnosticIdOpt = null, bool includeSuppressedDiagnostics = false, Func? addOperationScope = null, CancellationToken cancellationToken = default); + Task> GetDiagnosticsForSpanAsync(Document document, TextSpan range, string? diagnosticIdOpt = null, bool includeSuppressedDiagnostics = false, bool? highPriority = null, Func? addOperationScope = null, CancellationToken cancellationToken = default); + } + + internal static class IDiagnosticAnalyzerServiceExtensions + { + public static Task> GetDiagnosticsForSpanAsync(this IDiagnosticAnalyzerService service, Document document, TextSpan range, string? diagnosticIdOpt = null, bool includeSuppressedDiagnostics = false, Func? addOperationScope = null, CancellationToken cancellationToken = default) + => service.GetDiagnosticsForSpanAsync(document, range, diagnosticIdOpt, includeSuppressedDiagnostics, highPriority: null, addOperationScope, cancellationToken); } } diff --git a/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs b/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs index 7dfda5f2a97a9..dc3814d6976d3 100644 --- a/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs +++ b/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs @@ -2,25 +2,28 @@ // 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.Diagnostics; + namespace Microsoft.CodeAnalysis.CodeActions { + /// + /// Internal priority used to bluntly place items in a light bulb in strict orderings. Priorities take + /// the highest precedence when ordering items so that we can ensure very important items get top prominance, + /// and low priority items do not. + /// + /// + /// If is used, the feature that specifies that value should + /// implement and return true for , + /// and + /// . This + /// will ensure that the analysis engine runs the providers that will produce those actions first, + /// thus allowing those actions to be computed and displayed prior to running all other providers. + /// internal enum CodeActionPriority { - // - // Summary: - // Lowest priority suggestion. Lowest = 0, - // - // Summary: - // Low priority suggestion. Low = 1, - // - // Summary: - // Medium priority suggestion. Medium = 2, - // - // Summary: - // High priority suggestion. High = 3 } } diff --git a/src/Workspaces/Core/Portable/CodeFixes/CodeFixProvider.cs b/src/Workspaces/Core/Portable/CodeFixes/CodeFixProvider.cs index bc008e1a21613..151cb3d7a8eeb 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/CodeFixProvider.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/CodeFixProvider.cs @@ -34,5 +34,11 @@ public abstract class CodeFixProvider /// public virtual FixAllProvider? GetFixAllProvider() => null; + + /// + /// If this is a high-priority code fix provider that should run and display results in a client + /// prior to running the non-high-priority code fix providers. + /// + internal virtual bool IsHighPriority => false; } } diff --git a/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringProvider.cs b/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringProvider.cs index 6610058b63a8e..2611d44d24419 100644 --- a/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringProvider.cs +++ b/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringProvider.cs @@ -17,6 +17,10 @@ public abstract class CodeRefactoringProvider /// public abstract Task ComputeRefactoringsAsync(CodeRefactoringContext context); + /// + /// If this is a high-priority refactoring that should run and display results in a client + /// prior to running the non-high-priority refactorings. + /// internal virtual bool IsHighPriority => false; } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Diagnostics/IBuiltInAnalyzer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Diagnostics/IBuiltInAnalyzer.cs index ce12586f61d0a..49065751dba01 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Diagnostics/IBuiltInAnalyzer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Diagnostics/IBuiltInAnalyzer.cs @@ -32,5 +32,11 @@ internal interface IBuiltInAnalyzer /// This indicates whether this built-in analyzer will only run on opened files. /// bool OpenFileOnly(OptionSet options); + + /// + /// If this is a high-priority analyzer that should run and display results in a client + /// prior to running the non-high-priority analyzer. + /// + bool IsHighPriority { get; } } } From 60b9671569ca53f2136890b1e61fbb23ee127518 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 May 2021 14:27:56 -0700 Subject: [PATCH 05/53] Fallout --- .../AbstractBuiltInCodeStyleDiagnosticAnalyzer_Core.cs | 1 + .../Core/Analyzers/AbstractCodeQualityDiagnosticAnalyzer.cs | 1 + .../AbstractRemoveUnnecessaryImportsDiagnosticAnalyzer.cs | 1 + .../DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs | 2 ++ .../EditAndContinue/EditAndContinueDiagnosticAnalyzer.cs | 2 ++ .../Diagnostics/AbstractSuppressionAllCodeTests.cs | 4 +++- .../Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs | 2 ++ .../EditAndContinue/Helpers/MockDiagnosticAnalyzerService.cs | 2 +- .../Analyzers/UnboundIdentifiersDiagnosticAnalyzerBase.cs | 1 + .../Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs | 3 ++- .../SimplifyTypeNamesDiagnosticAnalyzerBase.cs | 2 ++ .../Protocol/Handler/CodeActions/CodeActionHelpers.cs | 4 ++-- .../Internal/Diagnostics/FSharpDocumentDiagnosticAnalyzer.cs | 2 ++ .../Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs | 2 ++ .../Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs | 2 ++ .../Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb | 2 +- 16 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer_Core.cs b/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer_Core.cs index 8d0a0b3688a4f..07948d75c2145 100644 --- a/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer_Core.cs +++ b/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer_Core.cs @@ -44,6 +44,7 @@ protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(ImmutableArray false; public override ImmutableArray SupportedDiagnostics { get; } protected static DiagnosticDescriptor CreateDescriptorWithId( diff --git a/src/Analyzers/Core/Analyzers/AbstractCodeQualityDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/AbstractCodeQualityDiagnosticAnalyzer.cs index 07305204db787..5363009c03af5 100644 --- a/src/Analyzers/Core/Analyzers/AbstractCodeQualityDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/AbstractCodeQualityDiagnosticAnalyzer.cs @@ -28,6 +28,7 @@ protected AbstractCodeQualityDiagnosticAnalyzer( _generatedCodeAnalysisFlags = generatedCodeAnalysisFlags; } + public virtual bool IsHighPriority => false; public sealed override ImmutableArray SupportedDiagnostics { get; } public sealed override void Initialize(AnalysisContext context) diff --git a/src/Analyzers/Core/Analyzers/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsDiagnosticAnalyzer.cs index 4bfda4c530054..f1742bcb81ea6 100644 --- a/src/Analyzers/Core/Analyzers/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsDiagnosticAnalyzer.cs @@ -117,6 +117,7 @@ public override ImmutableArray SupportedDiagnostics } } + public bool IsHighPriority => false; public bool OpenFileOnly(OptionSet options) => false; public override void Initialize(AnalysisContext context) diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs index a2a1db99543d7..3a6486d173fcf 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs @@ -184,6 +184,8 @@ private static void AccessSupportedDiagnostics(DiagnosticAnalyzer analyzer) private class ThrowingDoNotCatchDiagnosticAnalyzer : ThrowingDiagnosticAnalyzer, IBuiltInAnalyzer where TLanguageKindEnum : struct { + public bool IsHighPriority => false; + public bool OpenFileOnly(OptionSet options) => false; public DiagnosticAnalyzerCategory GetAnalyzerCategory() diff --git a/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticAnalyzer.cs b/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticAnalyzer.cs index 1ffc31abfbf19..f0a05e773cfa3 100644 --- a/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticAnalyzer.cs +++ b/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticAnalyzer.cs @@ -29,6 +29,8 @@ public override ImmutableArray SupportedDiagnostics public DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SemanticDocumentAnalysis; + public bool IsHighPriority => false; + public bool OpenFileOnly(OptionSet options) => false; diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs index 6f28bc5e2268b..a66fa0cba5a94 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs @@ -139,7 +139,9 @@ public int GetHashCode(Diagnostic obj) internal class Analyzer : DiagnosticAnalyzer, IBuiltInAnalyzer { private readonly DiagnosticDescriptor _descriptor = - new DiagnosticDescriptor("TestId", "Test", "Test", "Test", DiagnosticSeverity.Warning, isEnabledByDefault: true); + new DiagnosticDescriptor("TestId", "Test", "Test", "Test", DiagnosticSeverity.Warning, isEnabledByDefault: true); + + public bool IsHighPriority => false; public bool OpenFileOnly(CodeAnalysis.Options.OptionSet options) => false; diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs index f28edd0623202..b682a13b3c758 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs @@ -1226,6 +1226,8 @@ public override void Initialize(AnalysisContext context) public DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SyntaxTreeWithoutSemanticsAnalysis; + public bool IsHighPriority => false; + public bool OpenFileOnly(CodeAnalysis.Options.OptionSet options) => true; } diff --git a/src/EditorFeatures/Test/EditAndContinue/Helpers/MockDiagnosticAnalyzerService.cs b/src/EditorFeatures/Test/EditAndContinue/Helpers/MockDiagnosticAnalyzerService.cs index 31d5d58912d0e..7fa3b311e84f0 100644 --- a/src/EditorFeatures/Test/EditAndContinue/Helpers/MockDiagnosticAnalyzerService.cs +++ b/src/EditorFeatures/Test/EditAndContinue/Helpers/MockDiagnosticAnalyzerService.cs @@ -40,7 +40,7 @@ public Task> GetDiagnosticsAsync(Solution solutio public Task> GetDiagnosticsForIdsAsync(Solution solution, ProjectId? projectId = null, DocumentId? documentId = null, ImmutableHashSet? diagnosticIds = null, bool includeSuppressedDiagnostics = false, CancellationToken cancellationToken = default) => throw new NotImplementedException(); - public Task> GetDiagnosticsForSpanAsync(Document document, TextSpan range, string? diagnosticIdOpt = null, bool includeSuppressedDiagnostics = false, Func? addOperationScope = null, CancellationToken cancellationToken = default) + public Task> GetDiagnosticsForSpanAsync(Document document, TextSpan range, string? diagnosticIdOpt = null, bool includeSuppressedDiagnostics = false, bool? highPriority = null, Func? addOperationScope = null, CancellationToken cancellationToken = default) => throw new NotImplementedException(); public Task> GetProjectDiagnosticsForIdsAsync(Solution solution, ProjectId? projectId = null, ImmutableHashSet? diagnosticIds = null, bool includeSuppressedDiagnostics = false, CancellationToken cancellationToken = default) diff --git a/src/Features/Core/Portable/Diagnostics/Analyzers/UnboundIdentifiersDiagnosticAnalyzerBase.cs b/src/Features/Core/Portable/Diagnostics/Analyzers/UnboundIdentifiersDiagnosticAnalyzerBase.cs index 6b2fe42006751..96e82fc55ce8e 100644 --- a/src/Features/Core/Portable/Diagnostics/Analyzers/UnboundIdentifiersDiagnosticAnalyzerBase.cs +++ b/src/Features/Core/Portable/Diagnostics/Analyzers/UnboundIdentifiersDiagnosticAnalyzerBase.cs @@ -24,6 +24,7 @@ internal abstract class UnboundIdentifiersDiagnosticAnalyzerBase false; public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptor, DiagnosticDescriptor2); public bool OpenFileOnly(OptionSet options) => false; diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs index 4ccafd0b57907..323ff2ed82e75 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs @@ -69,7 +69,8 @@ public Task TryAppendDiagnosticsForSpanAsync(Document document, TextSpan r if (_map.TryGetValue(document.Project.Solution.Workspace, out var analyzer)) { // always make sure that analyzer is called on background thread. - return Task.Run(() => analyzer.TryAppendDiagnosticsForSpanAsync(document, range, diagnostics, diagnosticId: null, includeSuppressedDiagnostics, blockForData: false, addOperationScope: null, cancellationToken), cancellationToken); + return Task.Run(() => analyzer.TryAppendDiagnosticsForSpanAsync( + document, range, diagnostics, diagnosticId: null, includeSuppressedDiagnostics, highPriority: null, blockForData: false, addOperationScope: null, cancellationToken), cancellationToken); } return SpecializedTasks.False; diff --git a/src/Features/Core/Portable/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs b/src/Features/Core/Portable/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs index 31fe39b5ae923..6c4c11b3d0f7f 100644 --- a/src/Features/Core/Portable/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs +++ b/src/Features/Core/Portable/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs @@ -81,6 +81,8 @@ protected SimplifyTypeNamesDiagnosticAnalyzerBase() { } + public bool IsHighPriority => false; + public bool OpenFileOnly(OptionSet options) { var preferTypeKeywordInDeclarationOption = options.GetOption( diff --git a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs index 6e20c8632c6d4..c0b0e3a6d68b4 100644 --- a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs +++ b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs @@ -233,10 +233,10 @@ private static CodeAction GetNestedActionsFromActionSet(IUnifiedSuggestedAction var codeFixes = await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeFixesAsync( document.Project.Solution.Workspace, codeFixService, document, textSpan, includeSuppressionFixes: true, - isBlocking: false, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); + highPriority: null, isBlocking: false, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); var codeRefactorings = await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeRefactoringsAsync( - document.Project.Solution.Workspace, codeRefactoringService, document, textSpan, isBlocking: false, + document.Project.Solution.Workspace, codeRefactoringService, document, textSpan, highPriority: null, isBlocking: false, addOperationScope: _ => null, filterOutsideSelection: false, cancellationToken).ConfigureAwait(false); var actionSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets(codeFixes, codeRefactorings, textSpan); diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpDocumentDiagnosticAnalyzer.cs b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpDocumentDiagnosticAnalyzer.cs index 44dca0e868e41..9319a39230304 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpDocumentDiagnosticAnalyzer.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpDocumentDiagnosticAnalyzer.cs @@ -62,6 +62,8 @@ public static ImmutableArray CreateSupportedDiagnostics() return dummyDescriptors.ToImmutable(); } + public bool IsHighPriority => false; + public override int Priority => 10; // Default = 50 public override ImmutableArray SupportedDiagnostics => _supportedDiagnostics; diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs index 8b065621e17e6..9bbae91f02987 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs @@ -48,6 +48,8 @@ internal class FSharpSimplifyNameDiagnosticAnalyzer : DocumentDiagnosticAnalyzer public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(_descriptor); + public bool IsHighPriority => false; + public override int Priority => 100; // Default = 50 public override Task> AnalyzeSemanticsAsync(Document document, CancellationToken cancellationToken) diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs index aa70166db4d6a..84a2cdea3cee2 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs @@ -50,6 +50,8 @@ internal class FSharpUnusedDeclarationsDiagnosticAnalyzer : DocumentDiagnosticAn public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(_descriptor); + public bool IsHighPriority => false; + public override int Priority => 80; // Default = 50 public override Task> AnalyzeSemanticsAsync(Document document, CancellationToken cancellationToken) diff --git a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb index 096686214cc9e..3a9d55baf940d 100644 --- a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb +++ b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb @@ -512,7 +512,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Public Sub Reanalyze(workspace As Workspace, Optional projectIds As IEnumerable(Of ProjectId) = Nothing, Optional documentIds As IEnumerable(Of DocumentId) = Nothing, Optional highPriority As Boolean = False) Implements IDiagnosticAnalyzerService.Reanalyze End Sub - Public Function GetDiagnosticsForSpanAsync(document As Document, range As TextSpan, Optional diagnosticId As String = Nothing, Optional includeSuppressedDiagnostics As Boolean = False, Optional addOperationScope As Func(Of String, IDisposable) = Nothing, Optional cancellationToken As CancellationToken = Nothing) As Task(Of ImmutableArray(Of DiagnosticData)) Implements IDiagnosticAnalyzerService.GetDiagnosticsForSpanAsync + Public Function GetDiagnosticsForSpanAsync(document As Document, range As TextSpan, Optional diagnosticId As String = Nothing, Optional includeSuppressedDiagnostics As Boolean = False, Optional highPriority As Boolean? = Nothing, Optional addOperationScope As Func(Of String, IDisposable) = Nothing, Optional cancellationToken As CancellationToken = Nothing) As Task(Of ImmutableArray(Of DiagnosticData)) Implements IDiagnosticAnalyzerService.GetDiagnosticsForSpanAsync Return SpecializedTasks.EmptyImmutableArray(Of DiagnosticData) End Function From 183333d9d6f9659f6de50b15751051d7500ed69e Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 May 2021 14:31:57 -0700 Subject: [PATCH 06/53] Add docs --- .../Portable/AddImport/AbstractAddImportCodeFixProvider.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs index 53da9bb8770e8..c14fce74a65af 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs @@ -31,6 +31,11 @@ protected AbstractAddImportCodeFixProvider( _symbolSearchService = symbolSearchService; } + /// + /// Add-using gets special priviliges as being the most used code-action, along with being a core + /// 'smart tag' feature in VS prior to us even having 'light bulbs'. We want them to be computed + /// first, ahead of everything else, and the main results should show up at the top of the list. + /// internal override bool IsHighPriority => true; public sealed override FixAllProvider GetFixAllProvider() From 4d32a88383a1d6d72385280d0c811a9d73737878 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 May 2021 15:26:08 -0700 Subject: [PATCH 07/53] Add flag --- src/Features/Core/Portable/CodeFixes/CodeFixService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Features/Core/Portable/CodeFixes/CodeFixService.cs b/src/Features/Core/Portable/CodeFixes/CodeFixService.cs index 2c805d0bcd132..bb4b47610c298 100644 --- a/src/Features/Core/Portable/CodeFixes/CodeFixService.cs +++ b/src/Features/Core/Portable/CodeFixes/CodeFixService.cs @@ -172,7 +172,7 @@ public async Task> GetFixesAsync( // order diagnostics by span. SortedDictionary>? aggregatedDiagnostics = null; var diagnostics = await _diagnosticService.GetDiagnosticsForSpanAsync( - document, range, diagnosticIdOpt: null, includeConfigurationFixes, addOperationScope, cancellationToken).ConfigureAwait(false); + document, range, diagnosticIdOpt: null, includeConfigurationFixes, highPriority, addOperationScope, cancellationToken).ConfigureAwait(false); foreach (var diagnostic in diagnostics) { if (diagnostic.IsSuppressed) From e1b9a3081504ab2ef6cf26ad94017201c4fd2ae2 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 May 2021 18:01:01 -0700 Subject: [PATCH 08/53] warning --- src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs b/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs index dc3814d6976d3..1fd6355842ac1 100644 --- a/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs +++ b/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs @@ -6,6 +6,7 @@ namespace Microsoft.CodeAnalysis.CodeActions { +#pragma warning disable CA1200 // Avoid using cref tags with a prefix /// /// Internal priority used to bluntly place items in a light bulb in strict orderings. Priorities take /// the highest precedence when ordering items so that we can ensure very important items get top prominance, @@ -26,4 +27,5 @@ internal enum CodeActionPriority Medium = 2, High = 3 } +#pragma warning restore CA1200 // Avoid using cref tags with a prefix } From 11224066e6f18a47634db84b38b2b07dd3a67ee1 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 May 2021 20:22:39 -0700 Subject: [PATCH 09/53] Simplify logic --- .../Suggestions/SuggestedActionsSource.cs | 9 ++--- .../Host/Status/NoOpWorkspaceStatusService.cs | 38 +++++++++++++++++++ 2 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 src/Workspaces/Core/Portable/Workspace/Host/Status/NoOpWorkspaceStatusService.cs diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 1314e286597e2..8417597c7aa0d 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -197,12 +197,9 @@ public async IAsyncEnumerable GetSuggestedActionsAsync( if (IsDisposed) yield break; - if (_workspaceStatusService != null) + using (operationContext.AddScope(allowCancellation: true, description: EditorFeaturesResources.Gathering_Suggestions_Waiting_for_the_solution_to_fully_load)) { - using (operationContext.AddScope(allowCancellation: true, description: EditorFeaturesResources.Gathering_Suggestions_Waiting_for_the_solution_to_fully_load)) - { - await _workspaceStatusService.WaitUntilFullyLoadedAsync(cancellationToken).ConfigureAwait(true); - } + await _workspaceStatusService.WaitUntilFullyLoadedAsync(cancellationToken).ConfigureAwait(true); } using (Logger.LogBlock(FunctionId.SuggestedActions_GetSuggestedActions, cancellationToken)) @@ -211,6 +208,8 @@ public async IAsyncEnumerable GetSuggestedActionsAsync( if (document == null) yield break; + // Compute and return the high pri set of fixes and refactorings first so the user + // can act on them immediately without waiting on the regular set. var highPriSet = await GetCodeFixesAndRefactoringsAsync( requestedActionCategories, document, range, AddOperationScope, highPriority: true, cancellationToken).ConfigureAwait(false); foreach (var set in highPriSet) diff --git a/src/Workspaces/Core/Portable/Workspace/Host/Status/NoOpWorkspaceStatusService.cs b/src/Workspaces/Core/Portable/Workspace/Host/Status/NoOpWorkspaceStatusService.cs new file mode 100644 index 0000000000000..01e17ac5732d9 --- /dev/null +++ b/src/Workspaces/Core/Portable/Workspace/Host/Status/NoOpWorkspaceStatusService.cs @@ -0,0 +1,38 @@ +// 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.Threading; +using System.Threading.Tasks; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Host +{ + internal sealed class NoOpWorkspaceStatusService : IWorkspaceStatusService + { + public static readonly IWorkspaceStatusService Instance = new NoOpWorkspaceStatusService(); + + private NoOpWorkspaceStatusService() + { + } + + event EventHandler IWorkspaceStatusService.StatusChanged + { + add { } + remove { } + } + + public Task WaitUntilFullyLoadedAsync(CancellationToken cancellationToken) + { + // by the default, we are always fully loaded + return Task.CompletedTask; + } + + public Task IsFullyLoadedAsync(CancellationToken cancellationToken) + { + // by the default, we are always fully loaded + return SpecializedTasks.True; + } + } +} From df499e8937414e1e58cdcd54393f37e683532c0a Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 May 2021 20:29:55 -0700 Subject: [PATCH 10/53] use a different code --- .../Core.Wpf/Suggestions/SuggestedActionsSource.cs | 2 +- .../Compiler/Core/Log/FunctionId.cs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 8417597c7aa0d..d700a1bb6b168 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -202,7 +202,7 @@ public async IAsyncEnumerable GetSuggestedActionsAsync( await _workspaceStatusService.WaitUntilFullyLoadedAsync(cancellationToken).ConfigureAwait(true); } - using (Logger.LogBlock(FunctionId.SuggestedActions_GetSuggestedActions, cancellationToken)) + using (Logger.LogBlock(FunctionId.SuggestedActions_GetSuggestedActionsAsync, cancellationToken)) { var document = range.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs index 138d11391b46d..d3318dd9f82cd 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs @@ -519,5 +519,7 @@ internal enum FunctionId InheritanceMargin_NavigateToTarget = 488, VS_ErrorReportingService_ShowGlobalErrorInfo = 489, + + SuggestedActions_GetSuggestedActionsAsync = 490, } } From 187ae223ac7e925b463c5f6401e0c1d9929f4463 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 4 May 2021 09:52:01 -0700 Subject: [PATCH 11/53] Move down into the executor --- .../Diagnostics/DocumentAnalysisExecutor.cs | 20 ++++++++++++++++ ...crementalAnalyzer_GetDiagnosticsForSpan.cs | 23 +------------------ .../Diagnostics/DocumentAnalysisScope.cs | 10 ++++---- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/Features/Core/Portable/Diagnostics/DocumentAnalysisExecutor.cs b/src/Features/Core/Portable/Diagnostics/DocumentAnalysisExecutor.cs index 8af079a925384..953b28fce83b2 100644 --- a/src/Features/Core/Portable/Diagnostics/DocumentAnalysisExecutor.cs +++ b/src/Features/Core/Portable/Diagnostics/DocumentAnalysisExecutor.cs @@ -63,6 +63,10 @@ public async Task> ComputeDiagnosticsAsync(Diagnosti { Contract.ThrowIfFalse(AnalysisScope.Analyzers.Contains(analyzer)); + // If the caller only wants us processing high pri items, then only proceed with certain analyzers. + if (!MatchesPriority(analyzer, AnalysisScope.HighPriority)) + return SpecializedCollections.EmptyEnumerable(); + var textDocument = AnalysisScope.TextDocument; var span = AnalysisScope.Span; var kind = AnalysisScope.Kind; @@ -148,6 +152,22 @@ public async Task> ComputeDiagnosticsAsync(Diagnosti return diagnostics; } + private static bool MatchesPriority(DiagnosticAnalyzer analyzer, bool? highPriority) + { + // If caller isn't asking for prioritized result, then run all analyzers. + if (highPriority == null) + return true; + + // Otherwise, check our special internal flag to tell. + // + // Note: the compiler analyzer is always considered high-pri. This is needed as there can + // be high pri fixers that operate entirely off of compiler diagnostics. For example, the + // add-using fixer is high pri, and it works off of compiler diagnostics. So we always have + // to run that one up front. + var analyzerIsHighPri = analyzer.IsCompilerAnalyzer() || analyzer is IBuiltInAnalyzer { IsHighPriority: true }; + return analyzerIsHighPri == highPriority; + } + private async Task> GetAnalysisResultAsync(DocumentAnalysisScope analysisScope, CancellationToken cancellationToken) { RoslynDebug.Assert(_compilationWithAnalyzers != null); diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs index 29d5ded4bc18c..35da826dec5bf 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs @@ -205,11 +205,7 @@ private async Task ComputeDocumentDiagnosticsAsync( ArrayBuilder list, CancellationToken cancellationToken) { - analyzers = analyzers.WhereAsArray(a => MatchesPriority(a)); - if (analyzers.IsEmpty) - return; - - var analysisScope = new DocumentAnalysisScope(_document, span, analyzers, kind); + var analysisScope = new DocumentAnalysisScope(_document, span, analyzers, kind, _highPriority); var executor = new DocumentAnalysisExecutor(analysisScope, _compilationWithAnalyzers, _owner._diagnosticAnalyzerRunner, logPerformanceInfo: false); foreach (var analyzer in analyzers) { @@ -229,23 +225,6 @@ private async Task ComputeDocumentDiagnosticsAsync( } } - private bool MatchesPriority(DiagnosticAnalyzer analyzer) - { - // If caller isn't asking for prioritized result, then run all analyzers. - if (_highPriority == null) - return true; - - // Even if the caller is asking for prioritized results, we always need to - // run the compiler analyzer to get the basic set of diagnostics that analyzers - // need to process. - if (analyzer.IsCompilerAnalyzer()) - return true; - - // Otherwise, check our special internal flag to tell. - var analyzerIsHighPri = analyzer is IBuiltInAnalyzer { IsHighPriority: true }; - return analyzerIsHighPri == _highPriority; - } - private bool ShouldInclude(DiagnosticData diagnostic) { return diagnostic.DocumentId == _document.Id && _range.IntersectsWith(diagnostic.GetTextSpan()) diff --git a/src/Workspaces/Core/Portable/Diagnostics/DocumentAnalysisScope.cs b/src/Workspaces/Core/Portable/Diagnostics/DocumentAnalysisScope.cs index ccf7abf5554c2..1930c05c8aaf1 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/DocumentAnalysisScope.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/DocumentAnalysisScope.cs @@ -22,7 +22,8 @@ public DocumentAnalysisScope( TextDocument document, TextSpan? span, ImmutableArray analyzers, - AnalysisKind kind) + AnalysisKind kind, + bool? highPriority) { Debug.Assert(kind == AnalysisKind.Syntax || kind == AnalysisKind.Semantic); Debug.Assert(!analyzers.IsDefaultOrEmpty); @@ -31,7 +32,7 @@ public DocumentAnalysisScope( Span = span; Analyzers = analyzers; Kind = kind; - + HighPriority = highPriority; _lazyAdditionalFile = new Lazy(ComputeAdditionalFile); } @@ -39,6 +40,7 @@ public DocumentAnalysisScope( public TextSpan? Span { get; } public ImmutableArray Analyzers { get; } public AnalysisKind Kind { get; } + public bool? HighPriority { get; } /// /// Gets the corresponding to the . @@ -55,9 +57,9 @@ private AdditionalText ComputeAdditionalFile() } public DocumentAnalysisScope WithSpan(TextSpan? span) - => new(TextDocument, span, Analyzers, Kind); + => new(TextDocument, span, Analyzers, Kind, HighPriority); public DocumentAnalysisScope WithAnalyzers(ImmutableArray analyzers) - => new(TextDocument, Span, analyzers, Kind); + => new(TextDocument, Span, analyzers, Kind, HighPriority); } } From a0e9b9fc95641291e6ae69fc7b763495f8c77e9f Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 4 May 2021 10:12:11 -0700 Subject: [PATCH 12/53] Run high and low priority each after the other. --- .../DefaultDiagnosticAnalyzerService.cs | 29 ++++++++++--------- ...IncrementalAnalyzer_IncrementalAnalyzer.cs | 8 ++++- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs index df9c2f081b6dd..7404e078877cf 100644 --- a/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs +++ b/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs @@ -135,11 +135,18 @@ bool IsSemanticAnalysisOn() private async Task AnalyzeForKindAsync(TextDocument document, AnalysisKind kind, CancellationToken cancellationToken) { - var diagnosticData = await GetDiagnosticsAsync(document, kind, cancellationToken).ConfigureAwait(false); + // collect high pri diagnostics first, followed by normal pri. + await AnalyzeForKindAsync(highPriority: true).ConfigureAwait(false); + await AnalyzeForKindAsync(highPriority: false).ConfigureAwait(false); - _service.RaiseDiagnosticsUpdated( - DiagnosticsUpdatedArgs.DiagnosticsCreated(new DefaultUpdateArgsId(_workspace.Kind, kind, document.Id), - _workspace, document.Project.Solution, document.Project.Id, document.Id, diagnosticData)); + async Task AnalyzeForKindAsync(bool highPriority) + { + var diagnosticData = await GetDiagnosticsAsync(document, kind, highPriority, cancellationToken).ConfigureAwait(false); + + _service.RaiseDiagnosticsUpdated( + DiagnosticsUpdatedArgs.DiagnosticsCreated(new DefaultUpdateArgsId(_workspace.Kind, kind, document.Id), + _workspace, document.Project.Solution, document.Project.Id, document.Id, diagnosticData)); + } } /// @@ -155,33 +162,27 @@ private async Task AnalyzeForKindAsync(TextDocument document, AnalysisKind kind, /// that provide all kinds of knobs/cache/persistency/OOP to get better perf over simplicity. /// private async Task> GetDiagnosticsAsync( - TextDocument document, AnalysisKind kind, CancellationToken cancellationToken) + TextDocument document, AnalysisKind kind, bool highPriority, CancellationToken cancellationToken) { var loadDiagnostic = await document.State.GetLoadDiagnosticAsync(cancellationToken).ConfigureAwait(false); if (loadDiagnostic != null) - { return ImmutableArray.Create(DiagnosticData.Create(loadDiagnostic, document)); - } var project = document.Project; var analyzers = GetAnalyzers(project.Solution.State.Analyzers, project); if (analyzers.IsEmpty) - { return ImmutableArray.Empty; - } var compilationWithAnalyzers = await AnalyzerHelper.CreateCompilationWithAnalyzersAsync( project, analyzers, includeSuppressedDiagnostics: false, cancellationToken).ConfigureAwait(false); - var analysisScope = new DocumentAnalysisScope(document, span: null, analyzers, kind); + var analysisScope = new DocumentAnalysisScope(document, span: null, analyzers, kind, highPriority); var executor = new DocumentAnalysisExecutor(analysisScope, compilationWithAnalyzers, _diagnosticAnalyzerRunner, logPerformanceInfo: true); - var builder = ArrayBuilder.GetInstance(); + using var _ = ArrayBuilder.GetInstance(out var builder); foreach (var analyzer in analyzers) - { builder.AddRange(await executor.ComputeDiagnosticsAsync(analyzer, cancellationToken).ConfigureAwait(false)); - } - return builder.ToImmutableAndFree(); + return builder.ToImmutable(); } private static ImmutableArray GetAnalyzers(HostDiagnosticAnalyzers hostAnalyzers, Project project) diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs index 2b9812266dfa6..abadcff415b52 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs @@ -35,6 +35,12 @@ public Task AnalyzeNonSourceDocumentAsync(TextDocument textDocument, InvocationR => AnalyzeDocumentForKindAsync(textDocument, AnalysisKind.Syntax, cancellationToken); private async Task AnalyzeDocumentForKindAsync(TextDocument document, AnalysisKind kind, CancellationToken cancellationToken) + { + await AnalyzeDocumentForKindAsync(document, kind, highPriority: true, cancellationToken).ConfigureAwait(false); + await AnalyzeDocumentForKindAsync(document, kind, highPriority: false, cancellationToken).ConfigureAwait(false); + } + + private async Task AnalyzeDocumentForKindAsync(TextDocument document, AnalysisKind kind, bool highPriority, CancellationToken cancellationToken) { try { @@ -74,7 +80,7 @@ private async Task AnalyzeDocumentForKindAsync(TextDocument document, AnalysisKi // Then, compute the diagnostics for non-cached state sets, and cache and raise diagnostic reported events for these diagnostics. if (nonCachedStateSets.Count > 0) { - var analysisScope = new DocumentAnalysisScope(document, span: null, nonCachedStateSets.SelectAsArray(s => s.Analyzer), kind); + var analysisScope = new DocumentAnalysisScope(document, span: null, nonCachedStateSets.SelectAsArray(s => s.Analyzer), kind, highPriority); var executor = new DocumentAnalysisExecutor(analysisScope, compilationWithAnalyzers, _diagnosticAnalyzerRunner, logPerformanceInfo: true, onAnalysisException: OnAnalysisException); foreach (var stateSet in nonCachedStateSets) { From 6003f2c2e5b7994b0ce81c9c9b6e79aca8f77f07 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 4 May 2021 14:11:35 -0700 Subject: [PATCH 13/53] move down --- .../Services/DiagnosticAnalyzer/DiagnosticComputer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs index b99ff55be839f..1d80506100281 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs @@ -109,7 +109,7 @@ private async Task AnalyzeAsync( CancellationToken cancellationToken) { var documentAnalysisScope = _document != null - ? new DocumentAnalysisScope(_document, _span, analyzers, _analysisKind!.Value) + ? new DocumentAnalysisScope(_document, _span, analyzers, _analysisKind!.Value, highPriority: null) : null; var (analysisResult, additionalPragmaSuppressionDiagnostics) = await compilationWithAnalyzers.GetAnalysisResultAsync( From ed9bf08cba1f560f4075b3c6792ab07f532576bd Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 4 May 2021 14:39:47 -0700 Subject: [PATCH 14/53] Push down --- .../Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs | 6 +++--- .../Core/Portable/Diagnostics/DiagnosticArguments.cs | 9 +++++++-- ...crementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs | 1 + .../Core/Test.Next/Remote/JsonConverterTests.cs | 1 + .../Services/DiagnosticAnalyzer/DiagnosticComputer.cs | 6 ++++-- .../RemoteDiagnosticAnalyzerService.cs | 1 + 6 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs index b682a13b3c758..4567e7fdb92c2 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs @@ -975,7 +975,7 @@ internal async Task TestOnlyRequiredAnalyzerExecutedDuringDiagnosticComputation( var document = documentAnalysis ? project.Documents.Single() : null; var diagnosticComputer = new DiagnosticComputer(document, project, span: null, AnalysisKind.Semantic, new DiagnosticAnalyzerInfoCache()); var diagnosticsMapResults = await diagnosticComputer.GetDiagnosticsAsync(analyzerIdsToRequestDiagnostics, reportSuppressedDiagnostics: false, - logPerformanceInfo: false, getTelemetryInfo: false, cancellationToken: CancellationToken.None); + logPerformanceInfo: false, getTelemetryInfo: false, highPriority: null, cancellationToken: CancellationToken.None); Assert.False(analyzer2.ReceivedSymbolCallback); Assert.Equal(1, diagnosticsMapResults.Diagnostics.Length); @@ -1027,7 +1027,7 @@ void M() try { _ = await diagnosticComputer.GetDiagnosticsAsync(analyzerIds, reportSuppressedDiagnostics: false, - logPerformanceInfo: false, getTelemetryInfo: false, cancellationToken: analyzer.CancellationToken); + logPerformanceInfo: false, getTelemetryInfo: false, highPriority: null, cancellationToken: analyzer.CancellationToken); throw ExceptionUtilities.Unreachable; } @@ -1039,7 +1039,7 @@ void M() // Then invoke analysis without cancellation token, and verify non-cancelled diagnostic. var diagnosticsMap = await diagnosticComputer.GetDiagnosticsAsync(analyzerIds, reportSuppressedDiagnostics: false, - logPerformanceInfo: false, getTelemetryInfo: false, cancellationToken: CancellationToken.None); + logPerformanceInfo: false, getTelemetryInfo: false, highPriority: null, cancellationToken: CancellationToken.None); var builder = diagnosticsMap.Diagnostics.Single().diagnosticMap; var diagnostic = kind == AnalysisKind.Syntax ? builder.Syntax.Single().Item2.Single() : builder.Semantic.Single().Item2.Single(); Assert.Equal(CancellationTestAnalyzer.NonCanceledDiagnosticId, diagnostic.Id); diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs index 5189b74c71bb6..1f8c25e2c8895 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs @@ -56,16 +56,19 @@ internal class DiagnosticArguments [DataMember(Order = 5)] public AnalysisKind? DocumentAnalysisKind; + [DataMember(Order = 6)] + public bool? HighPriority; + /// /// Project ID for the document or project for which diagnostics need to be computed. /// - [DataMember(Order = 6)] + [DataMember(Order = 7)] public ProjectId ProjectId; /// /// Array of analyzer IDs for analyzers that need to be executed for computing diagnostics. /// - [DataMember(Order = 7)] + [DataMember(Order = 8)] public string[] AnalyzerIds; public DiagnosticArguments( @@ -75,6 +78,7 @@ public DiagnosticArguments( DocumentId? documentId, TextSpan? documentSpan, AnalysisKind? documentAnalysisKind, + bool? highPriority, ProjectId projectId, string[] analyzerIds) { @@ -90,6 +94,7 @@ public DiagnosticArguments( DocumentId = documentId; DocumentSpan = documentSpan; DocumentAnalysisKind = documentAnalysisKind; + HighPriority = highPriority; ProjectId = projectId; AnalyzerIds = analyzerIds; } diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs index 066075ae47bc9..414c55888d59f 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs @@ -180,6 +180,7 @@ private static async Task GetDiagnosticsAsync( bool reportSuppressedDiagnostics, bool logPerformanceInfo, bool getTelemetryInfo, + bool? highPriority, CancellationToken cancellationToken) { var (compilationWithAnalyzers, analyzerToIdMap) = await GetOrCreateCompilationWithAnalyzersAsync( @@ -88,7 +89,7 @@ public async Task GetDiagnosticsAsync( try { return await AnalyzeAsync(compilationWithAnalyzers, analyzerToIdMap, analyzers, skippedAnalyzersInfo, - reportSuppressedDiagnostics, logPerformanceInfo, getTelemetryInfo, cancellationToken).ConfigureAwait(false); + reportSuppressedDiagnostics, logPerformanceInfo, getTelemetryInfo, highPriority, cancellationToken).ConfigureAwait(false); } catch { @@ -106,10 +107,11 @@ private async Task AnalyzeAsync( bool reportSuppressedDiagnostics, bool logPerformanceInfo, bool getTelemetryInfo, + bool? highPriority, CancellationToken cancellationToken) { var documentAnalysisScope = _document != null - ? new DocumentAnalysisScope(_document, _span, analyzers, _analysisKind!.Value, highPriority: null) + ? new DocumentAnalysisScope(_document, _span, analyzers, _analysisKind!.Value, highPriority) : null; var (analysisResult, additionalPragmaSuppressionDiagnostics) = await compilationWithAnalyzers.GetAnalysisResultAsync( diff --git a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs index 4bf6b1c0da442..1f554b644afa8 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs @@ -65,6 +65,7 @@ public ValueTask CalculateDiagnosticsAsyn reportSuppressedDiagnostics: arguments.ReportSuppressedDiagnostics, logPerformanceInfo: arguments.LogPerformanceInfo, getTelemetryInfo: arguments.GetTelemetryInfo, + highPriority: arguments.HighPriority, cancellationToken).ConfigureAwait(false); // save log for debugging From 8477a121a8b488ba0703bba5558290e54b0ec4c1 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 5 May 2021 09:22:19 -0700 Subject: [PATCH 15/53] temp --- .../Suggestions/SuggestedActionsSource.cs | 52 +++++++++++++++---- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index d700a1bb6b168..ca9ab3f18950e 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -216,18 +216,21 @@ public async IAsyncEnumerable GetSuggestedActionsAsync( yield return set; var lowPriSet = await GetCodeFixesAndRefactoringsAsync( - requestedActionCategories, document, range, AddOperationScope, highPriority: false, cancellationToken).ConfigureAwait(false); - foreach (var set in lowPriSet) + state, requestedActionCategories, document, range, AddOperationScope, highPriority: false, cancellationToken).ConfigureAwait(false); + await foreach (var set in lowPriSet) yield return set; } + yield break; + IDisposable? AddOperationScope(string description) { return operationContext.AddScope(allowCancellation: true, string.Format(EditorFeaturesResources.Gathering_Suggestions_0, description)); } } - private async Task> GetCodeFixesAndRefactoringsAsync( + private async Task> GetCodeFixesAndRefactoringsAsync( + ReferenceCountedDisposable state, ISuggestedActionCategorySet requestedActionCategories, Document document, SnapshotSpan range, @@ -238,7 +241,7 @@ private async Task> GetCodeFixesAndRefactoringsA var workspace = document.Project.Solution.Workspace; var supportsFeatureService = workspace.Services.GetRequiredService(); - var selection = TryGetCodeRefactoringSelection(range); + var selection = TryGetCodeRefactoringSelection(state, range); var fixesTask = GetCodeFixesAsync( supportsFeatureService, requestedActionCategories, workspace, document, range, @@ -247,16 +250,43 @@ private async Task> GetCodeFixesAndRefactoringsA supportsFeatureService, requestedActionCategories, workspace, document, selection, addOperationScope, highPriority, isBlocking: false, cancellationToken); - await Task.WhenAll(fixesTask, refactoringsTask).ConfigureAwait(false); + if (highPriority) + { + // in a high pri scenario, return data as soon as possible so that the user can interact with them. + var firstTask = await Task.WhenAny(fixesTask, refactoringsTask).ConfigureAwait(false); + var secondTask = firstTask == fixesTask ? refactoringsTask : fixesTask; - var fixes = await fixesTask.ConfigureAwait(false); - var refactorings = await refactoringsTask.ConfigureAwait(false); + if (firstTask == fixesTask) + { + var fixes = await firstTask.ConfigureAwait(false); + + var filteredSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets( + fixes, ImmutableArray.Empty, selection); + if (filteredSets.HasValue) + yield return filteredSets.Value.Select(s => ConvertToSuggestedActionSet(s, state.Target.Owner, state.Target.SubjectBuffer)).WhereNotNull(); + + var refactorings = await secondTask.ConfigureAwait(false); + filteredSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets( + ImmutableArray.Empty, refactorings, selection); + if (filteredSets.HasValue) + yield return filteredSets.Value.Select(s => ConvertToSuggestedActionSet(s, state.Target.Owner, state.Target.SubjectBuffer)).WhereNotNull(); + } + else + { - var filteredSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets(fixes, refactorings, selection); - if (!filteredSets.HasValue) - return SpecializedCollections.EmptyEnumerable(); + } + } + else + { + await Task.WhenAll(fixesTask, refactoringsTask).ConfigureAwait(false); - return filteredSets.Value.Select(s => ConvertToSuggestedActionSet(s)).WhereNotNull(); + var fixes = await fixesTask.ConfigureAwait(false); + var refactorings = await refactoringsTask.ConfigureAwait(false); + + var filteredSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets(fixes, refactorings, selection); + if (filteredSets.HasValue) + yield return filteredSets.Value.Select(s => ConvertToSuggestedActionSet(s, state.Target.Owner, state.Target.SubjectBuffer)).WhereNotNull(); + } } [return: NotNullIfNotNull("unifiedSuggestedActionSet")] From cb1a318f38c4d44c26c0a6a7f08c839efae9520d Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 5 May 2021 09:34:32 -0700 Subject: [PATCH 16/53] Simplify suggested action computation. --- .../Suggestions/SuggestedActionsSource.cs | 7 +------ .../UnifiedSuggestedActionsSource.cs | 6 ++---- .../Handler/CodeActions/CodeActionHelpers.cs | 16 ++++++---------- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index ca9ab3f18950e..3e60654a80a7b 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -177,12 +177,7 @@ public bool TryGetTelemetryId(out Guid telemetryId) document, selection, addOperationScope, cancellationToken); var filteredSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets(fixes, refactorings, selection); - if (!filteredSets.HasValue) - { - return null; - } - - return filteredSets.Value.SelectAsArray((s, arg) => ConvertToSuggestedActionSet(s, arg.Owner, arg.SubjectBuffer), (state.Target.Owner, state.Target.SubjectBuffer)).WhereNotNull(); + return filteredSets.SelectAsArray((s, arg) => ConvertToSuggestedActionSet(s, arg.Owner, arg.SubjectBuffer), (state.Target.Owner, state.Target.SubjectBuffer)).WhereNotNull(); } } diff --git a/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs b/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs index 2818c9b9b31d3..6eaaedf4fd13b 100644 --- a/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs +++ b/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs @@ -522,7 +522,7 @@ private static UnifiedSuggestedActionSetPriority GetUnifiedSuggestedActionSetPri /// Should be called with the results from /// and . /// - public static ImmutableArray? FilterAndOrderActionSets( + public static ImmutableArray FilterAndOrderActionSets( ImmutableArray fixes, ImmutableArray refactorings, TextSpan? selectionOpt) @@ -531,9 +531,7 @@ private static UnifiedSuggestedActionSetPriority GetUnifiedSuggestedActionSetPri // ordered against each other. var result = GetInitiallyOrderedActionSets(selectionOpt, fixes, refactorings); if (result.IsEmpty) - { - return null; - } + return ImmutableArray.Empty; // Now that we have the entire set of action sets, inline, sort and filter // them appropriately against each other. diff --git a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs index c0b0e3a6d68b4..1030e7cc60a28 100644 --- a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs +++ b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs @@ -39,12 +39,10 @@ public static async Task GetVSCodeActionsAsync( { var actionSets = await GetActionSetsAsync( document, codeFixService, codeRefactoringService, request.Range, cancellationToken).ConfigureAwait(false); - if (!actionSets.HasValue) - { + if (actionSets.IsDefaultOrEmpty) return Array.Empty(); - } - await codeActionsCache.UpdateActionSetsAsync(document, request.Range, actionSets.Value, cancellationToken).ConfigureAwait(false); + await codeActionsCache.UpdateActionSetsAsync(document, request.Range, actionSets, cancellationToken).ConfigureAwait(false); var documentText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); // Each suggested action set should have a unique set number, which is used for grouping code actions together. @@ -166,17 +164,15 @@ public static async Task> GetCodeActionsAsync( { var actionSets = await GetActionSetsAsync( document, codeFixService, codeRefactoringService, selection, cancellationToken).ConfigureAwait(false); - if (!actionSets.HasValue) + if (actionSets.IsDefaultOrEmpty) { actionSets = await GetActionSetsAsync( document, codeFixService, codeRefactoringService, selection, cancellationToken).ConfigureAwait(false); - if (!actionSets.HasValue) - { + if (actionSets.IsDefaultOrEmpty) return ImmutableArray.Empty; - } - await codeActionsCache.UpdateActionSetsAsync(document, selection, actionSets.Value, cancellationToken).ConfigureAwait(false); + await codeActionsCache.UpdateActionSetsAsync(document, selection, actionSets, cancellationToken).ConfigureAwait(false); } var _ = ArrayBuilder.GetInstance(out var codeActions); @@ -221,7 +217,7 @@ private static CodeAction GetNestedActionsFromActionSet(IUnifiedSuggestedAction codeAction.Title, nestedActions.ToImmutable(), codeAction.IsInlinable, codeAction.Priority); } - private static async Task?> GetActionSetsAsync( + private static async Task> GetActionSetsAsync( Document document, ICodeFixService codeFixService, ICodeRefactoringService codeRefactoringService, From a2ba3089c9ebc212a0c924eb3d099b0e3a1e5f9c Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 5 May 2021 09:35:59 -0700 Subject: [PATCH 17/53] Simplify --- .../Core.Wpf/Suggestions/SuggestedActionsSource.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 3e60654a80a7b..e0e04de06dcab 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -177,7 +177,7 @@ public bool TryGetTelemetryId(out Guid telemetryId) document, selection, addOperationScope, cancellationToken); var filteredSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets(fixes, refactorings, selection); - return filteredSets.SelectAsArray((s, arg) => ConvertToSuggestedActionSet(s, arg.Owner, arg.SubjectBuffer), (state.Target.Owner, state.Target.SubjectBuffer)).WhereNotNull(); + return filteredSets.SelectAsArray(s => ConvertToSuggestedActionSet(s, state.Target.Owner, state.Target.SubjectBuffer)).WhereNotNull(); } } From 34642f46778ca003b4ab51b9315469ef5595932c Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 5 May 2021 09:48:52 -0700 Subject: [PATCH 18/53] PRoduce results as soon as we have them --- .../Suggestions/SuggestedActionsSource.cs | 64 ++++++++++--------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index e0e04de06dcab..685ff7ae4ad5d 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -8,6 +8,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; @@ -176,11 +177,16 @@ public bool TryGetTelemetryId(out Guid telemetryId) state, supportsFeatureService, requestedActionCategories, workspace, document, selection, addOperationScope, cancellationToken); - var filteredSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets(fixes, refactorings, selection); - return filteredSets.SelectAsArray(s => ConvertToSuggestedActionSet(s, state.Target.Owner, state.Target.SubjectBuffer)).WhereNotNull(); + return ConvertToSuggestedActionSets(state, selection, fixes, refactorings); } } + private IEnumerable ConvertToSuggestedActionSets(ReferenceCountedDisposable state, TextSpan? selection, ImmutableArray fixes, ImmutableArray refactorings) + { + var filteredSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets(fixes, refactorings, selection); + return filteredSets.SelectAsArray(s => ConvertToSuggestedActionSet(s, state.Target.Owner, state.Target.SubjectBuffer)).WhereNotNull(); + } + public async IAsyncEnumerable GetSuggestedActionsAsync( ISuggestedActionCategorySet requestedActionCategories, SnapshotSpan range, @@ -205,13 +211,11 @@ public async IAsyncEnumerable GetSuggestedActionsAsync( // Compute and return the high pri set of fixes and refactorings first so the user // can act on them immediately without waiting on the regular set. - var highPriSet = await GetCodeFixesAndRefactoringsAsync( - requestedActionCategories, document, range, AddOperationScope, highPriority: true, cancellationToken).ConfigureAwait(false); - foreach (var set in highPriSet) + var highPriSet = GetCodeFixesAndRefactoringsAsync(state, requestedActionCategories, document, range, AddOperationScope, highPriority: true, cancellationToken); + await foreach (var set in highPriSet) yield return set; - var lowPriSet = await GetCodeFixesAndRefactoringsAsync( - state, requestedActionCategories, document, range, AddOperationScope, highPriority: false, cancellationToken).ConfigureAwait(false); + var lowPriSet = GetCodeFixesAndRefactoringsAsync(state, requestedActionCategories, document, range, AddOperationScope, highPriority: false, cancellationToken); await foreach (var set in lowPriSet) yield return set; } @@ -224,14 +228,14 @@ public async IAsyncEnumerable GetSuggestedActionsAsync( } } - private async Task> GetCodeFixesAndRefactoringsAsync( + private async IAsyncEnumerable GetCodeFixesAndRefactoringsAsync( ReferenceCountedDisposable state, ISuggestedActionCategorySet requestedActionCategories, Document document, SnapshotSpan range, Func addOperationScope, bool highPriority, - CancellationToken cancellationToken) + [EnumeratorCancellation] CancellationToken cancellationToken) { var workspace = document.Project.Solution.Workspace; var supportsFeatureService = workspace.Services.GetRequiredService(); @@ -248,39 +252,37 @@ private async Task> GetCodeFixesAndRefactor if (highPriority) { // in a high pri scenario, return data as soon as possible so that the user can interact with them. + // this is especially important for state-machine oriented refactorings (like rename) where the user + // should always have access to them effectively synchronously. var firstTask = await Task.WhenAny(fixesTask, refactoringsTask).ConfigureAwait(false); var secondTask = firstTask == fixesTask ? refactoringsTask : fixesTask; - if (firstTask == fixesTask) - { - var fixes = await firstTask.ConfigureAwait(false); - - var filteredSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets( - fixes, ImmutableArray.Empty, selection); - if (filteredSets.HasValue) - yield return filteredSets.Value.Select(s => ConvertToSuggestedActionSet(s, state.Target.Owner, state.Target.SubjectBuffer)).WhereNotNull(); - - var refactorings = await secondTask.ConfigureAwait(false); - filteredSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets( - ImmutableArray.Empty, refactorings, selection); - if (filteredSets.HasValue) - yield return filteredSets.Value.Select(s => ConvertToSuggestedActionSet(s, state.Target.Owner, state.Target.SubjectBuffer)).WhereNotNull(); - } - else + var orderedTasks = new[] { firstTask, secondTask }; + foreach (var task in orderedTasks) { - + if (task == fixesTask) + { + var fixes = await fixesTask.ConfigureAwait(false); + foreach (var set in ConvertToSuggestedActionSets(state, selection, fixes, ImmutableArray.Empty)) + yield return set; + } + else + { + Contract.ThrowIfFalse(task == refactoringsTask); + + var refactorings = await refactoringsTask.ConfigureAwait(false); + foreach (var set in ConvertToSuggestedActionSets(state, selection, ImmutableArray.Empty, refactorings)) + yield return set; + } } } else { await Task.WhenAll(fixesTask, refactoringsTask).ConfigureAwait(false); - var fixes = await fixesTask.ConfigureAwait(false); var refactorings = await refactoringsTask.ConfigureAwait(false); - - var filteredSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets(fixes, refactorings, selection); - if (filteredSets.HasValue) - yield return filteredSets.Value.Select(s => ConvertToSuggestedActionSet(s, state.Target.Owner, state.Target.SubjectBuffer)).WhereNotNull(); + foreach (var set in ConvertToSuggestedActionSets(state, selection, fixes, refactorings)) + yield return set; } } From c0b4244dbd0952a381c30f48df2348448e1acd69 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 5 May 2021 11:15:36 -0700 Subject: [PATCH 19/53] Switch to valuetask --- .../Core.Wpf/Suggestions/SuggestedActionsSource.cs | 2 +- .../UnifiedSuggestedActionsSource.cs | 2 +- .../Handler/CodeActions/CodeActionHelpers.cs | 12 +++--------- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 685ff7ae4ad5d..52be97d75db0a 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -380,7 +380,7 @@ private async Task> GetCodeFixesAsync( const bool includeSuppressionFixes = true; return await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeFixesAsync( - workspace, _owner._codeFixService, document, range.Span.ToTextSpan(), + workspace, state.Target.Owner._codeFixService, document, range.Span.ToTextSpan(), includeSuppressionFixes, highPriority, isBlocking, addOperationScope, cancellationToken).ConfigureAwait(false); } diff --git a/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs b/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs index 6eaaedf4fd13b..7a21067039de4 100644 --- a/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs +++ b/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs @@ -29,7 +29,7 @@ internal class UnifiedSuggestedActionsSource /// /// Gets, filters, and orders code fixes. /// - public static async Task> GetFilterAndOrderCodeFixesAsync( + public static async ValueTask> GetFilterAndOrderCodeFixesAsync( Workspace workspace, ICodeFixService codeFixService, Document document, diff --git a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs index 1030e7cc60a28..09665e9d2033b 100644 --- a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs +++ b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs @@ -165,15 +165,9 @@ public static async Task> GetCodeActionsAsync( var actionSets = await GetActionSetsAsync( document, codeFixService, codeRefactoringService, selection, cancellationToken).ConfigureAwait(false); if (actionSets.IsDefaultOrEmpty) - { - actionSets = await GetActionSetsAsync( - document, codeFixService, codeRefactoringService, selection, cancellationToken).ConfigureAwait(false); - - if (actionSets.IsDefaultOrEmpty) - return ImmutableArray.Empty; + return ImmutableArray.Empty; - await codeActionsCache.UpdateActionSetsAsync(document, selection, actionSets, cancellationToken).ConfigureAwait(false); - } + await codeActionsCache.UpdateActionSetsAsync(document, selection, actionSets, cancellationToken).ConfigureAwait(false); var _ = ArrayBuilder.GetInstance(out var codeActions); foreach (var set in actionSets) @@ -217,7 +211,7 @@ private static CodeAction GetNestedActionsFromActionSet(IUnifiedSuggestedAction codeAction.Title, nestedActions.ToImmutable(), codeAction.IsInlinable, codeAction.Priority); } - private static async Task> GetActionSetsAsync( + private static async ValueTask> GetActionSetsAsync( Document document, ICodeFixService codeFixService, ICodeRefactoringService codeRefactoringService, From b4834c93f70e4f2576be2f201bd4f071e5f0e6b5 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 5 May 2021 15:06:53 -0700 Subject: [PATCH 20/53] fallout --- .../Suggestions/SuggestedActionsSource.cs | 29 ++++++++++++------- .../ICodeRefactoringService.cs | 4 +-- .../UnifiedSuggestedActionsSource.cs | 2 +- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 52be97d75db0a..d22ceba7e5223 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -195,12 +195,17 @@ public async IAsyncEnumerable GetSuggestedActionsAsync( AssertIsForeground(); var cancellationToken = operationContext.UserCancellationToken; - if (IsDisposed) + using var state = _state.TryAddReference(); + if (state is null) + yield break; + + var workspace = state.Target.Workspace; + if (workspace == null) yield break; using (operationContext.AddScope(allowCancellation: true, description: EditorFeaturesResources.Gathering_Suggestions_Waiting_for_the_solution_to_fully_load)) { - await _workspaceStatusService.WaitUntilFullyLoadedAsync(cancellationToken).ConfigureAwait(true); + await workspace.Services.GetRequiredService().WaitUntilFullyLoadedAsync(cancellationToken).ConfigureAwait(true); } using (Logger.LogBlock(FunctionId.SuggestedActions_GetSuggestedActionsAsync, cancellationToken)) @@ -243,10 +248,10 @@ private async IAsyncEnumerable GetCodeFixesAndRefactoringsAs var selection = TryGetCodeRefactoringSelection(state, range); var fixesTask = GetCodeFixesAsync( - supportsFeatureService, requestedActionCategories, workspace, document, range, + state, supportsFeatureService, requestedActionCategories, workspace, document, range, addOperationScope, highPriority, isBlocking: false, cancellationToken); var refactoringsTask = GetRefactoringsAsync( - supportsFeatureService, requestedActionCategories, workspace, document, selection, + state, supportsFeatureService, requestedActionCategories, workspace, document, selection, addOperationScope, highPriority, isBlocking: false, cancellationToken); if (highPriority) @@ -353,11 +358,12 @@ private ImmutableArray GetCodeFixes( this.AssertIsForeground(); return GetCodeFixesAsync( - supportsFeatureService, requestedActionCategories, workspace, document, range, + state, supportsFeatureService, requestedActionCategories, workspace, document, range, addOperationScope, highPriority: null, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); } - private async Task> GetCodeFixesAsync( + private static async Task> GetCodeFixesAsync( + ReferenceCountedDisposable state, ITextBufferSupportsFeatureService supportsFeatureService, ISuggestedActionCategorySet requestedActionCategories, Workspace workspace, @@ -368,8 +374,8 @@ private async Task> GetCodeFixesAsync( bool isBlocking, CancellationToken cancellationToken) { - if (_owner._codeFixService == null || - !supportsFeatureService.SupportsCodeFixes(_subjectBuffer) || + if (state.Target.Owner._codeFixService == null || + !supportsFeatureService.SupportsCodeFixes(state.Target.SubjectBuffer) || !requestedActionCategories.Contains(PredefinedSuggestedActionCategoryNames.CodeFix)) { return ImmutableArray.Empty; @@ -411,11 +417,12 @@ private ImmutableArray GetRefactorings( { this.AssertIsForeground(); return GetRefactoringsAsync( - supportsFeatureService, requestedActionCategories, workspace, document, selection, + state, supportsFeatureService, requestedActionCategories, workspace, document, selection, addOperationScope, highPriority: null, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); } - private async Task> GetRefactoringsAsync( + private static async Task> GetRefactoringsAsync( + ReferenceCountedDisposable state, ITextBufferSupportsFeatureService supportsFeatureService, ISuggestedActionCategorySet requestedActionCategories, Workspace workspace, @@ -441,7 +448,7 @@ private async Task> GetRefactoringsAsy var filterOutsideSelection = !requestedActionCategories.Contains(PredefinedSuggestedActionCategoryNames.Refactoring); return await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeRefactoringsAsync( - workspace, _owner._codeRefactoringService, document, selection.Value, highPriority, isBlocking, + workspace, state.Target.Owner._codeRefactoringService, document, selection.Value, highPriority, isBlocking, addOperationScope, filterOutsideSelection, cancellationToken).ConfigureAwait(false); } diff --git a/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs index c6bf7365ecbc4..b9bb2bceb3211 100644 --- a/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs @@ -14,7 +14,7 @@ internal interface ICodeRefactoringService { Task HasRefactoringsAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken); - Task> GetRefactoringsAsync(Document document, TextSpan textSpan, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken); + Task> GetRefactoringsAsync(Document document, TextSpan textSpan, bool? highPriority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken); } internal static class ICodeRefactoringServiceExtensions @@ -23,6 +23,6 @@ public static Task> GetRefactoringsAsync(this IC => service.GetRefactoringsAsync(document, state, isBlocking: false, cancellationToken); public static Task> GetRefactoringsAsync(this ICodeRefactoringService service, Document document, TextSpan state, bool isBlocking, CancellationToken cancellationToken) - => service.GetRefactoringsAsync(document, state, isBlocking, addOperationScope: _ => null, cancellationToken); + => service.GetRefactoringsAsync(document, state, highPriority: null, isBlocking, addOperationScope: _ => null, cancellationToken); } } diff --git a/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs b/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs index 7a21067039de4..eba406493035a 100644 --- a/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs +++ b/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs @@ -406,7 +406,7 @@ public static async Task> GetFilterAnd // the UI thread. var refactorings = await Task.Run( () => codeRefactoringService.GetRefactoringsAsync( - document, selection, isBlocking, addOperationScope, + document, selection, highPriority, isBlocking, addOperationScope, cancellationToken), cancellationToken).ConfigureAwait(false); var filteredRefactorings = FilterOnAnyThread(refactorings, selection, filterOutsideSelection); From ea93f6212f2704c3ae87951eaa303dc08861e364 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 5 May 2021 15:10:23 -0700 Subject: [PATCH 21/53] restore --- .../DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs index 35da826dec5bf..8bdcff12ad7b3 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs @@ -205,6 +205,9 @@ private async Task ComputeDocumentDiagnosticsAsync( ArrayBuilder list, CancellationToken cancellationToken) { + if (analyzers.IsEmpty) + return; + var analysisScope = new DocumentAnalysisScope(_document, span, analyzers, kind, _highPriority); var executor = new DocumentAnalysisExecutor(analysisScope, _compilationWithAnalyzers, _owner._diagnosticAnalyzerRunner, logPerformanceInfo: false); foreach (var analyzer in analyzers) From 79765d60aba6a83fee0c5daac75733a58fb3a93f Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 5 May 2021 15:16:10 -0700 Subject: [PATCH 22/53] Remove --- .../Host/Status/NoOpWorkspaceStatusService.cs | 38 ------------------- 1 file changed, 38 deletions(-) delete mode 100644 src/Workspaces/Core/Portable/Workspace/Host/Status/NoOpWorkspaceStatusService.cs diff --git a/src/Workspaces/Core/Portable/Workspace/Host/Status/NoOpWorkspaceStatusService.cs b/src/Workspaces/Core/Portable/Workspace/Host/Status/NoOpWorkspaceStatusService.cs deleted file mode 100644 index 01e17ac5732d9..0000000000000 --- a/src/Workspaces/Core/Portable/Workspace/Host/Status/NoOpWorkspaceStatusService.cs +++ /dev/null @@ -1,38 +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. - -using System; -using System.Threading; -using System.Threading.Tasks; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Host -{ - internal sealed class NoOpWorkspaceStatusService : IWorkspaceStatusService - { - public static readonly IWorkspaceStatusService Instance = new NoOpWorkspaceStatusService(); - - private NoOpWorkspaceStatusService() - { - } - - event EventHandler IWorkspaceStatusService.StatusChanged - { - add { } - remove { } - } - - public Task WaitUntilFullyLoadedAsync(CancellationToken cancellationToken) - { - // by the default, we are always fully loaded - return Task.CompletedTask; - } - - public Task IsFullyLoadedAsync(CancellationToken cancellationToken) - { - // by the default, we are always fully loaded - return SpecializedTasks.True; - } - } -} From 56d51e09c9840a3f11dc7b5fdba583bd1b9c4463 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Thu, 6 May 2021 12:08:57 -0700 Subject: [PATCH 23/53] Roll back to the previous model --- .../DiagnosticAnalyzerServiceTests.cs | 6 +++--- .../DefaultDiagnosticAnalyzerService.cs | 19 ++++++------------ .../Diagnostics/DiagnosticArguments.cs | 9 ++------- .../Diagnostics/DocumentAnalysisExecutor.cs | 20 ------------------- ...alyzer.InProcOrRemoteHostAnalyzerRunner.cs | 1 - ...crementalAnalyzer_GetDiagnosticsForSpan.cs | 20 ++++++++++++++++++- ...IncrementalAnalyzer_IncrementalAnalyzer.cs | 8 +------- .../Test.Next/Remote/JsonConverterTests.cs | 1 - .../Diagnostics/DocumentAnalysisScope.cs | 9 +++------ .../DiagnosticAnalyzer/DiagnosticComputer.cs | 6 ++---- .../RemoteDiagnosticAnalyzerService.cs | 1 - 11 files changed, 36 insertions(+), 64 deletions(-) diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs index 4567e7fdb92c2..b682a13b3c758 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs @@ -975,7 +975,7 @@ internal async Task TestOnlyRequiredAnalyzerExecutedDuringDiagnosticComputation( var document = documentAnalysis ? project.Documents.Single() : null; var diagnosticComputer = new DiagnosticComputer(document, project, span: null, AnalysisKind.Semantic, new DiagnosticAnalyzerInfoCache()); var diagnosticsMapResults = await diagnosticComputer.GetDiagnosticsAsync(analyzerIdsToRequestDiagnostics, reportSuppressedDiagnostics: false, - logPerformanceInfo: false, getTelemetryInfo: false, highPriority: null, cancellationToken: CancellationToken.None); + logPerformanceInfo: false, getTelemetryInfo: false, cancellationToken: CancellationToken.None); Assert.False(analyzer2.ReceivedSymbolCallback); Assert.Equal(1, diagnosticsMapResults.Diagnostics.Length); @@ -1027,7 +1027,7 @@ void M() try { _ = await diagnosticComputer.GetDiagnosticsAsync(analyzerIds, reportSuppressedDiagnostics: false, - logPerformanceInfo: false, getTelemetryInfo: false, highPriority: null, cancellationToken: analyzer.CancellationToken); + logPerformanceInfo: false, getTelemetryInfo: false, cancellationToken: analyzer.CancellationToken); throw ExceptionUtilities.Unreachable; } @@ -1039,7 +1039,7 @@ void M() // Then invoke analysis without cancellation token, and verify non-cancelled diagnostic. var diagnosticsMap = await diagnosticComputer.GetDiagnosticsAsync(analyzerIds, reportSuppressedDiagnostics: false, - logPerformanceInfo: false, getTelemetryInfo: false, highPriority: null, cancellationToken: CancellationToken.None); + logPerformanceInfo: false, getTelemetryInfo: false, cancellationToken: CancellationToken.None); var builder = diagnosticsMap.Diagnostics.Single().diagnosticMap; var diagnostic = kind == AnalysisKind.Syntax ? builder.Syntax.Single().Item2.Single() : builder.Semantic.Single().Item2.Single(); Assert.Equal(CancellationTestAnalyzer.NonCanceledDiagnosticId, diagnostic.Id); diff --git a/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs index 7404e078877cf..85c7441b31001 100644 --- a/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs +++ b/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs @@ -135,18 +135,11 @@ bool IsSemanticAnalysisOn() private async Task AnalyzeForKindAsync(TextDocument document, AnalysisKind kind, CancellationToken cancellationToken) { - // collect high pri diagnostics first, followed by normal pri. - await AnalyzeForKindAsync(highPriority: true).ConfigureAwait(false); - await AnalyzeForKindAsync(highPriority: false).ConfigureAwait(false); + var diagnosticData = await GetDiagnosticsAsync(document, kind, cancellationToken).ConfigureAwait(false); - async Task AnalyzeForKindAsync(bool highPriority) - { - var diagnosticData = await GetDiagnosticsAsync(document, kind, highPriority, cancellationToken).ConfigureAwait(false); - - _service.RaiseDiagnosticsUpdated( - DiagnosticsUpdatedArgs.DiagnosticsCreated(new DefaultUpdateArgsId(_workspace.Kind, kind, document.Id), - _workspace, document.Project.Solution, document.Project.Id, document.Id, diagnosticData)); - } + _service.RaiseDiagnosticsUpdated( + DiagnosticsUpdatedArgs.DiagnosticsCreated(new DefaultUpdateArgsId(_workspace.Kind, kind, document.Id), + _workspace, document.Project.Solution, document.Project.Id, document.Id, diagnosticData)); } /// @@ -162,7 +155,7 @@ async Task AnalyzeForKindAsync(bool highPriority) /// that provide all kinds of knobs/cache/persistency/OOP to get better perf over simplicity. /// private async Task> GetDiagnosticsAsync( - TextDocument document, AnalysisKind kind, bool highPriority, CancellationToken cancellationToken) + TextDocument document, AnalysisKind kind, CancellationToken cancellationToken) { var loadDiagnostic = await document.State.GetLoadDiagnosticAsync(cancellationToken).ConfigureAwait(false); if (loadDiagnostic != null) @@ -175,7 +168,7 @@ private async Task> GetDiagnosticsAsync( var compilationWithAnalyzers = await AnalyzerHelper.CreateCompilationWithAnalyzersAsync( project, analyzers, includeSuppressedDiagnostics: false, cancellationToken).ConfigureAwait(false); - var analysisScope = new DocumentAnalysisScope(document, span: null, analyzers, kind, highPriority); + var analysisScope = new DocumentAnalysisScope(document, span: null, analyzers, kind); var executor = new DocumentAnalysisExecutor(analysisScope, compilationWithAnalyzers, _diagnosticAnalyzerRunner, logPerformanceInfo: true); using var _ = ArrayBuilder.GetInstance(out var builder); diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs index 1f8c25e2c8895..5189b74c71bb6 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs @@ -56,19 +56,16 @@ internal class DiagnosticArguments [DataMember(Order = 5)] public AnalysisKind? DocumentAnalysisKind; - [DataMember(Order = 6)] - public bool? HighPriority; - /// /// Project ID for the document or project for which diagnostics need to be computed. /// - [DataMember(Order = 7)] + [DataMember(Order = 6)] public ProjectId ProjectId; /// /// Array of analyzer IDs for analyzers that need to be executed for computing diagnostics. /// - [DataMember(Order = 8)] + [DataMember(Order = 7)] public string[] AnalyzerIds; public DiagnosticArguments( @@ -78,7 +75,6 @@ public DiagnosticArguments( DocumentId? documentId, TextSpan? documentSpan, AnalysisKind? documentAnalysisKind, - bool? highPriority, ProjectId projectId, string[] analyzerIds) { @@ -94,7 +90,6 @@ public DiagnosticArguments( DocumentId = documentId; DocumentSpan = documentSpan; DocumentAnalysisKind = documentAnalysisKind; - HighPriority = highPriority; ProjectId = projectId; AnalyzerIds = analyzerIds; } diff --git a/src/Features/Core/Portable/Diagnostics/DocumentAnalysisExecutor.cs b/src/Features/Core/Portable/Diagnostics/DocumentAnalysisExecutor.cs index 953b28fce83b2..8af079a925384 100644 --- a/src/Features/Core/Portable/Diagnostics/DocumentAnalysisExecutor.cs +++ b/src/Features/Core/Portable/Diagnostics/DocumentAnalysisExecutor.cs @@ -63,10 +63,6 @@ public async Task> ComputeDiagnosticsAsync(Diagnosti { Contract.ThrowIfFalse(AnalysisScope.Analyzers.Contains(analyzer)); - // If the caller only wants us processing high pri items, then only proceed with certain analyzers. - if (!MatchesPriority(analyzer, AnalysisScope.HighPriority)) - return SpecializedCollections.EmptyEnumerable(); - var textDocument = AnalysisScope.TextDocument; var span = AnalysisScope.Span; var kind = AnalysisScope.Kind; @@ -152,22 +148,6 @@ public async Task> ComputeDiagnosticsAsync(Diagnosti return diagnostics; } - private static bool MatchesPriority(DiagnosticAnalyzer analyzer, bool? highPriority) - { - // If caller isn't asking for prioritized result, then run all analyzers. - if (highPriority == null) - return true; - - // Otherwise, check our special internal flag to tell. - // - // Note: the compiler analyzer is always considered high-pri. This is needed as there can - // be high pri fixers that operate entirely off of compiler diagnostics. For example, the - // add-using fixer is high pri, and it works off of compiler diagnostics. So we always have - // to run that one up front. - var analyzerIsHighPri = analyzer.IsCompilerAnalyzer() || analyzer is IBuiltInAnalyzer { IsHighPriority: true }; - return analyzerIsHighPri == highPriority; - } - private async Task> GetAnalysisResultAsync(DocumentAnalysisScope analysisScope, CancellationToken cancellationToken) { RoslynDebug.Assert(_compilationWithAnalyzers != null); diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs index 414c55888d59f..066075ae47bc9 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs @@ -180,7 +180,6 @@ private static async Task list, CancellationToken cancellationToken) { + analyzers = analyzers.WhereAsArray(a => MatchesPriority(a)); + if (analyzers.IsEmpty) return; - var analysisScope = new DocumentAnalysisScope(_document, span, analyzers, kind, _highPriority); + var analysisScope = new DocumentAnalysisScope(_document, span, analyzers, kind); var executor = new DocumentAnalysisExecutor(analysisScope, _compilationWithAnalyzers, _owner._diagnosticAnalyzerRunner, logPerformanceInfo: false); foreach (var analyzer in analyzers) { @@ -228,6 +230,22 @@ private async Task ComputeDocumentDiagnosticsAsync( } } + private bool MatchesPriority(DiagnosticAnalyzer analyzer) + { + // If caller isn't asking for prioritized result, then run all analyzers. + if (_highPriority == null) + return true; + + // Otherwise, check our special internal flag to tell. + // + // Note: the compiler analyzer is always considered high-pri. This is needed as there can + // be high pri fixers that operate entirely off of compiler diagnostics. For example, the + // add-using fixer is high pri, and it works off of compiler diagnostics. So we always have + // to run that one up front. + var analyzerIsHighPri = analyzer.IsCompilerAnalyzer() || analyzer is IBuiltInAnalyzer { IsHighPriority: true }; + return analyzerIsHighPri == _highPriority; + } + private bool ShouldInclude(DiagnosticData diagnostic) { return diagnostic.DocumentId == _document.Id && _range.IntersectsWith(diagnostic.GetTextSpan()) diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs index abadcff415b52..2b9812266dfa6 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs @@ -35,12 +35,6 @@ public Task AnalyzeNonSourceDocumentAsync(TextDocument textDocument, InvocationR => AnalyzeDocumentForKindAsync(textDocument, AnalysisKind.Syntax, cancellationToken); private async Task AnalyzeDocumentForKindAsync(TextDocument document, AnalysisKind kind, CancellationToken cancellationToken) - { - await AnalyzeDocumentForKindAsync(document, kind, highPriority: true, cancellationToken).ConfigureAwait(false); - await AnalyzeDocumentForKindAsync(document, kind, highPriority: false, cancellationToken).ConfigureAwait(false); - } - - private async Task AnalyzeDocumentForKindAsync(TextDocument document, AnalysisKind kind, bool highPriority, CancellationToken cancellationToken) { try { @@ -80,7 +74,7 @@ private async Task AnalyzeDocumentForKindAsync(TextDocument document, AnalysisKi // Then, compute the diagnostics for non-cached state sets, and cache and raise diagnostic reported events for these diagnostics. if (nonCachedStateSets.Count > 0) { - var analysisScope = new DocumentAnalysisScope(document, span: null, nonCachedStateSets.SelectAsArray(s => s.Analyzer), kind, highPriority); + var analysisScope = new DocumentAnalysisScope(document, span: null, nonCachedStateSets.SelectAsArray(s => s.Analyzer), kind); var executor = new DocumentAnalysisExecutor(analysisScope, compilationWithAnalyzers, _diagnosticAnalyzerRunner, logPerformanceInfo: true, onAnalysisException: OnAnalysisException); foreach (var stateSet in nonCachedStateSets) { diff --git a/src/VisualStudio/Core/Test.Next/Remote/JsonConverterTests.cs b/src/VisualStudio/Core/Test.Next/Remote/JsonConverterTests.cs index 19056b3387cc2..f1027e7123a59 100644 --- a/src/VisualStudio/Core/Test.Next/Remote/JsonConverterTests.cs +++ b/src/VisualStudio/Core/Test.Next/Remote/JsonConverterTests.cs @@ -69,7 +69,6 @@ public void TestDiagnosticArguments() documentId: DocumentId.CreateNewId(projectId), documentSpan: new TextSpan(0, 1), documentAnalysisKind: AnalysisKind.Syntax, - highPriority: null, projectId: projectId, analyzerIds: new[] { "analyzer1", "analyzer2" }); diff --git a/src/Workspaces/Core/Portable/Diagnostics/DocumentAnalysisScope.cs b/src/Workspaces/Core/Portable/Diagnostics/DocumentAnalysisScope.cs index 1930c05c8aaf1..d978a95006e5c 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/DocumentAnalysisScope.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/DocumentAnalysisScope.cs @@ -22,8 +22,7 @@ public DocumentAnalysisScope( TextDocument document, TextSpan? span, ImmutableArray analyzers, - AnalysisKind kind, - bool? highPriority) + AnalysisKind kind) { Debug.Assert(kind == AnalysisKind.Syntax || kind == AnalysisKind.Semantic); Debug.Assert(!analyzers.IsDefaultOrEmpty); @@ -32,7 +31,6 @@ public DocumentAnalysisScope( Span = span; Analyzers = analyzers; Kind = kind; - HighPriority = highPriority; _lazyAdditionalFile = new Lazy(ComputeAdditionalFile); } @@ -40,7 +38,6 @@ public DocumentAnalysisScope( public TextSpan? Span { get; } public ImmutableArray Analyzers { get; } public AnalysisKind Kind { get; } - public bool? HighPriority { get; } /// /// Gets the corresponding to the . @@ -57,9 +54,9 @@ private AdditionalText ComputeAdditionalFile() } public DocumentAnalysisScope WithSpan(TextSpan? span) - => new(TextDocument, span, Analyzers, Kind, HighPriority); + => new(TextDocument, span, Analyzers, Kind); public DocumentAnalysisScope WithAnalyzers(ImmutableArray analyzers) - => new(TextDocument, Span, analyzers, Kind, HighPriority); + => new(TextDocument, Span, analyzers, Kind); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs index 820d1e1a676d6..b99ff55be839f 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs @@ -64,7 +64,6 @@ public async Task GetDiagnosticsAsync( bool reportSuppressedDiagnostics, bool logPerformanceInfo, bool getTelemetryInfo, - bool? highPriority, CancellationToken cancellationToken) { var (compilationWithAnalyzers, analyzerToIdMap) = await GetOrCreateCompilationWithAnalyzersAsync( @@ -89,7 +88,7 @@ public async Task GetDiagnosticsAsync( try { return await AnalyzeAsync(compilationWithAnalyzers, analyzerToIdMap, analyzers, skippedAnalyzersInfo, - reportSuppressedDiagnostics, logPerformanceInfo, getTelemetryInfo, highPriority, cancellationToken).ConfigureAwait(false); + reportSuppressedDiagnostics, logPerformanceInfo, getTelemetryInfo, cancellationToken).ConfigureAwait(false); } catch { @@ -107,11 +106,10 @@ private async Task AnalyzeAsync( bool reportSuppressedDiagnostics, bool logPerformanceInfo, bool getTelemetryInfo, - bool? highPriority, CancellationToken cancellationToken) { var documentAnalysisScope = _document != null - ? new DocumentAnalysisScope(_document, _span, analyzers, _analysisKind!.Value, highPriority) + ? new DocumentAnalysisScope(_document, _span, analyzers, _analysisKind!.Value) : null; var (analysisResult, additionalPragmaSuppressionDiagnostics) = await compilationWithAnalyzers.GetAnalysisResultAsync( diff --git a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs index 1f554b644afa8..4bf6b1c0da442 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs @@ -65,7 +65,6 @@ public ValueTask CalculateDiagnosticsAsyn reportSuppressedDiagnostics: arguments.ReportSuppressedDiagnostics, logPerformanceInfo: arguments.LogPerformanceInfo, getTelemetryInfo: arguments.GetTelemetryInfo, - highPriority: arguments.HighPriority, cancellationToken).ConfigureAwait(false); // save log for debugging From 4b735b529d567e984a92041136eefb7e56dfc6b1 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 10 May 2021 14:41:55 -0700 Subject: [PATCH 24/53] Update version --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index 64879f26cce09..6a940b6e72d29 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -32,7 +32,7 @@ 1.0.1-beta1.20623.3 3.9.0 16.10.44 - 17.0.32-g9d6b2c6f26 + 17.0.56-gb3c64827ce 5.0.0-alpha1.19409.1 5.0.0-preview.1.20112.8 17.0.20-g6553c6c46e From 505c91f4de38b7f3a9e3b4d7296f8e905400b72f Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Thu, 13 May 2021 09:19:08 -0700 Subject: [PATCH 25/53] Update version --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index 0defd24a7e86b..6d9a454b3332f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -32,7 +32,7 @@ 1.0.1-beta1.20623.3 3.9.0 16.10.44 - 17.0.56-gb3c64827ce + 17.0.73-g303b0cab45 5.0.0-alpha1.19409.1 5.0.0-preview.1.20112.8 17.0.20-g6553c6c46e From 27a15e6268b2a28dabd4df6fb5b9dbac841f960e Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Thu, 13 May 2021 09:39:48 -0700 Subject: [PATCH 26/53] Update version --- .../Core.Wpf/Suggestions/SuggestedActionsSource.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index d22ceba7e5223..7e53d12130ecb 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -32,7 +32,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions { internal partial class SuggestedActionsSourceProvider { - private partial class SuggestedActionsSource : ForegroundThreadAffinitizedObject, ISuggestedActionsSource3 + private partial class SuggestedActionsSource : ForegroundThreadAffinitizedObject, ISuggestedActionsSource4 { private readonly ISuggestedActionCategoryRegistryService _suggestedActionCategoryRegistry; From 6403b5e9fe72a59bdc316fff5a465f1fe750fe74 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 25 May 2021 16:29:49 -0700 Subject: [PATCH 27/53] Update version --- eng/Versions.props | 2 +- .../Suggestions/SuggestedActionsSource.cs | 21 +++++-------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index f172056eb7f49..37826203e6bfd 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -32,7 +32,7 @@ 1.0.1-beta1.20623.3 3.9.0 16.10.44 - 17.0.73-g303b0cab45 + 17.0.77-preview-g95aaee7977 5.0.0-alpha1.19409.1 5.0.0-preview.1.20112.8 17.0.20-g6553c6c46e diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 7e53d12130ecb..fc87e4b361441 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -32,7 +32,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions { internal partial class SuggestedActionsSourceProvider { - private partial class SuggestedActionsSource : ForegroundThreadAffinitizedObject, ISuggestedActionsSource4 + private partial class SuggestedActionsSource : ForegroundThreadAffinitizedObject, ISuggestedActionsSourceExperimental { private readonly ISuggestedActionCategoryRegistryService _suggestedActionCategoryRegistry; @@ -190,10 +190,9 @@ private IEnumerable ConvertToSuggestedActionSets(ReferenceCo public async IAsyncEnumerable GetSuggestedActionsAsync( ISuggestedActionCategorySet requestedActionCategories, SnapshotSpan range, - IUIThreadOperationContext operationContext) + [EnumeratorCancellation] CancellationToken cancellationToken) { AssertIsForeground(); - var cancellationToken = operationContext.UserCancellationToken; using var state = _state.TryAddReference(); if (state is null) @@ -203,10 +202,7 @@ public async IAsyncEnumerable GetSuggestedActionsAsync( if (workspace == null) yield break; - using (operationContext.AddScope(allowCancellation: true, description: EditorFeaturesResources.Gathering_Suggestions_Waiting_for_the_solution_to_fully_load)) - { - await workspace.Services.GetRequiredService().WaitUntilFullyLoadedAsync(cancellationToken).ConfigureAwait(true); - } + await workspace.Services.GetRequiredService().WaitUntilFullyLoadedAsync(cancellationToken).ConfigureAwait(true); using (Logger.LogBlock(FunctionId.SuggestedActions_GetSuggestedActionsAsync, cancellationToken)) { @@ -216,21 +212,14 @@ public async IAsyncEnumerable GetSuggestedActionsAsync( // Compute and return the high pri set of fixes and refactorings first so the user // can act on them immediately without waiting on the regular set. - var highPriSet = GetCodeFixesAndRefactoringsAsync(state, requestedActionCategories, document, range, AddOperationScope, highPriority: true, cancellationToken); + var highPriSet = GetCodeFixesAndRefactoringsAsync(state, requestedActionCategories, document, range, _ => null, highPriority: true, cancellationToken); await foreach (var set in highPriSet) yield return set; - var lowPriSet = GetCodeFixesAndRefactoringsAsync(state, requestedActionCategories, document, range, AddOperationScope, highPriority: false, cancellationToken); + var lowPriSet = GetCodeFixesAndRefactoringsAsync(state, requestedActionCategories, document, range, _ => null, highPriority: false, cancellationToken); await foreach (var set in lowPriSet) yield return set; } - - yield break; - - IDisposable? AddOperationScope(string description) - { - return operationContext.AddScope(allowCancellation: true, string.Format(EditorFeaturesResources.Gathering_Suggestions_0, description)); - } } private async IAsyncEnumerable GetCodeFixesAndRefactoringsAsync( From 3f5d239d508de3393594266a238e46c9daa9afc1 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 25 May 2021 17:16:54 -0700 Subject: [PATCH 28/53] Fix --- .../DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs index 1e29104260f5d..52b66f81314b1 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs @@ -173,7 +173,8 @@ private async Task TryGetCachedDocumentDiagnosticsAsync( ArrayBuilder list, CancellationToken cancellationToken) { - if (!stateSet.Analyzer.SupportAnalysisKind(kind)) + if (!stateSet.Analyzer.SupportAnalysisKind(kind) || + !MatchesPriority(stateSet.Analyzer)) { return true; } From 5ff2685f2e5fe939bc2e490d951ef967eea71962 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 25 May 2021 19:30:37 -0700 Subject: [PATCH 29/53] Move to an enum --- .../Suggestions/SuggestedActionsSource.cs | 25 +++++++------- .../Helpers/MockDiagnosticAnalyzerService.cs | 3 +- .../Core/Portable/CodeFixes/CodeFixService.cs | 19 +++++++---- .../Portable/CodeFixes/ICodeFixService.cs | 5 +-- .../CodeRefactoringService.cs | 10 ++++-- .../ICodeRefactoringService.cs | 5 +-- .../Diagnostics/DiagnosticAnalyzerService.cs | 7 ++-- ...crementalAnalyzer_GetDiagnosticsForSpan.cs | 24 +++++++------- .../Diagnostics/IDiagnosticAnalyzerService.cs | 5 +-- .../UnifiedSuggestedActionsSource.cs | 8 ++--- .../Handler/CodeActions/CodeActionHelpers.cs | 4 +-- .../CodeActions/CodeActionPriority.cs | 1 - .../CodeActions/CodeActionProviderPriority.cs | 33 +++++++++++++++++++ 13 files changed, 99 insertions(+), 50 deletions(-) create mode 100644 src/Workspaces/Core/Portable/CodeActions/CodeActionProviderPriority.cs diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index fc87e4b361441..7583f9da8f23d 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -11,6 +11,7 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.Shared; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; @@ -212,11 +213,11 @@ public async IAsyncEnumerable GetSuggestedActionsAsync( // Compute and return the high pri set of fixes and refactorings first so the user // can act on them immediately without waiting on the regular set. - var highPriSet = GetCodeFixesAndRefactoringsAsync(state, requestedActionCategories, document, range, _ => null, highPriority: true, cancellationToken); + var highPriSet = GetCodeFixesAndRefactoringsAsync(state, requestedActionCategories, document, range, _ => null, CodeActionProviderPriority.High, cancellationToken); await foreach (var set in highPriSet) yield return set; - var lowPriSet = GetCodeFixesAndRefactoringsAsync(state, requestedActionCategories, document, range, _ => null, highPriority: false, cancellationToken); + var lowPriSet = GetCodeFixesAndRefactoringsAsync(state, requestedActionCategories, document, range, _ => null, CodeActionProviderPriority.Normal, cancellationToken); await foreach (var set in lowPriSet) yield return set; } @@ -228,7 +229,7 @@ private async IAsyncEnumerable GetCodeFixesAndRefactoringsAs Document document, SnapshotSpan range, Func addOperationScope, - bool highPriority, + CodeActionProviderPriority priority, [EnumeratorCancellation] CancellationToken cancellationToken) { var workspace = document.Project.Solution.Workspace; @@ -238,12 +239,12 @@ private async IAsyncEnumerable GetCodeFixesAndRefactoringsAs var fixesTask = GetCodeFixesAsync( state, supportsFeatureService, requestedActionCategories, workspace, document, range, - addOperationScope, highPriority, isBlocking: false, cancellationToken); + addOperationScope, priority, isBlocking: false, cancellationToken); var refactoringsTask = GetRefactoringsAsync( state, supportsFeatureService, requestedActionCategories, workspace, document, selection, - addOperationScope, highPriority, isBlocking: false, cancellationToken); + addOperationScope, priority, isBlocking: false, cancellationToken); - if (highPriority) + if (priority == CodeActionProviderPriority.High) { // in a high pri scenario, return data as soon as possible so that the user can interact with them. // this is especially important for state-machine oriented refactorings (like rename) where the user @@ -348,7 +349,7 @@ private ImmutableArray GetCodeFixes( return GetCodeFixesAsync( state, supportsFeatureService, requestedActionCategories, workspace, document, range, - addOperationScope, highPriority: null, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); + addOperationScope, CodeActionProviderPriority.None, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); } private static async Task> GetCodeFixesAsync( @@ -359,7 +360,7 @@ private static async Task> GetCodeFixe Document document, SnapshotSpan range, Func addOperationScope, - bool? highPriority, + CodeActionProviderPriority priority, bool isBlocking, CancellationToken cancellationToken) { @@ -376,7 +377,7 @@ private static async Task> GetCodeFixe return await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeFixesAsync( workspace, state.Target.Owner._codeFixService, document, range.Span.ToTextSpan(), - includeSuppressionFixes, highPriority, isBlocking, addOperationScope, cancellationToken).ConfigureAwait(false); + includeSuppressionFixes, priority, isBlocking, addOperationScope, cancellationToken).ConfigureAwait(false); } private static string GetFixCategory(DiagnosticSeverity severity) @@ -407,7 +408,7 @@ private ImmutableArray GetRefactorings( this.AssertIsForeground(); return GetRefactoringsAsync( state, supportsFeatureService, requestedActionCategories, workspace, document, selection, - addOperationScope, highPriority: null, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); + addOperationScope, CodeActionProviderPriority.None, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); } private static async Task> GetRefactoringsAsync( @@ -418,7 +419,7 @@ private static async Task> GetRefactor Document document, TextSpan? selection, Func addOperationScope, - bool? highPriority, + CodeActionProviderPriority priority, bool isBlocking, CancellationToken cancellationToken) { @@ -437,7 +438,7 @@ private static async Task> GetRefactor var filterOutsideSelection = !requestedActionCategories.Contains(PredefinedSuggestedActionCategoryNames.Refactoring); return await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeRefactoringsAsync( - workspace, state.Target.Owner._codeRefactoringService, document, selection.Value, highPriority, isBlocking, + workspace, state.Target.Owner._codeRefactoringService, document, selection.Value, priority, isBlocking, addOperationScope, filterOutsideSelection, cancellationToken).ConfigureAwait(false); } diff --git a/src/EditorFeatures/Test/EditAndContinue/Helpers/MockDiagnosticAnalyzerService.cs b/src/EditorFeatures/Test/EditAndContinue/Helpers/MockDiagnosticAnalyzerService.cs index 7fa3b311e84f0..34f45be83990c 100644 --- a/src/EditorFeatures/Test/EditAndContinue/Helpers/MockDiagnosticAnalyzerService.cs +++ b/src/EditorFeatures/Test/EditAndContinue/Helpers/MockDiagnosticAnalyzerService.cs @@ -9,6 +9,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; @@ -40,7 +41,7 @@ public Task> GetDiagnosticsAsync(Solution solutio public Task> GetDiagnosticsForIdsAsync(Solution solution, ProjectId? projectId = null, DocumentId? documentId = null, ImmutableHashSet? diagnosticIds = null, bool includeSuppressedDiagnostics = false, CancellationToken cancellationToken = default) => throw new NotImplementedException(); - public Task> GetDiagnosticsForSpanAsync(Document document, TextSpan range, string? diagnosticIdOpt = null, bool includeSuppressedDiagnostics = false, bool? highPriority = null, Func? addOperationScope = null, CancellationToken cancellationToken = default) + public Task> GetDiagnosticsForSpanAsync(Document document, TextSpan range, string? diagnosticIdOpt = null, bool includeSuppressedDiagnostics = false, CodeActionProviderPriority priority = CodeActionProviderPriority.None, Func? addOperationScope = null, CancellationToken cancellationToken = default) => throw new NotImplementedException(); public Task> GetProjectDiagnosticsForIdsAsync(Solution solution, ProjectId? projectId = null, ImmutableHashSet? diagnosticIds = null, bool includeSuppressedDiagnostics = false, CancellationToken cancellationToken = default) diff --git a/src/Features/Core/Portable/CodeFixes/CodeFixService.cs b/src/Features/Core/Portable/CodeFixes/CodeFixService.cs index d2015c52045f9..70ded7150749a 100644 --- a/src/Features/Core/Portable/CodeFixes/CodeFixService.cs +++ b/src/Features/Core/Portable/CodeFixes/CodeFixService.cs @@ -12,6 +12,7 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes.Suppression; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor; @@ -155,7 +156,7 @@ public async Task> GetFixesAsync( Document document, TextSpan range, bool includeConfigurationFixes, - bool? highPriority, + CodeActionProviderPriority priority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken) @@ -172,7 +173,7 @@ public async Task> GetFixesAsync( // order diagnostics by span. SortedDictionary>? aggregatedDiagnostics = null; var diagnostics = await _diagnosticService.GetDiagnosticsForSpanAsync( - document, range, diagnosticIdOpt: null, includeConfigurationFixes, highPriority, addOperationScope, cancellationToken).ConfigureAwait(false); + document, range, diagnosticIdOpt: null, includeConfigurationFixes, priority, addOperationScope, cancellationToken).ConfigureAwait(false); foreach (var diagnostic in diagnostics) { if (diagnostic.IsSuppressed) @@ -199,7 +200,7 @@ public async Task> GetFixesAsync( { await AppendFixesAsync( document, spanAndDiagnostic.Key, spanAndDiagnostic.Value, fixAllForInSpan: false, - highPriority, isBlocking, result, addOperationScope, cancellationToken).ConfigureAwait(false); + priority, isBlocking, result, addOperationScope, cancellationToken).ConfigureAwait(false); } if (result.Count > 0 && TryGetWorkspaceFixersPriorityMap(document, out var fixersForLanguage)) @@ -239,7 +240,7 @@ await AppendConfigurationsAsync( } using var resultDisposer = ArrayBuilder.GetInstance(out var result); - await AppendFixesAsync(document, range, diagnostics, fixAllForInSpan: true, highPriority: null, isBlocking: false, result, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); + await AppendFixesAsync(document, range, diagnostics, fixAllForInSpan: true, CodeActionProviderPriority.None, isBlocking: false, result, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); // TODO: Just get the first fix for now until we have a way to config user's preferred fix // https://github.com/dotnet/roslyn/issues/27066 @@ -333,7 +334,7 @@ private async Task AppendFixesAsync( TextSpan span, IEnumerable diagnostics, bool fixAllForInSpan, - bool? highPriority, + CodeActionProviderPriority priority, bool isBlocking, ArrayBuilder result, Func addOperationScope, @@ -398,8 +399,12 @@ private async Task AppendFixesAsync( { cancellationToken.ThrowIfCancellationRequested(); - if (highPriority != null && highPriority != fixer.IsHighPriority) - continue; + if (priority != CodeActionProviderPriority.None) + { + var highPriority = priority == CodeActionProviderPriority.High; + if (highPriority != fixer.IsHighPriority) + continue; + } await AppendFixesOrConfigurationsAsync( document, span, diagnostics, fixAllForInSpan, result, fixer, diff --git a/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs b/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs index cf09aa0507f59..df59ecabc189c 100644 --- a/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs +++ b/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; @@ -14,7 +15,7 @@ namespace Microsoft.CodeAnalysis.CodeFixes { internal interface ICodeFixService { - Task> GetFixesAsync(Document document, TextSpan textSpan, bool includeSuppressionFixes, bool? highPriority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken); + Task> GetFixesAsync(Document document, TextSpan textSpan, bool includeSuppressionFixes, CodeActionProviderPriority priority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken); Task GetDocumentFixAllForIdInSpanAsync(Document document, TextSpan textSpan, string diagnosticId, CancellationToken cancellationToken); Task ApplyCodeFixesForSpecificDiagnosticIdAsync(Document document, string diagnosticId, IProgressTracker progressTracker, CancellationToken cancellationToken); CodeFixProvider? GetSuppressionFixer(string language, IEnumerable diagnosticIds); @@ -27,6 +28,6 @@ public static Task> GetFixesAsync(this ICodeFi => service.GetFixesAsync(document, range, includeConfigurationFixes, isBlocking: false, cancellationToken); public static Task> GetFixesAsync(this ICodeFixService service, Document document, TextSpan range, bool includeConfigurationFixes, bool isBlocking, CancellationToken cancellationToken) - => service.GetFixesAsync(document, range, includeConfigurationFixes, highPriority: null, isBlocking, addOperationScope: _ => null, cancellationToken); + => service.GetFixesAsync(document, range, includeConfigurationFixes, CodeActionProviderPriority.None, isBlocking, addOperationScope: _ => null, cancellationToken); } } diff --git a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs index e221190ed845e..b74f27a4fe583 100644 --- a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs @@ -108,7 +108,7 @@ public async Task HasRefactoringsAsync( public async Task> GetRefactoringsAsync( Document document, TextSpan state, - bool? highPriority, + CodeActionProviderPriority priority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken) @@ -120,8 +120,12 @@ public async Task> GetRefactoringsAsync( foreach (var provider in GetProviders(document)) { - if (highPriority != null && highPriority != provider.IsHighPriority) - continue; + if (priority != CodeActionProviderPriority.None) + { + var highPriority = priority == CodeActionProviderPriority.High; + if (highPriority != provider.IsHighPriority) + continue; + } tasks.Add(Task.Run(() => { diff --git a/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs index b9bb2bceb3211..8fcf9af8c8e9b 100644 --- a/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CodeRefactorings @@ -14,7 +15,7 @@ internal interface ICodeRefactoringService { Task HasRefactoringsAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken); - Task> GetRefactoringsAsync(Document document, TextSpan textSpan, bool? highPriority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken); + Task> GetRefactoringsAsync(Document document, TextSpan textSpan, CodeActionProviderPriority priority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken); } internal static class ICodeRefactoringServiceExtensions @@ -23,6 +24,6 @@ public static Task> GetRefactoringsAsync(this IC => service.GetRefactoringsAsync(document, state, isBlocking: false, cancellationToken); public static Task> GetRefactoringsAsync(this ICodeRefactoringService service, Document document, TextSpan state, bool isBlocking, CancellationToken cancellationToken) - => service.GetRefactoringsAsync(document, state, highPriority: null, isBlocking, addOperationScope: _ => null, cancellationToken); + => service.GetRefactoringsAsync(document, state, CodeActionProviderPriority.None, isBlocking, addOperationScope: _ => null, cancellationToken); } } diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs index 323ff2ed82e75..304a2ad60fc09 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs @@ -10,6 +10,7 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Diagnostics.EngineV2; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.PooledObjects; @@ -70,7 +71,7 @@ public Task TryAppendDiagnosticsForSpanAsync(Document document, TextSpan r { // always make sure that analyzer is called on background thread. return Task.Run(() => analyzer.TryAppendDiagnosticsForSpanAsync( - document, range, diagnostics, diagnosticId: null, includeSuppressedDiagnostics, highPriority: null, blockForData: false, addOperationScope: null, cancellationToken), cancellationToken); + document, range, diagnostics, diagnosticId: null, includeSuppressedDiagnostics, CodeActionProviderPriority.None, blockForData: false, addOperationScope: null, cancellationToken), cancellationToken); } return SpecializedTasks.False; @@ -80,7 +81,7 @@ public Task> GetDiagnosticsForSpanAsync( Document document, TextSpan range, string? diagnosticId, bool includeSuppressedDiagnostics, - bool? highPriority, + CodeActionProviderPriority priority, Func? addOperationScope, CancellationToken cancellationToken) { @@ -88,7 +89,7 @@ public Task> GetDiagnosticsForSpanAsync( { // always make sure that analyzer is called on background thread. return Task.Run(() => analyzer.GetDiagnosticsForSpanAsync( - document, range, diagnosticId, includeSuppressedDiagnostics, highPriority, + document, range, diagnosticId, includeSuppressedDiagnostics, priority, blockForData: true, addOperationScope, cancellationToken), cancellationToken); } diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs index 52b66f81314b1..9bcd44fc05bc3 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.PooledObjects; @@ -21,12 +22,12 @@ internal partial class DiagnosticIncrementalAnalyzer { public async Task TryAppendDiagnosticsForSpanAsync( Document document, TextSpan range, ArrayBuilder result, string? diagnosticId, - bool includeSuppressedDiagnostics, bool? highPriority, bool blockForData, + bool includeSuppressedDiagnostics, CodeActionProviderPriority priority, bool blockForData, Func? addOperationScope, CancellationToken cancellationToken) { var getter = await LatestDiagnosticsForSpanGetter.CreateAsync( this, document, range, blockForData, addOperationScope, includeSuppressedDiagnostics, - highPriority, diagnosticId, cancellationToken).ConfigureAwait(false); + priority, diagnosticId, cancellationToken).ConfigureAwait(false); return await getter.TryGetAsync(result, cancellationToken).ConfigureAwait(false); } @@ -35,7 +36,7 @@ public async Task> GetDiagnosticsForSpanAsync( TextSpan range, string? diagnosticId, bool includeSuppressedDiagnostics, - bool? highPriority, + CodeActionProviderPriority priority, bool blockForData, Func? addOperationScope, CancellationToken cancellationToken) @@ -43,7 +44,7 @@ public async Task> GetDiagnosticsForSpanAsync( using var _ = ArrayBuilder.GetInstance(out var list); var result = await TryAppendDiagnosticsForSpanAsync( document, range, list, diagnosticId, includeSuppressedDiagnostics, - highPriority, blockForData, addOperationScope, cancellationToken).ConfigureAwait(false); + priority, blockForData, addOperationScope, cancellationToken).ConfigureAwait(false); Debug.Assert(result); return list.ToImmutable(); } @@ -62,7 +63,7 @@ private sealed class LatestDiagnosticsForSpanGetter private readonly TextSpan _range; private readonly bool _blockForData; private readonly bool _includeSuppressedDiagnostics; - private readonly bool? _highPriority; + private readonly CodeActionProviderPriority _priority; private readonly string? _diagnosticId; private readonly Func? _addOperationScope; @@ -75,7 +76,7 @@ public static async Task CreateAsync( bool blockForData, Func? addOperationScope, bool includeSuppressedDiagnostics, - bool? highPriority, + CodeActionProviderPriority priority, string? diagnosticId, CancellationToken cancellationToken) { @@ -92,7 +93,7 @@ public static async Task CreateAsync( return new LatestDiagnosticsForSpanGetter( owner, compilationWithAnalyzers, document, stateSets, diagnosticId, range, - blockForData, addOperationScope, includeSuppressedDiagnostics, highPriority); + blockForData, addOperationScope, includeSuppressedDiagnostics, priority); } private LatestDiagnosticsForSpanGetter( @@ -105,7 +106,7 @@ private LatestDiagnosticsForSpanGetter( bool blockForData, Func? addOperationScope, bool includeSuppressedDiagnostics, - bool? highPriority) + CodeActionProviderPriority priority) { _owner = owner; _compilationWithAnalyzers = compilationWithAnalyzers; @@ -116,7 +117,7 @@ private LatestDiagnosticsForSpanGetter( _blockForData = blockForData; _addOperationScope = addOperationScope; _includeSuppressedDiagnostics = includeSuppressedDiagnostics; - _highPriority = highPriority; + _priority = priority; } public async Task TryGetAsync(ArrayBuilder list, CancellationToken cancellationToken) @@ -234,7 +235,7 @@ private async Task ComputeDocumentDiagnosticsAsync( private bool MatchesPriority(DiagnosticAnalyzer analyzer) { // If caller isn't asking for prioritized result, then run all analyzers. - if (_highPriority == null) + if (_priority == CodeActionProviderPriority.None) return true; // Otherwise, check our special internal flag to tell. @@ -244,7 +245,8 @@ private bool MatchesPriority(DiagnosticAnalyzer analyzer) // add-using fixer is high pri, and it works off of compiler diagnostics. So we always have // to run that one up front. var analyzerIsHighPri = analyzer.IsCompilerAnalyzer() || analyzer is IBuiltInAnalyzer { IsHighPriority: true }; - return analyzerIsHighPri == _highPriority; + var highPriority = _priority == CodeActionProviderPriority.High; + return analyzerIsHighPri == highPriority; } private bool ShouldInclude(DiagnosticData diagnostic) diff --git a/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs index 555689bddf73c..b7f076b352aab 100644 --- a/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs +++ b/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; @@ -76,12 +77,12 @@ internal interface IDiagnosticAnalyzerService /// This can be expensive since it is force analyzing diagnostics if it doesn't have up-to-date one yet. /// If diagnosticIdOpt is not null, it gets diagnostics only for this given diagnosticIdOpt value /// - Task> GetDiagnosticsForSpanAsync(Document document, TextSpan range, string? diagnosticIdOpt = null, bool includeSuppressedDiagnostics = false, bool? highPriority = null, Func? addOperationScope = null, CancellationToken cancellationToken = default); + Task> GetDiagnosticsForSpanAsync(Document document, TextSpan range, string? diagnosticIdOpt = null, bool includeSuppressedDiagnostics = false, CodeActionProviderPriority priority = CodeActionProviderPriority.None, Func? addOperationScope = null, CancellationToken cancellationToken = default); } internal static class IDiagnosticAnalyzerServiceExtensions { public static Task> GetDiagnosticsForSpanAsync(this IDiagnosticAnalyzerService service, Document document, TextSpan range, string? diagnosticIdOpt = null, bool includeSuppressedDiagnostics = false, Func? addOperationScope = null, CancellationToken cancellationToken = default) - => service.GetDiagnosticsForSpanAsync(document, range, diagnosticIdOpt, includeSuppressedDiagnostics, highPriority: null, addOperationScope, cancellationToken); + => service.GetDiagnosticsForSpanAsync(document, range, diagnosticIdOpt, includeSuppressedDiagnostics, CodeActionProviderPriority.None, addOperationScope, cancellationToken); } } diff --git a/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs b/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs index c97b9b9454294..bbf1f740fc143 100644 --- a/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs +++ b/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs @@ -35,7 +35,7 @@ public static async ValueTask> GetFilt Document document, TextSpan selection, bool includeSuppressionFixes, - bool? highPriority, + CodeActionProviderPriority priority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken) @@ -46,7 +46,7 @@ public static async ValueTask> GetFilt // the UI thread. var fixes = await Task.Run( () => codeFixService.GetFixesAsync( - document, selection, includeSuppressionFixes, highPriority, isBlocking, + document, selection, includeSuppressionFixes, priority, isBlocking, addOperationScope, cancellationToken), cancellationToken).ConfigureAwait(false); var filteredFixes = fixes.WhereAsArray(c => c.Fixes.Length > 0); @@ -394,7 +394,7 @@ public static async Task> GetFilterAnd ICodeRefactoringService codeRefactoringService, Document document, TextSpan selection, - bool? highPriority, + CodeActionProviderPriority priority, bool isBlocking, Func addOperationScope, bool filterOutsideSelection, @@ -406,7 +406,7 @@ public static async Task> GetFilterAnd // the UI thread. var refactorings = await Task.Run( () => codeRefactoringService.GetRefactoringsAsync( - document, selection, highPriority, isBlocking, addOperationScope, + document, selection, priority, isBlocking, addOperationScope, cancellationToken), cancellationToken).ConfigureAwait(false); var filteredRefactorings = FilterOnAnyThread(refactorings, selection, filterOutsideSelection); diff --git a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs index 09665e9d2033b..1950cdde850c0 100644 --- a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs +++ b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs @@ -223,10 +223,10 @@ private static async ValueTask> GetAct var codeFixes = await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeFixesAsync( document.Project.Solution.Workspace, codeFixService, document, textSpan, includeSuppressionFixes: true, - highPriority: null, isBlocking: false, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); + CodeActionProviderPriority.None, isBlocking: false, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); var codeRefactorings = await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeRefactoringsAsync( - document.Project.Solution.Workspace, codeRefactoringService, document, textSpan, highPriority: null, isBlocking: false, + document.Project.Solution.Workspace, codeRefactoringService, document, textSpan, CodeActionProviderPriority.None, isBlocking: false, addOperationScope: _ => null, filterOutsideSelection: false, cancellationToken).ConfigureAwait(false); var actionSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets(codeFixes, codeRefactorings, textSpan); diff --git a/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs b/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs index 1fd6355842ac1..5ca0b3fa318f0 100644 --- a/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs +++ b/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs @@ -27,5 +27,4 @@ internal enum CodeActionPriority Medium = 2, High = 3 } -#pragma warning restore CA1200 // Avoid using cref tags with a prefix } diff --git a/src/Workspaces/Core/Portable/CodeActions/CodeActionProviderPriority.cs b/src/Workspaces/Core/Portable/CodeActions/CodeActionProviderPriority.cs new file mode 100644 index 0000000000000..2234319233af8 --- /dev/null +++ b/src/Workspaces/Core/Portable/CodeActions/CodeActionProviderPriority.cs @@ -0,0 +1,33 @@ +// 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.CodeFixes; +using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.CodeAnalysis.CodeActions +{ + internal enum CodeActionProviderPriority + { + /// + /// No priority specified, all refactoring, code fixes, and analyzers should be run. + /// + None = 0, + /// + /// Only normal priority refactoring, code fix providers should be run. Specifically, + /// providers will be run when and + /// are . s + /// will be run except for . + /// + Normal = 1, + /// + /// Only high priority refactoring, code fix providers should be run. Specifically, + /// providers will be run when or + /// is . + /// The + /// will be run. + /// + High = 2, + } +} From 188be8f05d1993a3b2d5756462395caa58342c9d Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 25 May 2021 19:32:07 -0700 Subject: [PATCH 30/53] Add docs --- .../Core/Portable/CodeActions/CodeActionProviderPriority.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Workspaces/Core/Portable/CodeActions/CodeActionProviderPriority.cs b/src/Workspaces/Core/Portable/CodeActions/CodeActionProviderPriority.cs index 2234319233af8..318a7fb71cda6 100644 --- a/src/Workspaces/Core/Portable/CodeActions/CodeActionProviderPriority.cs +++ b/src/Workspaces/Core/Portable/CodeActions/CodeActionProviderPriority.cs @@ -11,7 +11,8 @@ namespace Microsoft.CodeAnalysis.CodeActions internal enum CodeActionProviderPriority { /// - /// No priority specified, all refactoring, code fixes, and analyzers should be run. + /// No priority specified, all refactoring, code fixes, and analyzers should be run. This is equivalent + /// to and combined. /// None = 0, /// From 4aa0237aab55312ccfcf8df1735767de77dacb29 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 25 May 2021 19:41:17 -0700 Subject: [PATCH 31/53] Move new code into new files --- ...rce_ISuggestedActionsSourceExperimental.cs | 121 ++++++++++++++++++ .../Suggestions/SuggestedActionsSource.cs | 95 +------------- 2 files changed, 122 insertions(+), 94 deletions(-) create mode 100644 src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs new file mode 100644 index 0000000000000..c3df634ae0f61 --- /dev/null +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs @@ -0,0 +1,121 @@ +// 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.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.Editor.Shared; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.UnifiedSuggestions; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions +{ + internal partial class SuggestedActionsSourceProvider + { + private partial class SuggestedActionsSource : ISuggestedActionsSourceExperimental + { + public async IAsyncEnumerable GetSuggestedActionsAsync( + ISuggestedActionCategorySet requestedActionCategories, + SnapshotSpan range, + [EnumeratorCancellation] CancellationToken cancellationToken) + { + AssertIsForeground(); + + using var state = _state.TryAddReference(); + if (state is null) + yield break; + + var workspace = state.Target.Workspace; + if (workspace == null) + yield break; + + await workspace.Services.GetRequiredService().WaitUntilFullyLoadedAsync(cancellationToken).ConfigureAwait(true); + + using (Logger.LogBlock(FunctionId.SuggestedActions_GetSuggestedActionsAsync, cancellationToken)) + { + var document = range.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); + if (document == null) + yield break; + + // Compute and return the high pri set of fixes and refactorings first so the user + // can act on them immediately without waiting on the regular set. + var highPriSet = GetCodeFixesAndRefactoringsAsync(state, requestedActionCategories, document, range, _ => null, CodeActionProviderPriority.High, cancellationToken); + await foreach (var set in highPriSet) + yield return set; + + var lowPriSet = GetCodeFixesAndRefactoringsAsync(state, requestedActionCategories, document, range, _ => null, CodeActionProviderPriority.Normal, cancellationToken); + await foreach (var set in lowPriSet) + yield return set; + } + } + + private async IAsyncEnumerable GetCodeFixesAndRefactoringsAsync( + ReferenceCountedDisposable state, + ISuggestedActionCategorySet requestedActionCategories, + Document document, + SnapshotSpan range, + Func addOperationScope, + CodeActionProviderPriority priority, + [EnumeratorCancellation] CancellationToken cancellationToken) + { + var workspace = document.Project.Solution.Workspace; + var supportsFeatureService = workspace.Services.GetRequiredService(); + + var selection = TryGetCodeRefactoringSelection(state, range); + + var fixesTask = GetCodeFixesAsync( + state, supportsFeatureService, requestedActionCategories, workspace, document, range, + addOperationScope, priority, isBlocking: false, cancellationToken); + var refactoringsTask = GetRefactoringsAsync( + state, supportsFeatureService, requestedActionCategories, workspace, document, selection, + addOperationScope, priority, isBlocking: false, cancellationToken); + + if (priority == CodeActionProviderPriority.High) + { + // in a high pri scenario, return data as soon as possible so that the user can interact with them. + // this is especially important for state-machine oriented refactorings (like rename) where the user + // should always have access to them effectively synchronously. + var firstTask = await Task.WhenAny(fixesTask, refactoringsTask).ConfigureAwait(false); + var secondTask = firstTask == fixesTask ? refactoringsTask : fixesTask; + + var orderedTasks = new[] { firstTask, secondTask }; + foreach (var task in orderedTasks) + { + if (task == fixesTask) + { + var fixes = await fixesTask.ConfigureAwait(false); + foreach (var set in ConvertToSuggestedActionSets(state, selection, fixes, ImmutableArray.Empty)) + yield return set; + } + else + { + Contract.ThrowIfFalse(task == refactoringsTask); + + var refactorings = await refactoringsTask.ConfigureAwait(false); + foreach (var set in ConvertToSuggestedActionSets(state, selection, ImmutableArray.Empty, refactorings)) + yield return set; + } + } + } + else + { + await Task.WhenAll(fixesTask, refactoringsTask).ConfigureAwait(false); + var fixes = await fixesTask.ConfigureAwait(false); + var refactorings = await refactoringsTask.ConfigureAwait(false); + foreach (var set in ConvertToSuggestedActionSets(state, selection, fixes, refactorings)) + yield return set; + } + } + } + } +} diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 7583f9da8f23d..019e3f98edae8 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -33,7 +33,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions { internal partial class SuggestedActionsSourceProvider { - private partial class SuggestedActionsSource : ForegroundThreadAffinitizedObject, ISuggestedActionsSourceExperimental + private partial class SuggestedActionsSource : ForegroundThreadAffinitizedObject, ISuggestedActionsSource3 { private readonly ISuggestedActionCategoryRegistryService _suggestedActionCategoryRegistry; @@ -188,99 +188,6 @@ private IEnumerable ConvertToSuggestedActionSets(ReferenceCo return filteredSets.SelectAsArray(s => ConvertToSuggestedActionSet(s, state.Target.Owner, state.Target.SubjectBuffer)).WhereNotNull(); } - public async IAsyncEnumerable GetSuggestedActionsAsync( - ISuggestedActionCategorySet requestedActionCategories, - SnapshotSpan range, - [EnumeratorCancellation] CancellationToken cancellationToken) - { - AssertIsForeground(); - - using var state = _state.TryAddReference(); - if (state is null) - yield break; - - var workspace = state.Target.Workspace; - if (workspace == null) - yield break; - - await workspace.Services.GetRequiredService().WaitUntilFullyLoadedAsync(cancellationToken).ConfigureAwait(true); - - using (Logger.LogBlock(FunctionId.SuggestedActions_GetSuggestedActionsAsync, cancellationToken)) - { - var document = range.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); - if (document == null) - yield break; - - // Compute and return the high pri set of fixes and refactorings first so the user - // can act on them immediately without waiting on the regular set. - var highPriSet = GetCodeFixesAndRefactoringsAsync(state, requestedActionCategories, document, range, _ => null, CodeActionProviderPriority.High, cancellationToken); - await foreach (var set in highPriSet) - yield return set; - - var lowPriSet = GetCodeFixesAndRefactoringsAsync(state, requestedActionCategories, document, range, _ => null, CodeActionProviderPriority.Normal, cancellationToken); - await foreach (var set in lowPriSet) - yield return set; - } - } - - private async IAsyncEnumerable GetCodeFixesAndRefactoringsAsync( - ReferenceCountedDisposable state, - ISuggestedActionCategorySet requestedActionCategories, - Document document, - SnapshotSpan range, - Func addOperationScope, - CodeActionProviderPriority priority, - [EnumeratorCancellation] CancellationToken cancellationToken) - { - var workspace = document.Project.Solution.Workspace; - var supportsFeatureService = workspace.Services.GetRequiredService(); - - var selection = TryGetCodeRefactoringSelection(state, range); - - var fixesTask = GetCodeFixesAsync( - state, supportsFeatureService, requestedActionCategories, workspace, document, range, - addOperationScope, priority, isBlocking: false, cancellationToken); - var refactoringsTask = GetRefactoringsAsync( - state, supportsFeatureService, requestedActionCategories, workspace, document, selection, - addOperationScope, priority, isBlocking: false, cancellationToken); - - if (priority == CodeActionProviderPriority.High) - { - // in a high pri scenario, return data as soon as possible so that the user can interact with them. - // this is especially important for state-machine oriented refactorings (like rename) where the user - // should always have access to them effectively synchronously. - var firstTask = await Task.WhenAny(fixesTask, refactoringsTask).ConfigureAwait(false); - var secondTask = firstTask == fixesTask ? refactoringsTask : fixesTask; - - var orderedTasks = new[] { firstTask, secondTask }; - foreach (var task in orderedTasks) - { - if (task == fixesTask) - { - var fixes = await fixesTask.ConfigureAwait(false); - foreach (var set in ConvertToSuggestedActionSets(state, selection, fixes, ImmutableArray.Empty)) - yield return set; - } - else - { - Contract.ThrowIfFalse(task == refactoringsTask); - - var refactorings = await refactoringsTask.ConfigureAwait(false); - foreach (var set in ConvertToSuggestedActionSets(state, selection, ImmutableArray.Empty, refactorings)) - yield return set; - } - } - } - else - { - await Task.WhenAll(fixesTask, refactoringsTask).ConfigureAwait(false); - var fixes = await fixesTask.ConfigureAwait(false); - var refactorings = await refactoringsTask.ConfigureAwait(false); - foreach (var set in ConvertToSuggestedActionSets(state, selection, fixes, refactorings)) - yield return set; - } - } - [return: NotNullIfNotNull("unifiedSuggestedActionSet")] private SuggestedActionSet? ConvertToSuggestedActionSet(UnifiedSuggestedActionSet? unifiedSuggestedActionSet, SuggestedActionsSourceProvider owner, ITextBuffer subjectBuffer) { From 677099f33ed19bdfb453912fe15a76e17393eede Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 25 May 2021 19:43:07 -0700 Subject: [PATCH 32/53] Wrap --- ...estedActionSource_ISuggestedActionsSourceExperimental.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs index c3df634ae0f61..ac5c1434cebb3 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs @@ -49,11 +49,13 @@ public async IAsyncEnumerable GetSuggestedActionsAsync( // Compute and return the high pri set of fixes and refactorings first so the user // can act on them immediately without waiting on the regular set. - var highPriSet = GetCodeFixesAndRefactoringsAsync(state, requestedActionCategories, document, range, _ => null, CodeActionProviderPriority.High, cancellationToken); + var highPriSet = GetCodeFixesAndRefactoringsAsync( + state, requestedActionCategories, document, range, _ => null, CodeActionProviderPriority.High, cancellationToken); await foreach (var set in highPriSet) yield return set; - var lowPriSet = GetCodeFixesAndRefactoringsAsync(state, requestedActionCategories, document, range, _ => null, CodeActionProviderPriority.Normal, cancellationToken); + var lowPriSet = GetCodeFixesAndRefactoringsAsync( + state, requestedActionCategories, document, range, _ => null, CodeActionProviderPriority.Normal, cancellationToken); await foreach (var set in lowPriSet) yield return set; } From 1d8249aebe97c8b958420b80df2db464047d7ad9 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 25 May 2021 19:46:51 -0700 Subject: [PATCH 33/53] REvert --- .../Core.Wpf/Suggestions/SuggestedActionsSource.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 019e3f98edae8..60baab72c7f4f 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -331,7 +331,11 @@ private static async Task> GetRefactor CancellationToken cancellationToken) { if (!selection.HasValue) + { + // this is here to fail test and see why it is failed. + Trace.WriteLine("given range is not current"); return ImmutableArray.Empty; + } if (!workspace.Options.GetOption(EditorComponentOnOffOptions.CodeRefactorings) || state.Target.Owner._codeRefactoringService == null || From 647525450c5ff1a727f99ec5e349e3926cc623b0 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 25 May 2021 19:48:00 -0700 Subject: [PATCH 34/53] Make sync --- .../Core.Wpf/Suggestions/SuggestedActionsSource.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 60baab72c7f4f..2a58b93225fe2 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -318,7 +318,7 @@ private ImmutableArray GetRefactorings( addOperationScope, CodeActionProviderPriority.None, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); } - private static async Task> GetRefactoringsAsync( + private static Task> GetRefactoringsAsync( ReferenceCountedDisposable state, ITextBufferSupportsFeatureService supportsFeatureService, ISuggestedActionCategorySet requestedActionCategories, @@ -334,23 +334,23 @@ private static async Task> GetRefactor { // this is here to fail test and see why it is failed. Trace.WriteLine("given range is not current"); - return ImmutableArray.Empty; + return SpecializedTasks.EmptyImmutableArray(); } if (!workspace.Options.GetOption(EditorComponentOnOffOptions.CodeRefactorings) || state.Target.Owner._codeRefactoringService == null || !supportsFeatureService.SupportsRefactorings(state.Target.SubjectBuffer)) { - return ImmutableArray.Empty; + return SpecializedTasks.EmptyImmutableArray(); } // If we are computing refactorings outside the 'Refactoring' context, i.e. for example, from the lightbulb under a squiggle or selection, // then we want to filter out refactorings outside the selection span. var filterOutsideSelection = !requestedActionCategories.Contains(PredefinedSuggestedActionCategoryNames.Refactoring); - return await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeRefactoringsAsync( + return UnifiedSuggestedActionsSource.GetFilterAndOrderCodeRefactoringsAsync( workspace, state.Target.Owner._codeRefactoringService, document, selection.Value, priority, isBlocking, - addOperationScope, filterOutsideSelection, cancellationToken).ConfigureAwait(false); + addOperationScope, filterOutsideSelection, cancellationToken); } public Task HasSuggestedActionsAsync( From dd8e145a6cfc008de6a1d8f55d95352223a7e6bc Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 25 May 2021 20:01:14 -0700 Subject: [PATCH 35/53] Fix --- .../Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb index 3a9d55baf940d..58043068bcf70 100644 --- a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb +++ b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb @@ -5,6 +5,7 @@ Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CommonDiagnosticAnalyzers Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Editor.UnitTests @@ -512,7 +513,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Public Sub Reanalyze(workspace As Workspace, Optional projectIds As IEnumerable(Of ProjectId) = Nothing, Optional documentIds As IEnumerable(Of DocumentId) = Nothing, Optional highPriority As Boolean = False) Implements IDiagnosticAnalyzerService.Reanalyze End Sub - Public Function GetDiagnosticsForSpanAsync(document As Document, range As TextSpan, Optional diagnosticId As String = Nothing, Optional includeSuppressedDiagnostics As Boolean = False, Optional highPriority As Boolean? = Nothing, Optional addOperationScope As Func(Of String, IDisposable) = Nothing, Optional cancellationToken As CancellationToken = Nothing) As Task(Of ImmutableArray(Of DiagnosticData)) Implements IDiagnosticAnalyzerService.GetDiagnosticsForSpanAsync + Public Function GetDiagnosticsForSpanAsync(document As Document, range As TextSpan, Optional diagnosticId As String = Nothing, Optional includeSuppressedDiagnostics As Boolean = False, Optional priority As CodeActionProviderPriority = CodeActionProviderPriority.None, Optional addOperationScope As Func(Of String, IDisposable) = Nothing, Optional cancellationToken As CancellationToken = Nothing) As Task(Of ImmutableArray(Of DiagnosticData)) Implements IDiagnosticAnalyzerService.GetDiagnosticsForSpanAsync Return SpecializedTasks.EmptyImmutableArray(Of DiagnosticData) End Function From 63320d4cfc5a04329c2adee8c53e1639c6926f7b Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 25 May 2021 20:06:26 -0700 Subject: [PATCH 36/53] Revert --- .../Core/Portable/Diagnostics/DocumentAnalysisScope.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Workspaces/Core/Portable/Diagnostics/DocumentAnalysisScope.cs b/src/Workspaces/Core/Portable/Diagnostics/DocumentAnalysisScope.cs index d978a95006e5c..ccf7abf5554c2 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/DocumentAnalysisScope.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/DocumentAnalysisScope.cs @@ -31,6 +31,7 @@ public DocumentAnalysisScope( Span = span; Analyzers = analyzers; Kind = kind; + _lazyAdditionalFile = new Lazy(ComputeAdditionalFile); } From 306220688d92977669e2f8d19bd937b22dabfa71 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 26 May 2021 10:57:57 -0700 Subject: [PATCH 37/53] No alloc --- .../DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs index 9bcd44fc05bc3..03d7a9a177539 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs @@ -189,9 +189,10 @@ private async Task TryGetCachedDocumentDiagnosticsAsync( var version = await GetDiagnosticVersionAsync(_document.Project, cancellationToken).ConfigureAwait(false); if (existingData.Version == version) { - if (!existingData.Items.IsEmpty) + foreach (var item in existingData.Items) { - list.AddRange(existingData.Items.Where(ShouldInclude)); + if (ShouldInclude(item)) + list.Add(item); } return true; From 00ea3f0a698a1276359eaf672b5eb19a53f0640e Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 26 May 2021 11:03:43 -0700 Subject: [PATCH 38/53] Simplify --- ...ticIncrementalAnalyzer_GetDiagnosticsForSpan.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs index 03d7a9a177539..01d5f788aac19 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs @@ -132,12 +132,10 @@ public async Task TryGetAsync(ArrayBuilder list, Cancellat using var _3 = ArrayBuilder.GetInstance(out var semanticDocumentBasedAnalyzers); foreach (var stateSet in _stateSets) { - if (!await TryGetCachedDocumentDiagnosticsAsync(stateSet, AnalysisKind.Syntax, list, cancellationToken).ConfigureAwait(false)) - { + if (!await TryAddCachedDocumentDiagnosticsAsync(stateSet, AnalysisKind.Syntax, list, cancellationToken).ConfigureAwait(false)) syntaxAnalyzers.Add(stateSet.Analyzer); - } - if (!await TryGetCachedDocumentDiagnosticsAsync(stateSet, AnalysisKind.Semantic, list, cancellationToken).ConfigureAwait(false)) + if (!await TryAddCachedDocumentDiagnosticsAsync(stateSet, AnalysisKind.Semantic, list, cancellationToken).ConfigureAwait(false)) { // Check whether we want up-to-date document wide semantic diagnostics var spanBased = stateSet.Analyzer.SupportsSpanBasedSemanticDiagnosticAnalysis(); @@ -168,7 +166,10 @@ public async Task TryGetAsync(ArrayBuilder list, Cancellat } } - private async Task TryGetCachedDocumentDiagnosticsAsync( + /// + /// Returns if we were able to add the cached diagnostics and we do not need to compute them fresh. + /// + private async Task TryAddCachedDocumentDiagnosticsAsync( StateSet stateSet, AnalysisKind kind, ArrayBuilder list, @@ -177,6 +178,9 @@ private async Task TryGetCachedDocumentDiagnosticsAsync( if (!stateSet.Analyzer.SupportAnalysisKind(kind) || !MatchesPriority(stateSet.Analyzer)) { + // In the case where the analyzer doesn't support the requested kind or priority, act as if we succeeded, but just + // added no items to the result. Effectively we did add the cached values, just that all the values that could have + // been added have been filtered out. We do not want to then compute the up to date values in the caller. return true; } From 4e3524b2fd4fb568ff24b5cbb57cf75ddfb1b579 Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Wed, 26 May 2021 18:05:25 -0400 Subject: [PATCH 39/53] Update src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs Co-authored-by: Jason Malinowski --- .../Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs index c14fce74a65af..d7eeeb29e60d5 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs @@ -32,7 +32,7 @@ protected AbstractAddImportCodeFixProvider( } /// - /// Add-using gets special priviliges as being the most used code-action, along with being a core + /// Add-using gets special privileges as being the most used code-action, along with being a core /// 'smart tag' feature in VS prior to us even having 'light bulbs'. We want them to be computed /// first, ahead of everything else, and the main results should show up at the top of the list. /// From fe96d77eb3eb0ac22077b7dc4b08da9c8b12127e Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Wed, 26 May 2021 18:05:39 -0400 Subject: [PATCH 40/53] Update src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs Co-authored-by: Jason Malinowski --- src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs b/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs index 5ca0b3fa318f0..fe4501b9dfd38 100644 --- a/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs +++ b/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CodeActions #pragma warning disable CA1200 // Avoid using cref tags with a prefix /// /// Internal priority used to bluntly place items in a light bulb in strict orderings. Priorities take - /// the highest precedence when ordering items so that we can ensure very important items get top prominance, + /// the highest precedence when ordering items so that we can ensure very important items get top prominence, /// and low priority items do not. /// /// From 3423ad90917c57a6789ca6ebcd2625de3606b289 Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Wed, 26 May 2021 18:07:18 -0400 Subject: [PATCH 41/53] Update src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs Co-authored-by: Andrew Hall --- ...SuggestedActionSource_ISuggestedActionsSourceExperimental.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs index ac5c1434cebb3..6178df3bb3c2e 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs @@ -36,7 +36,7 @@ public async IAsyncEnumerable GetSuggestedActionsAsync( yield break; var workspace = state.Target.Workspace; - if (workspace == null) + if (workspace is null) yield break; await workspace.Services.GetRequiredService().WaitUntilFullyLoadedAsync(cancellationToken).ConfigureAwait(true); From 8ab79717003f1a59e505d3c2dde7fe94d9063a35 Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Wed, 26 May 2021 18:07:41 -0400 Subject: [PATCH 42/53] Update src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs Co-authored-by: Andrew Hall --- ...SuggestedActionSource_ISuggestedActionsSourceExperimental.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs index 6178df3bb3c2e..1e2313c77bcdf 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs @@ -44,7 +44,7 @@ public async IAsyncEnumerable GetSuggestedActionsAsync( using (Logger.LogBlock(FunctionId.SuggestedActions_GetSuggestedActionsAsync, cancellationToken)) { var document = range.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); - if (document == null) + if (document is null) yield break; // Compute and return the high pri set of fixes and refactorings first so the user From c2b1f614cb839aadcf3be224bc8b7348499d1120 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 26 May 2021 18:07:30 -0700 Subject: [PATCH 43/53] Simplify --- .../SuggestedActionSource_ISuggestedActionsSourceExperimental.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs index ac5c1434cebb3..ef4f899c1c701 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs @@ -111,7 +111,6 @@ private async IAsyncEnumerable GetCodeFixesAndRefactoringsAs } else { - await Task.WhenAll(fixesTask, refactoringsTask).ConfigureAwait(false); var fixes = await fixesTask.ConfigureAwait(false); var refactorings = await refactoringsTask.ConfigureAwait(false); foreach (var set in ConvertToSuggestedActionSets(state, selection, fixes, refactorings)) From ddcf0b01c9266f1307c8eb1db52d5db46398b170 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 26 May 2021 18:08:57 -0700 Subject: [PATCH 44/53] Simplify --- ...gestedActionSource_ISuggestedActionsSourceExperimental.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs index ef4f899c1c701..c04061a2ef3fc 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs @@ -111,9 +111,8 @@ private async IAsyncEnumerable GetCodeFixesAndRefactoringsAs } else { - var fixes = await fixesTask.ConfigureAwait(false); - var refactorings = await refactoringsTask.ConfigureAwait(false); - foreach (var set in ConvertToSuggestedActionSets(state, selection, fixes, refactorings)) + var actionsArray = await Task.WhenAll(fixesTask, refactoringsTask).ConfigureAwait(false); + foreach (var set in ConvertToSuggestedActionSets(state, selection, fixes: actionsArray[0], refactorings: actionsArray[1])) yield return set; } } From 1d59ca0c9aadb0c9f6be37d42391fedefa606147 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 26 May 2021 18:15:33 -0700 Subject: [PATCH 45/53] Simplify --- .../Suggestions/SuggestedActionsSource.cs | 53 ++++--------------- 1 file changed, 10 insertions(+), 43 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 2a58b93225fe2..c58e2d7040c2a 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -171,12 +171,12 @@ public bool TryGetTelemetryId(out Guid telemetryId) // We convert the code fixes and refactorings to UnifiedSuggestedActionSets instead of // SuggestedActionSets so that we can share logic between local Roslyn and LSP. - var fixes = GetCodeFixes( - state, supportsFeatureService, requestedActionCategories, workspace, - document, range, addOperationScope, cancellationToken); - var refactorings = GetRefactorings( - state, supportsFeatureService, requestedActionCategories, workspace, - document, selection, addOperationScope, cancellationToken); + var fixes = GetCodeFixesAsync( + state, supportsFeatureService, requestedActionCategories, workspace, document, range, + addOperationScope, CodeActionProviderPriority.None, isBlocking: true, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); + var refactorings = GetRefactoringsAsync( + state, supportsFeatureService, requestedActionCategories, workspace, document, selection, + addOperationScope, CodeActionProviderPriority.None, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); return ConvertToSuggestedActionSets(state, selection, fixes, refactorings); } @@ -242,24 +242,7 @@ static SuggestedActionSetPriority ConvertToSuggestedActionSetPriority(UnifiedSug }; } - private ImmutableArray GetCodeFixes( - ReferenceCountedDisposable state, - ITextBufferSupportsFeatureService supportsFeatureService, - ISuggestedActionCategorySet requestedActionCategories, - Workspace workspace, - Document document, - SnapshotSpan range, - Func addOperationScope, - CancellationToken cancellationToken) - { - this.AssertIsForeground(); - - return GetCodeFixesAsync( - state, supportsFeatureService, requestedActionCategories, workspace, document, range, - addOperationScope, CodeActionProviderPriority.None, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); - } - - private static async Task> GetCodeFixesAsync( + private static ValueTask> GetCodeFixesAsync( ReferenceCountedDisposable state, ITextBufferSupportsFeatureService supportsFeatureService, ISuggestedActionCategorySet requestedActionCategories, @@ -275,16 +258,16 @@ private static async Task> GetCodeFixe !supportsFeatureService.SupportsCodeFixes(state.Target.SubjectBuffer) || !requestedActionCategories.Contains(PredefinedSuggestedActionCategoryNames.CodeFix)) { - return ImmutableArray.Empty; + return ValueTaskFactory.FromResult(ImmutableArray.Empty); } // Make sure we include the suppression fixes even when the light bulb is only asking for only code fixes. // See https://github.com/dotnet/roslyn/issues/29589 const bool includeSuppressionFixes = true; - return await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeFixesAsync( + return UnifiedSuggestedActionsSource.GetFilterAndOrderCodeFixesAsync( workspace, state.Target.Owner._codeFixService, document, range.Span.ToTextSpan(), - includeSuppressionFixes, priority, isBlocking, addOperationScope, cancellationToken).ConfigureAwait(false); + includeSuppressionFixes, priority, isBlocking, addOperationScope, cancellationToken); } private static string GetFixCategory(DiagnosticSeverity severity) @@ -302,22 +285,6 @@ private static string GetFixCategory(DiagnosticSeverity severity) } } - private ImmutableArray GetRefactorings( - ReferenceCountedDisposable state, - ITextBufferSupportsFeatureService supportsFeatureService, - ISuggestedActionCategorySet requestedActionCategories, - Workspace workspace, - Document document, - TextSpan? selection, - Func addOperationScope, - CancellationToken cancellationToken) - { - this.AssertIsForeground(); - return GetRefactoringsAsync( - state, supportsFeatureService, requestedActionCategories, workspace, document, selection, - addOperationScope, CodeActionProviderPriority.None, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); - } - private static Task> GetRefactoringsAsync( ReferenceCountedDisposable state, ITextBufferSupportsFeatureService supportsFeatureService, From 8a7679f60a91b3d147a4fb56a9f4e9f744ea7801 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 26 May 2021 18:16:53 -0700 Subject: [PATCH 46/53] Simplify --- .../Core.Wpf/Suggestions/SuggestedActionsSource.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index c58e2d7040c2a..195820c10f293 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -173,7 +173,7 @@ public bool TryGetTelemetryId(out Guid telemetryId) // SuggestedActionSets so that we can share logic between local Roslyn and LSP. var fixes = GetCodeFixesAsync( state, supportsFeatureService, requestedActionCategories, workspace, document, range, - addOperationScope, CodeActionProviderPriority.None, isBlocking: true, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); + addOperationScope, CodeActionProviderPriority.None, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); var refactorings = GetRefactoringsAsync( state, supportsFeatureService, requestedActionCategories, workspace, document, selection, addOperationScope, CodeActionProviderPriority.None, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); @@ -242,7 +242,7 @@ static SuggestedActionSetPriority ConvertToSuggestedActionSetPriority(UnifiedSug }; } - private static ValueTask> GetCodeFixesAsync( + private static Task> GetCodeFixesAsync( ReferenceCountedDisposable state, ITextBufferSupportsFeatureService supportsFeatureService, ISuggestedActionCategorySet requestedActionCategories, @@ -258,7 +258,7 @@ private static ValueTask> GetCodeFixes !supportsFeatureService.SupportsCodeFixes(state.Target.SubjectBuffer) || !requestedActionCategories.Contains(PredefinedSuggestedActionCategoryNames.CodeFix)) { - return ValueTaskFactory.FromResult(ImmutableArray.Empty); + return SpecializedTasks.EmptyImmutableArray(); } // Make sure we include the suppression fixes even when the light bulb is only asking for only code fixes. @@ -267,7 +267,7 @@ private static ValueTask> GetCodeFixes return UnifiedSuggestedActionsSource.GetFilterAndOrderCodeFixesAsync( workspace, state.Target.Owner._codeFixService, document, range.Span.ToTextSpan(), - includeSuppressionFixes, priority, isBlocking, addOperationScope, cancellationToken); + includeSuppressionFixes, priority, isBlocking, addOperationScope, cancellationToken).AsTask(); } private static string GetFixCategory(DiagnosticSeverity severity) From e626d4bbcb6ac220849d92ec41d3d03e5f2b4dd0 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 26 May 2021 18:22:10 -0700 Subject: [PATCH 47/53] Rename type --- ...onSource_ISuggestedActionsSourceExperimental.cs | 8 ++++---- .../Core.Wpf/Suggestions/SuggestedActionsSource.cs | 8 ++++---- .../Helpers/MockDiagnosticAnalyzerService.cs | 2 +- .../Core/Portable/CodeFixes/CodeFixService.cs | 10 +++++----- .../Core/Portable/CodeFixes/ICodeFixService.cs | 4 ++-- .../CodeRefactorings/CodeRefactoringService.cs | 6 +++--- .../CodeRefactorings/ICodeRefactoringService.cs | 4 ++-- .../Diagnostics/DiagnosticAnalyzerService.cs | 4 ++-- ...ticIncrementalAnalyzer_GetDiagnosticsForSpan.cs | 14 +++++++------- .../Diagnostics/IDiagnosticAnalyzerService.cs | 4 ++-- .../UnifiedSuggestedActionsSource.cs | 4 ++-- .../Handler/CodeActions/CodeActionHelpers.cs | 4 ++-- .../ExternalDiagnosticUpdateSourceTests.vb | 2 +- ...derPriority.cs => CodeActionRequestPriority.cs} | 2 +- 14 files changed, 38 insertions(+), 38 deletions(-) rename src/Workspaces/Core/Portable/CodeActions/{CodeActionProviderPriority.cs => CodeActionRequestPriority.cs} (97%) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs index 4abb99372f8ac..607c380d95b94 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs @@ -50,12 +50,12 @@ public async IAsyncEnumerable GetSuggestedActionsAsync( // Compute and return the high pri set of fixes and refactorings first so the user // can act on them immediately without waiting on the regular set. var highPriSet = GetCodeFixesAndRefactoringsAsync( - state, requestedActionCategories, document, range, _ => null, CodeActionProviderPriority.High, cancellationToken); + state, requestedActionCategories, document, range, _ => null, CodeActionRequestPriority.High, cancellationToken); await foreach (var set in highPriSet) yield return set; var lowPriSet = GetCodeFixesAndRefactoringsAsync( - state, requestedActionCategories, document, range, _ => null, CodeActionProviderPriority.Normal, cancellationToken); + state, requestedActionCategories, document, range, _ => null, CodeActionRequestPriority.Normal, cancellationToken); await foreach (var set in lowPriSet) yield return set; } @@ -67,7 +67,7 @@ private async IAsyncEnumerable GetCodeFixesAndRefactoringsAs Document document, SnapshotSpan range, Func addOperationScope, - CodeActionProviderPriority priority, + CodeActionRequestPriority priority, [EnumeratorCancellation] CancellationToken cancellationToken) { var workspace = document.Project.Solution.Workspace; @@ -82,7 +82,7 @@ private async IAsyncEnumerable GetCodeFixesAndRefactoringsAs state, supportsFeatureService, requestedActionCategories, workspace, document, selection, addOperationScope, priority, isBlocking: false, cancellationToken); - if (priority == CodeActionProviderPriority.High) + if (priority == CodeActionRequestPriority.High) { // in a high pri scenario, return data as soon as possible so that the user can interact with them. // this is especially important for state-machine oriented refactorings (like rename) where the user diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 195820c10f293..39d7254265d0a 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -173,10 +173,10 @@ public bool TryGetTelemetryId(out Guid telemetryId) // SuggestedActionSets so that we can share logic between local Roslyn and LSP. var fixes = GetCodeFixesAsync( state, supportsFeatureService, requestedActionCategories, workspace, document, range, - addOperationScope, CodeActionProviderPriority.None, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); + addOperationScope, CodeActionRequestPriority.None, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); var refactorings = GetRefactoringsAsync( state, supportsFeatureService, requestedActionCategories, workspace, document, selection, - addOperationScope, CodeActionProviderPriority.None, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); + addOperationScope, CodeActionRequestPriority.None, isBlocking: true, cancellationToken).WaitAndGetResult(cancellationToken); return ConvertToSuggestedActionSets(state, selection, fixes, refactorings); } @@ -250,7 +250,7 @@ private static Task> GetCodeFixesAsync Document document, SnapshotSpan range, Func addOperationScope, - CodeActionProviderPriority priority, + CodeActionRequestPriority priority, bool isBlocking, CancellationToken cancellationToken) { @@ -293,7 +293,7 @@ private static Task> GetRefactoringsAs Document document, TextSpan? selection, Func addOperationScope, - CodeActionProviderPriority priority, + CodeActionRequestPriority priority, bool isBlocking, CancellationToken cancellationToken) { diff --git a/src/EditorFeatures/Test/EditAndContinue/Helpers/MockDiagnosticAnalyzerService.cs b/src/EditorFeatures/Test/EditAndContinue/Helpers/MockDiagnosticAnalyzerService.cs index 34f45be83990c..cab6ff1c804ad 100644 --- a/src/EditorFeatures/Test/EditAndContinue/Helpers/MockDiagnosticAnalyzerService.cs +++ b/src/EditorFeatures/Test/EditAndContinue/Helpers/MockDiagnosticAnalyzerService.cs @@ -41,7 +41,7 @@ public Task> GetDiagnosticsAsync(Solution solutio public Task> GetDiagnosticsForIdsAsync(Solution solution, ProjectId? projectId = null, DocumentId? documentId = null, ImmutableHashSet? diagnosticIds = null, bool includeSuppressedDiagnostics = false, CancellationToken cancellationToken = default) => throw new NotImplementedException(); - public Task> GetDiagnosticsForSpanAsync(Document document, TextSpan range, string? diagnosticIdOpt = null, bool includeSuppressedDiagnostics = false, CodeActionProviderPriority priority = CodeActionProviderPriority.None, Func? addOperationScope = null, CancellationToken cancellationToken = default) + public Task> GetDiagnosticsForSpanAsync(Document document, TextSpan range, string? diagnosticIdOpt = null, bool includeSuppressedDiagnostics = false, CodeActionRequestPriority priority = CodeActionRequestPriority.None, Func? addOperationScope = null, CancellationToken cancellationToken = default) => throw new NotImplementedException(); public Task> GetProjectDiagnosticsForIdsAsync(Solution solution, ProjectId? projectId = null, ImmutableHashSet? diagnosticIds = null, bool includeSuppressedDiagnostics = false, CancellationToken cancellationToken = default) diff --git a/src/Features/Core/Portable/CodeFixes/CodeFixService.cs b/src/Features/Core/Portable/CodeFixes/CodeFixService.cs index 70ded7150749a..eb08e9868f83c 100644 --- a/src/Features/Core/Portable/CodeFixes/CodeFixService.cs +++ b/src/Features/Core/Portable/CodeFixes/CodeFixService.cs @@ -156,7 +156,7 @@ public async Task> GetFixesAsync( Document document, TextSpan range, bool includeConfigurationFixes, - CodeActionProviderPriority priority, + CodeActionRequestPriority priority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken) @@ -240,7 +240,7 @@ await AppendConfigurationsAsync( } using var resultDisposer = ArrayBuilder.GetInstance(out var result); - await AppendFixesAsync(document, range, diagnostics, fixAllForInSpan: true, CodeActionProviderPriority.None, isBlocking: false, result, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); + await AppendFixesAsync(document, range, diagnostics, fixAllForInSpan: true, CodeActionRequestPriority.None, isBlocking: false, result, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); // TODO: Just get the first fix for now until we have a way to config user's preferred fix // https://github.com/dotnet/roslyn/issues/27066 @@ -334,7 +334,7 @@ private async Task AppendFixesAsync( TextSpan span, IEnumerable diagnostics, bool fixAllForInSpan, - CodeActionProviderPriority priority, + CodeActionRequestPriority priority, bool isBlocking, ArrayBuilder result, Func addOperationScope, @@ -399,9 +399,9 @@ private async Task AppendFixesAsync( { cancellationToken.ThrowIfCancellationRequested(); - if (priority != CodeActionProviderPriority.None) + if (priority != CodeActionRequestPriority.None) { - var highPriority = priority == CodeActionProviderPriority.High; + var highPriority = priority == CodeActionRequestPriority.High; if (highPriority != fixer.IsHighPriority) continue; } diff --git a/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs b/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs index df59ecabc189c..4d31f79a088cc 100644 --- a/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs +++ b/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.CodeFixes { internal interface ICodeFixService { - Task> GetFixesAsync(Document document, TextSpan textSpan, bool includeSuppressionFixes, CodeActionProviderPriority priority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken); + Task> GetFixesAsync(Document document, TextSpan textSpan, bool includeSuppressionFixes, CodeActionRequestPriority priority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken); Task GetDocumentFixAllForIdInSpanAsync(Document document, TextSpan textSpan, string diagnosticId, CancellationToken cancellationToken); Task ApplyCodeFixesForSpecificDiagnosticIdAsync(Document document, string diagnosticId, IProgressTracker progressTracker, CancellationToken cancellationToken); CodeFixProvider? GetSuppressionFixer(string language, IEnumerable diagnosticIds); @@ -28,6 +28,6 @@ public static Task> GetFixesAsync(this ICodeFi => service.GetFixesAsync(document, range, includeConfigurationFixes, isBlocking: false, cancellationToken); public static Task> GetFixesAsync(this ICodeFixService service, Document document, TextSpan range, bool includeConfigurationFixes, bool isBlocking, CancellationToken cancellationToken) - => service.GetFixesAsync(document, range, includeConfigurationFixes, CodeActionProviderPriority.None, isBlocking, addOperationScope: _ => null, cancellationToken); + => service.GetFixesAsync(document, range, includeConfigurationFixes, CodeActionRequestPriority.None, isBlocking, addOperationScope: _ => null, cancellationToken); } } diff --git a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs index b74f27a4fe583..4adf817061a8b 100644 --- a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs @@ -108,7 +108,7 @@ public async Task HasRefactoringsAsync( public async Task> GetRefactoringsAsync( Document document, TextSpan state, - CodeActionProviderPriority priority, + CodeActionRequestPriority priority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken) @@ -120,9 +120,9 @@ public async Task> GetRefactoringsAsync( foreach (var provider in GetProviders(document)) { - if (priority != CodeActionProviderPriority.None) + if (priority != CodeActionRequestPriority.None) { - var highPriority = priority == CodeActionProviderPriority.High; + var highPriority = priority == CodeActionRequestPriority.High; if (highPriority != provider.IsHighPriority) continue; } diff --git a/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs index 8fcf9af8c8e9b..840c4835d72d4 100644 --- a/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs @@ -15,7 +15,7 @@ internal interface ICodeRefactoringService { Task HasRefactoringsAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken); - Task> GetRefactoringsAsync(Document document, TextSpan textSpan, CodeActionProviderPriority priority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken); + Task> GetRefactoringsAsync(Document document, TextSpan textSpan, CodeActionRequestPriority priority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken); } internal static class ICodeRefactoringServiceExtensions @@ -24,6 +24,6 @@ public static Task> GetRefactoringsAsync(this IC => service.GetRefactoringsAsync(document, state, isBlocking: false, cancellationToken); public static Task> GetRefactoringsAsync(this ICodeRefactoringService service, Document document, TextSpan state, bool isBlocking, CancellationToken cancellationToken) - => service.GetRefactoringsAsync(document, state, CodeActionProviderPriority.None, isBlocking, addOperationScope: _ => null, cancellationToken); + => service.GetRefactoringsAsync(document, state, CodeActionRequestPriority.None, isBlocking, addOperationScope: _ => null, cancellationToken); } } diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs index 304a2ad60fc09..98f013d6a0ebf 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs @@ -71,7 +71,7 @@ public Task TryAppendDiagnosticsForSpanAsync(Document document, TextSpan r { // always make sure that analyzer is called on background thread. return Task.Run(() => analyzer.TryAppendDiagnosticsForSpanAsync( - document, range, diagnostics, diagnosticId: null, includeSuppressedDiagnostics, CodeActionProviderPriority.None, blockForData: false, addOperationScope: null, cancellationToken), cancellationToken); + document, range, diagnostics, diagnosticId: null, includeSuppressedDiagnostics, CodeActionRequestPriority.None, blockForData: false, addOperationScope: null, cancellationToken), cancellationToken); } return SpecializedTasks.False; @@ -81,7 +81,7 @@ public Task> GetDiagnosticsForSpanAsync( Document document, TextSpan range, string? diagnosticId, bool includeSuppressedDiagnostics, - CodeActionProviderPriority priority, + CodeActionRequestPriority priority, Func? addOperationScope, CancellationToken cancellationToken) { diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs index 01d5f788aac19..888d5f13bb44d 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs @@ -22,7 +22,7 @@ internal partial class DiagnosticIncrementalAnalyzer { public async Task TryAppendDiagnosticsForSpanAsync( Document document, TextSpan range, ArrayBuilder result, string? diagnosticId, - bool includeSuppressedDiagnostics, CodeActionProviderPriority priority, bool blockForData, + bool includeSuppressedDiagnostics, CodeActionRequestPriority priority, bool blockForData, Func? addOperationScope, CancellationToken cancellationToken) { var getter = await LatestDiagnosticsForSpanGetter.CreateAsync( @@ -36,7 +36,7 @@ public async Task> GetDiagnosticsForSpanAsync( TextSpan range, string? diagnosticId, bool includeSuppressedDiagnostics, - CodeActionProviderPriority priority, + CodeActionRequestPriority priority, bool blockForData, Func? addOperationScope, CancellationToken cancellationToken) @@ -63,7 +63,7 @@ private sealed class LatestDiagnosticsForSpanGetter private readonly TextSpan _range; private readonly bool _blockForData; private readonly bool _includeSuppressedDiagnostics; - private readonly CodeActionProviderPriority _priority; + private readonly CodeActionRequestPriority _priority; private readonly string? _diagnosticId; private readonly Func? _addOperationScope; @@ -76,7 +76,7 @@ public static async Task CreateAsync( bool blockForData, Func? addOperationScope, bool includeSuppressedDiagnostics, - CodeActionProviderPriority priority, + CodeActionRequestPriority priority, string? diagnosticId, CancellationToken cancellationToken) { @@ -106,7 +106,7 @@ private LatestDiagnosticsForSpanGetter( bool blockForData, Func? addOperationScope, bool includeSuppressedDiagnostics, - CodeActionProviderPriority priority) + CodeActionRequestPriority priority) { _owner = owner; _compilationWithAnalyzers = compilationWithAnalyzers; @@ -240,7 +240,7 @@ private async Task ComputeDocumentDiagnosticsAsync( private bool MatchesPriority(DiagnosticAnalyzer analyzer) { // If caller isn't asking for prioritized result, then run all analyzers. - if (_priority == CodeActionProviderPriority.None) + if (_priority == CodeActionRequestPriority.None) return true; // Otherwise, check our special internal flag to tell. @@ -250,7 +250,7 @@ private bool MatchesPriority(DiagnosticAnalyzer analyzer) // add-using fixer is high pri, and it works off of compiler diagnostics. So we always have // to run that one up front. var analyzerIsHighPri = analyzer.IsCompilerAnalyzer() || analyzer is IBuiltInAnalyzer { IsHighPriority: true }; - var highPriority = _priority == CodeActionProviderPriority.High; + var highPriority = _priority == CodeActionRequestPriority.High; return analyzerIsHighPri == highPriority; } diff --git a/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs index b7f076b352aab..ba1bb8fb23c7f 100644 --- a/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs +++ b/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs @@ -77,12 +77,12 @@ internal interface IDiagnosticAnalyzerService /// This can be expensive since it is force analyzing diagnostics if it doesn't have up-to-date one yet. /// If diagnosticIdOpt is not null, it gets diagnostics only for this given diagnosticIdOpt value /// - Task> GetDiagnosticsForSpanAsync(Document document, TextSpan range, string? diagnosticIdOpt = null, bool includeSuppressedDiagnostics = false, CodeActionProviderPriority priority = CodeActionProviderPriority.None, Func? addOperationScope = null, CancellationToken cancellationToken = default); + Task> GetDiagnosticsForSpanAsync(Document document, TextSpan range, string? diagnosticIdOpt = null, bool includeSuppressedDiagnostics = false, CodeActionRequestPriority priority = CodeActionRequestPriority.None, Func? addOperationScope = null, CancellationToken cancellationToken = default); } internal static class IDiagnosticAnalyzerServiceExtensions { public static Task> GetDiagnosticsForSpanAsync(this IDiagnosticAnalyzerService service, Document document, TextSpan range, string? diagnosticIdOpt = null, bool includeSuppressedDiagnostics = false, Func? addOperationScope = null, CancellationToken cancellationToken = default) - => service.GetDiagnosticsForSpanAsync(document, range, diagnosticIdOpt, includeSuppressedDiagnostics, CodeActionProviderPriority.None, addOperationScope, cancellationToken); + => service.GetDiagnosticsForSpanAsync(document, range, diagnosticIdOpt, includeSuppressedDiagnostics, CodeActionRequestPriority.None, addOperationScope, cancellationToken); } } diff --git a/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs b/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs index bbf1f740fc143..8b14fabcc902c 100644 --- a/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs +++ b/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs @@ -35,7 +35,7 @@ public static async ValueTask> GetFilt Document document, TextSpan selection, bool includeSuppressionFixes, - CodeActionProviderPriority priority, + CodeActionRequestPriority priority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken) @@ -394,7 +394,7 @@ public static async Task> GetFilterAnd ICodeRefactoringService codeRefactoringService, Document document, TextSpan selection, - CodeActionProviderPriority priority, + CodeActionRequestPriority priority, bool isBlocking, Func addOperationScope, bool filterOutsideSelection, diff --git a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs index 1950cdde850c0..ed5c43597b543 100644 --- a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs +++ b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs @@ -223,10 +223,10 @@ private static async ValueTask> GetAct var codeFixes = await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeFixesAsync( document.Project.Solution.Workspace, codeFixService, document, textSpan, includeSuppressionFixes: true, - CodeActionProviderPriority.None, isBlocking: false, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); + CodeActionRequestPriority.None, isBlocking: false, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); var codeRefactorings = await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeRefactoringsAsync( - document.Project.Solution.Workspace, codeRefactoringService, document, textSpan, CodeActionProviderPriority.None, isBlocking: false, + document.Project.Solution.Workspace, codeRefactoringService, document, textSpan, CodeActionRequestPriority.None, isBlocking: false, addOperationScope: _ => null, filterOutsideSelection: false, cancellationToken).ConfigureAwait(false); var actionSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets(codeFixes, codeRefactorings, textSpan); diff --git a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb index 58043068bcf70..33152eb3fae72 100644 --- a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb +++ b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb @@ -513,7 +513,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Public Sub Reanalyze(workspace As Workspace, Optional projectIds As IEnumerable(Of ProjectId) = Nothing, Optional documentIds As IEnumerable(Of DocumentId) = Nothing, Optional highPriority As Boolean = False) Implements IDiagnosticAnalyzerService.Reanalyze End Sub - Public Function GetDiagnosticsForSpanAsync(document As Document, range As TextSpan, Optional diagnosticId As String = Nothing, Optional includeSuppressedDiagnostics As Boolean = False, Optional priority As CodeActionProviderPriority = CodeActionProviderPriority.None, Optional addOperationScope As Func(Of String, IDisposable) = Nothing, Optional cancellationToken As CancellationToken = Nothing) As Task(Of ImmutableArray(Of DiagnosticData)) Implements IDiagnosticAnalyzerService.GetDiagnosticsForSpanAsync + Public Function GetDiagnosticsForSpanAsync(document As Document, range As TextSpan, Optional diagnosticId As String = Nothing, Optional includeSuppressedDiagnostics As Boolean = False, Optional priority As CodeActionRequestPriority = CodeActionRequestPriority.None, Optional addOperationScope As Func(Of String, IDisposable) = Nothing, Optional cancellationToken As CancellationToken = Nothing) As Task(Of ImmutableArray(Of DiagnosticData)) Implements IDiagnosticAnalyzerService.GetDiagnosticsForSpanAsync Return SpecializedTasks.EmptyImmutableArray(Of DiagnosticData) End Function diff --git a/src/Workspaces/Core/Portable/CodeActions/CodeActionProviderPriority.cs b/src/Workspaces/Core/Portable/CodeActions/CodeActionRequestPriority.cs similarity index 97% rename from src/Workspaces/Core/Portable/CodeActions/CodeActionProviderPriority.cs rename to src/Workspaces/Core/Portable/CodeActions/CodeActionRequestPriority.cs index 318a7fb71cda6..544a478fcaad4 100644 --- a/src/Workspaces/Core/Portable/CodeActions/CodeActionProviderPriority.cs +++ b/src/Workspaces/Core/Portable/CodeActions/CodeActionRequestPriority.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.CodeActions { - internal enum CodeActionProviderPriority + internal enum CodeActionRequestPriority { /// /// No priority specified, all refactoring, code fixes, and analyzers should be run. This is equivalent From e0ca75c5b4c180c25ef66a07803cd582a45f72a4 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 26 May 2021 19:11:22 -0700 Subject: [PATCH 48/53] Move away from a bool --- ...tBuiltInCodeStyleDiagnosticAnalyzer_Core.cs | 3 ++- .../AbstractCodeQualityDiagnosticAnalyzer.cs | 3 ++- ...moveUnnecessaryImportsDiagnosticAnalyzer.cs | 3 ++- .../DiagnosticAnalyzerDriverTests.cs | 3 ++- .../EditAndContinueDiagnosticAnalyzer.cs | 3 ++- .../RenameTrackingCodeRefactoringProvider.cs | 4 +++- .../AbstractSuppressionAllCodeTests.cs | 2 +- .../DiagnosticAnalyzerServiceTests.cs | 3 ++- .../AbstractAddImportCodeFixProvider.cs | 4 +++- .../Core/Portable/CodeFixes/CodeFixService.cs | 8 ++------ .../CodeRefactorings/CodeRefactoringService.cs | 8 ++------ ...UnboundIdentifiersDiagnosticAnalyzerBase.cs | 3 ++- ...ncrementalAnalyzer_GetDiagnosticsForSpan.cs | 7 ++++--- .../SimplifyTypeNamesDiagnosticAnalyzerBase.cs | 3 ++- .../FSharpDocumentDiagnosticAnalyzer.cs | 3 ++- .../FSharpSimplifyNameDiagnosticAnalyzer.cs | 3 ++- .../FSharpUnusedDeclarationsAnalyzer.cs | 3 ++- .../Portable/CodeActions/CodeActionPriority.cs | 6 +++--- .../Core/Portable/CodeFixes/CodeFixProvider.cs | 18 +++++++++++++++--- .../CodeRefactoringProvider.cs | 18 +++++++++++++++--- .../CodeActions/CodeActionRequestPriority.cs | 12 ++++++------ .../Compiler/Core/CompilerExtensions.projitems | 1 + .../Core/Diagnostics/IBuiltInAnalyzer.cs | 7 ++++--- 23 files changed, 81 insertions(+), 47 deletions(-) rename src/Workspaces/{Core/Portable => SharedUtilitiesAndExtensions/Compiler/Core}/CodeActions/CodeActionRequestPriority.cs (70%) diff --git a/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer_Core.cs b/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer_Core.cs index 07948d75c2145..8b99806626614 100644 --- a/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer_Core.cs +++ b/src/Analyzers/Core/Analyzers/AbstractBuiltInCodeStyleDiagnosticAnalyzer_Core.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Diagnostics; namespace Microsoft.CodeAnalysis.CodeStyle @@ -44,7 +45,7 @@ protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(ImmutableArray false; + public CodeActionRequestPriority RequestPriority => CodeActionRequestPriority.Normal; public override ImmutableArray SupportedDiagnostics { get; } protected static DiagnosticDescriptor CreateDescriptorWithId( diff --git a/src/Analyzers/Core/Analyzers/AbstractCodeQualityDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/AbstractCodeQualityDiagnosticAnalyzer.cs index 5363009c03af5..d044fe182f8c5 100644 --- a/src/Analyzers/Core/Analyzers/AbstractCodeQualityDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/AbstractCodeQualityDiagnosticAnalyzer.cs @@ -5,6 +5,7 @@ #nullable disable using System.Collections.Immutable; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; @@ -28,7 +29,7 @@ protected AbstractCodeQualityDiagnosticAnalyzer( _generatedCodeAnalysisFlags = generatedCodeAnalysisFlags; } - public virtual bool IsHighPriority => false; + public CodeActionRequestPriority RequestPriority => CodeActionRequestPriority.Normal; public sealed override ImmutableArray SupportedDiagnostics { get; } public sealed override void Initialize(AnalysisContext context) diff --git a/src/Analyzers/Core/Analyzers/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsDiagnosticAnalyzer.cs index f1742bcb81ea6..bb8987d95ec05 100644 --- a/src/Analyzers/Core/Analyzers/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsDiagnosticAnalyzer.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; +using Microsoft.CodeAnalysis.CodeActions; #if CODE_STYLE using OptionSet = Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptions; @@ -117,7 +118,7 @@ public override ImmutableArray SupportedDiagnostics } } - public bool IsHighPriority => false; + public CodeActionRequestPriority RequestPriority => CodeActionRequestPriority.Normal; public bool OpenFileOnly(OptionSet options) => false; public override void Initialize(AnalysisContext context) diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs index 3a6486d173fcf..767cc14c124f1 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Diagnostics; @@ -184,7 +185,7 @@ private static void AccessSupportedDiagnostics(DiagnosticAnalyzer analyzer) private class ThrowingDoNotCatchDiagnosticAnalyzer : ThrowingDiagnosticAnalyzer, IBuiltInAnalyzer where TLanguageKindEnum : struct { - public bool IsHighPriority => false; + public CodeActionRequestPriority RequestPriority => CodeActionRequestPriority.Normal; public bool OpenFileOnly(OptionSet options) => false; diff --git a/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticAnalyzer.cs b/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticAnalyzer.cs index f0a05e773cfa3..05ef90fdce8c1 100644 --- a/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticAnalyzer.cs +++ b/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticAnalyzer.cs @@ -8,6 +8,7 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Debugging; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.Implementation.EditAndContinue; @@ -29,7 +30,7 @@ public override ImmutableArray SupportedDiagnostics public DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SemanticDocumentAnalysis; - public bool IsHighPriority => false; + public CodeActionRequestPriority RequestPriority => CodeActionRequestPriority.Normal; public bool OpenFileOnly(OptionSet options) => false; diff --git a/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingCodeRefactoringProvider.cs b/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingCodeRefactoringProvider.cs index 612c601979513..41c320fca2083 100644 --- a/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingCodeRefactoringProvider.cs +++ b/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingCodeRefactoringProvider.cs @@ -6,6 +6,7 @@ using System.Composition; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.VisualStudio.Text.Operations; @@ -46,6 +47,7 @@ public override Task ComputeRefactoringsAsync(CodeRefactoringContext context) /// change the name of something and pop up the lightbulb without having to wait for the rest to /// compute. /// - internal override bool IsHighPriority => true; + private protected override CodeActionRequestPriority ComputeRequestPriority() + => CodeActionRequestPriority.High; } } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs index a66fa0cba5a94..c161366b2490d 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs @@ -141,7 +141,7 @@ internal class Analyzer : DiagnosticAnalyzer, IBuiltInAnalyzer private readonly DiagnosticDescriptor _descriptor = new DiagnosticDescriptor("TestId", "Test", "Test", "Test", DiagnosticSeverity.Warning, isEnabledByDefault: true); - public bool IsHighPriority => false; + public CodeActionRequestPriority RequestPriority => CodeActionRequestPriority.Normal; public bool OpenFileOnly(CodeAnalysis.Options.OptionSet options) => false; diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs index b682a13b3c758..fbf2f4d8221aa 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs @@ -10,6 +10,7 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CSharp.RemoveUnnecessarySuppressions; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics.CSharp; @@ -1226,7 +1227,7 @@ public override void Initialize(AnalysisContext context) public DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SyntaxTreeWithoutSemanticsAnalysis; - public bool IsHighPriority => false; + public CodeActionRequestPriority RequestPriority => CodeActionRequestPriority.Normal; public bool OpenFileOnly(CodeAnalysis.Options.OptionSet options) => true; diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs index d7eeeb29e60d5..d08056166d630 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Packaging; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -36,7 +37,8 @@ protected AbstractAddImportCodeFixProvider( /// 'smart tag' feature in VS prior to us even having 'light bulbs'. We want them to be computed /// first, ahead of everything else, and the main results should show up at the top of the list. /// - internal override bool IsHighPriority => true; + private protected override CodeActionRequestPriority ComputeRequestPriority() + => CodeActionRequestPriority.High; public sealed override FixAllProvider GetFixAllProvider() { diff --git a/src/Features/Core/Portable/CodeFixes/CodeFixService.cs b/src/Features/Core/Portable/CodeFixes/CodeFixService.cs index eb08e9868f83c..101d54b009ff5 100644 --- a/src/Features/Core/Portable/CodeFixes/CodeFixService.cs +++ b/src/Features/Core/Portable/CodeFixes/CodeFixService.cs @@ -399,12 +399,8 @@ private async Task AppendFixesAsync( { cancellationToken.ThrowIfCancellationRequested(); - if (priority != CodeActionRequestPriority.None) - { - var highPriority = priority == CodeActionRequestPriority.High; - if (highPriority != fixer.IsHighPriority) - continue; - } + if (priority != CodeActionRequestPriority.None && priority != fixer.RequestPriority) + continue; await AppendFixesOrConfigurationsAsync( document, span, diagnostics, fixAllForInSpan, result, fixer, diff --git a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs index 4adf817061a8b..4fd43ca55d7b3 100644 --- a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs @@ -120,12 +120,8 @@ public async Task> GetRefactoringsAsync( foreach (var provider in GetProviders(document)) { - if (priority != CodeActionRequestPriority.None) - { - var highPriority = priority == CodeActionRequestPriority.High; - if (highPriority != provider.IsHighPriority) - continue; - } + if (priority != CodeActionRequestPriority.None && priority != provider.RequestPriority) + continue; tasks.Add(Task.Run(() => { diff --git a/src/Features/Core/Portable/Diagnostics/Analyzers/UnboundIdentifiersDiagnosticAnalyzerBase.cs b/src/Features/Core/Portable/Diagnostics/Analyzers/UnboundIdentifiersDiagnosticAnalyzerBase.cs index 1fee4480d2cbc..b7bd9e733aa83 100644 --- a/src/Features/Core/Portable/Diagnostics/Analyzers/UnboundIdentifiersDiagnosticAnalyzerBase.cs +++ b/src/Features/Core/Portable/Diagnostics/Analyzers/UnboundIdentifiersDiagnosticAnalyzerBase.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Linq; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Options; using Roslyn.Utilities; @@ -32,7 +33,7 @@ internal abstract class UnboundIdentifiersDiagnosticAnalyzerBase SyntaxKindsOfInterest { get; } protected abstract bool IsNameOf(SyntaxNode node); - public bool IsHighPriority => false; + public CodeActionRequestPriority RequestPriority => CodeActionRequestPriority.Normal; public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptor); diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs index 888d5f13bb44d..d0af6060edb11 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs @@ -249,9 +249,10 @@ private bool MatchesPriority(DiagnosticAnalyzer analyzer) // be high pri fixers that operate entirely off of compiler diagnostics. For example, the // add-using fixer is high pri, and it works off of compiler diagnostics. So we always have // to run that one up front. - var analyzerIsHighPri = analyzer.IsCompilerAnalyzer() || analyzer is IBuiltInAnalyzer { IsHighPriority: true }; - var highPriority = _priority == CodeActionRequestPriority.High; - return analyzerIsHighPri == highPriority; + var analyzerPriority = + analyzer.IsCompilerAnalyzer() ? CodeActionRequestPriority.High : + analyzer is IBuiltInAnalyzer { RequestPriority: var rp } ? rp : CodeActionRequestPriority.Normal; + return _priority == analyzerPriority; } private bool ShouldInclude(DiagnosticData diagnostic) diff --git a/src/Features/Core/Portable/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs b/src/Features/Core/Portable/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs index 6c4c11b3d0f7f..9ee94966b1a4d 100644 --- a/src/Features/Core/Portable/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs +++ b/src/Features/Core/Portable/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs @@ -11,6 +11,7 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Threading; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Options; @@ -81,7 +82,7 @@ protected SimplifyTypeNamesDiagnosticAnalyzerBase() { } - public bool IsHighPriority => false; + public CodeActionRequestPriority RequestPriority => CodeActionRequestPriority.Normal; public bool OpenFileOnly(OptionSet options) { diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpDocumentDiagnosticAnalyzer.cs b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpDocumentDiagnosticAnalyzer.cs index 9319a39230304..a062ed5ed0ef2 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpDocumentDiagnosticAnalyzer.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpDocumentDiagnosticAnalyzer.cs @@ -9,6 +9,7 @@ using System.Composition; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics; using Microsoft.CodeAnalysis.Host; @@ -62,7 +63,7 @@ public static ImmutableArray CreateSupportedDiagnostics() return dummyDescriptors.ToImmutable(); } - public bool IsHighPriority => false; + public CodeActionRequestPriority RequestPriority => CodeActionRequestPriority.Normal; public override int Priority => 10; // Default = 50 diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs index 9bbae91f02987..e0ea3fa75e614 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpSimplifyNameDiagnosticAnalyzer.cs @@ -9,6 +9,7 @@ using System.Composition; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics; using Microsoft.CodeAnalysis.Host; @@ -48,7 +49,7 @@ internal class FSharpSimplifyNameDiagnosticAnalyzer : DocumentDiagnosticAnalyzer public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(_descriptor); - public bool IsHighPriority => false; + public CodeActionRequestPriority RequestPriority => CodeActionRequestPriority.Normal; public override int Priority => 100; // Default = 50 diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs index 84a2cdea3cee2..9b24795e73559 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Diagnostics/FSharpUnusedDeclarationsAnalyzer.cs @@ -9,6 +9,7 @@ using System.Composition; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics; using Microsoft.CodeAnalysis.Host; @@ -50,7 +51,7 @@ internal class FSharpUnusedDeclarationsDiagnosticAnalyzer : DocumentDiagnosticAn public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(_descriptor); - public bool IsHighPriority => false; + public CodeActionRequestPriority RequestPriority => CodeActionRequestPriority.Normal; public override int Priority => 80; // Default = 50 diff --git a/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs b/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs index fe4501b9dfd38..b44b3cdc3bf5e 100644 --- a/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs +++ b/src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs @@ -14,9 +14,9 @@ namespace Microsoft.CodeAnalysis.CodeActions /// /// /// If is used, the feature that specifies that value should - /// implement and return true for , - /// and - /// . This + /// implement and return for , + /// and + /// . This /// will ensure that the analysis engine runs the providers that will produce those actions first, /// thus allowing those actions to be computed and displayed prior to running all other providers. /// diff --git a/src/Workspaces/Core/Portable/CodeFixes/CodeFixProvider.cs b/src/Workspaces/Core/Portable/CodeFixes/CodeFixProvider.cs index 151cb3d7a8eeb..3c3e70d190c13 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/CodeFixProvider.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/CodeFixProvider.cs @@ -4,6 +4,8 @@ using System.Collections.Immutable; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeFixes { @@ -36,9 +38,19 @@ public abstract class CodeFixProvider => null; /// - /// If this is a high-priority code fix provider that should run and display results in a client - /// prior to running the non-high-priority code fix providers. + /// What priority this provider should run at. /// - internal virtual bool IsHighPriority => false; + internal CodeActionRequestPriority RequestPriority + { + get + { + var priority = ComputeRequestPriority(); + Contract.ThrowIfFalse(priority is CodeActionRequestPriority.Normal or CodeActionRequestPriority.High); + return priority; + } + } + + private protected virtual CodeActionRequestPriority ComputeRequestPriority() + => CodeActionRequestPriority.Normal; } } diff --git a/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringProvider.cs b/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringProvider.cs index 2611d44d24419..d2eec59ff6f11 100644 --- a/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringProvider.cs +++ b/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringProvider.cs @@ -3,6 +3,8 @@ // See the LICENSE file in the project root for more information. using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeRefactorings { @@ -18,9 +20,19 @@ public abstract class CodeRefactoringProvider public abstract Task ComputeRefactoringsAsync(CodeRefactoringContext context); /// - /// If this is a high-priority refactoring that should run and display results in a client - /// prior to running the non-high-priority refactorings. + /// What priority this provider should run at. /// - internal virtual bool IsHighPriority => false; + internal CodeActionRequestPriority RequestPriority + { + get + { + var priority = ComputeRequestPriority(); + Contract.ThrowIfFalse(priority is CodeActionRequestPriority.Normal or CodeActionRequestPriority.High); + return priority; + } + } + + private protected virtual CodeActionRequestPriority ComputeRequestPriority() + => CodeActionRequestPriority.Normal; } } diff --git a/src/Workspaces/Core/Portable/CodeActions/CodeActionRequestPriority.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeActions/CodeActionRequestPriority.cs similarity index 70% rename from src/Workspaces/Core/Portable/CodeActions/CodeActionRequestPriority.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeActions/CodeActionRequestPriority.cs index 544a478fcaad4..49ce82b69d797 100644 --- a/src/Workspaces/Core/Portable/CodeActions/CodeActionRequestPriority.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeActions/CodeActionRequestPriority.cs @@ -2,12 +2,11 @@ // 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.CodeFixes; -using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Diagnostics; namespace Microsoft.CodeAnalysis.CodeActions { +#pragma warning disable CA1200 // Avoid using cref tags with a prefix internal enum CodeActionRequestPriority { /// @@ -15,17 +14,18 @@ internal enum CodeActionRequestPriority /// to and combined. /// None = 0, + /// /// Only normal priority refactoring, code fix providers should be run. Specifically, - /// providers will be run when and - /// are . s + /// providers will be run when or + /// is . s /// will be run except for . /// Normal = 1, /// /// Only high priority refactoring, code fix providers should be run. Specifically, - /// providers will be run when or - /// is . + /// providers will be run when or + /// is . /// The /// will be run. /// diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems index faf79cc6b0e29..9b3683215b094 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems @@ -174,6 +174,7 @@ InternalUtilities\UnicodeCharacterUtilities.cs + diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Diagnostics/IBuiltInAnalyzer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Diagnostics/IBuiltInAnalyzer.cs index 49065751dba01..a4b05a9130121 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Diagnostics/IBuiltInAnalyzer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Diagnostics/IBuiltInAnalyzer.cs @@ -2,6 +2,8 @@ // 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.CodeActions; + #if CODE_STYLE using OptionSet = Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptions; #else @@ -34,9 +36,8 @@ internal interface IBuiltInAnalyzer bool OpenFileOnly(OptionSet options); /// - /// If this is a high-priority analyzer that should run and display results in a client - /// prior to running the non-high-priority analyzer. + /// What priority this provider should run at. This value is not allowed to be . /// - bool IsHighPriority { get; } + CodeActionRequestPriority RequestPriority { get; } } } From adfeb29ed87e10ed907ff0b8dbb239281bcb125e Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Sun, 30 May 2021 18:27:45 -0700 Subject: [PATCH 49/53] SImplify --- ...tionSource_ISuggestedActionsSourceExperimental.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs index 607c380d95b94..40d10a6b0f61e 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs @@ -39,7 +39,8 @@ public async IAsyncEnumerable GetSuggestedActionsAsync( if (workspace is null) yield break; - await workspace.Services.GetRequiredService().WaitUntilFullyLoadedAsync(cancellationToken).ConfigureAwait(true); + var selection = TryGetCodeRefactoringSelection(state, range); + await workspace.Services.GetRequiredService().WaitUntilFullyLoadedAsync(cancellationToken).ConfigureAwait(false); using (Logger.LogBlock(FunctionId.SuggestedActions_GetSuggestedActionsAsync, cancellationToken)) { @@ -50,12 +51,14 @@ public async IAsyncEnumerable GetSuggestedActionsAsync( // Compute and return the high pri set of fixes and refactorings first so the user // can act on them immediately without waiting on the regular set. var highPriSet = GetCodeFixesAndRefactoringsAsync( - state, requestedActionCategories, document, range, _ => null, CodeActionRequestPriority.High, cancellationToken); + state, requestedActionCategories, document, range, selection, _ => null, + CodeActionRequestPriority.High, cancellationToken).WithCancellation(cancellationToken).ConfigureAwait(false); await foreach (var set in highPriSet) yield return set; var lowPriSet = GetCodeFixesAndRefactoringsAsync( - state, requestedActionCategories, document, range, _ => null, CodeActionRequestPriority.Normal, cancellationToken); + state, requestedActionCategories, document, range, selection, _ => null, + CodeActionRequestPriority.Normal, cancellationToken).WithCancellation(cancellationToken).ConfigureAwait(false); await foreach (var set in lowPriSet) yield return set; } @@ -66,6 +69,7 @@ private async IAsyncEnumerable GetCodeFixesAndRefactoringsAs ISuggestedActionCategorySet requestedActionCategories, Document document, SnapshotSpan range, + TextSpan? selection, Func addOperationScope, CodeActionRequestPriority priority, [EnumeratorCancellation] CancellationToken cancellationToken) @@ -73,8 +77,6 @@ private async IAsyncEnumerable GetCodeFixesAndRefactoringsAs var workspace = document.Project.Solution.Workspace; var supportsFeatureService = workspace.Services.GetRequiredService(); - var selection = TryGetCodeRefactoringSelection(state, range); - var fixesTask = GetCodeFixesAsync( state, supportsFeatureService, requestedActionCategories, workspace, document, range, addOperationScope, priority, isBlocking: false, cancellationToken); From 2afda3ca8fc849ab4349d226dd7c440c87da7d5c Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Sun, 30 May 2021 18:29:03 -0700 Subject: [PATCH 50/53] Comments --- .../Core.Wpf/Suggestions/SuggestedActionsSource.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 2654f13e68970..29bd0d05ef0eb 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -343,7 +343,7 @@ public Task HasSuggestedActionsAsync( $"Invalid text buffer passed to {nameof(HasSuggestedActionsAsync)}"); // Next, before we do any async work, acquire the user's selection, directly grabbing - // it from the UI thread if htat's what we're on. That way we don't have any reentrancy + // it from the UI thread if that's what we're on. That way we don't have any reentrancy // blocking concerns if VS wants to block on this call (for example, if the user // explicitly invokes the 'show smart tag' command). // @@ -353,18 +353,18 @@ public Task HasSuggestedActionsAsync( // Note: we may be called in one of two VS scenarios: // 1) User has moved caret to a new line. In this case VS will call into us in the // bg to see if we have any suggested actions for this line. In order to figure - // this out, we need to see what selectoin the user has (for refactorings), which + // this out, we need to see what selection the user has (for refactorings), which // necessitates going back to the fg. // // 2) User moves to a line and immediately hits ctrl-dot. In this case, on the UI // thread VS will kick us off and then immediately block to get the results so - // that they can expand the lightbulb. In this case we cannot do BG work first, + // that they can expand the light-bulb. In this case we cannot do BG work first, // then call back into the UI thread to try to get the user selection. This will // deadlock as the UI thread is blocked on us. // // There are two solution to '2'. Either introduce reentrancy (which we really don't // like to do), or just ensure that we acquire and get the users selection up front. - // This means that when we're called from the UI therad, we never try to go back to the + // This means that when we're called from the UI thread, we never try to go back to the // UI thread. TextSpan? selection = null; if (IsForeground()) @@ -539,7 +539,7 @@ private void OnWorkspaceStatusChanged(object sender, EventArgs args) return; } - // ask editor to refresh lightbulb when workspace solution status is changed + // ask editor to refresh light-bulb when workspace solution status is changed this.SuggestedActionsChanged?.Invoke(this, EventArgs.Empty); } From ffe832e456f296d631ae75dc96595190c2448c73 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 28 Jun 2021 16:24:24 -0700 Subject: [PATCH 51/53] Add option --- ...ntal.cs => AsyncSuggestedActionsSource.cs} | 16 +++++++-- .../SuggestedActionsSource.State.cs | 2 +- .../Suggestions/SuggestedActionsSource.cs | 14 ++++---- .../SuggestedActionsSourceProvider.cs | 16 ++++++--- .../Suggestions/SuggestionsOptions.cs | 15 ++++++++ .../Suggestions/SuggestionsOptionsProvider.cs | 26 ++++++++++++++ .../Suggestions/SyncSuggestedActionsSource.cs | 27 +++++++++++++++ .../Options/AdvancedOptionPageControl.xaml | 7 ++++ .../Options/AdvancedOptionPageControl.xaml.cs | 7 ++++ .../Impl/Options/AdvancedOptionPageStrings.cs | 18 +++++----- .../Core/Def/ServicesVSResources.resx | 6 ++++ .../Core/Def/xlf/ServicesVSResources.cs.xlf | 10 ++++++ .../Core/Def/xlf/ServicesVSResources.de.xlf | 10 ++++++ .../Core/Def/xlf/ServicesVSResources.es.xlf | 10 ++++++ .../Core/Def/xlf/ServicesVSResources.fr.xlf | 10 ++++++ .../Core/Def/xlf/ServicesVSResources.it.xlf | 10 ++++++ .../Core/Def/xlf/ServicesVSResources.ja.xlf | 10 ++++++ .../Core/Def/xlf/ServicesVSResources.ko.xlf | 10 ++++++ .../Core/Def/xlf/ServicesVSResources.pl.xlf | 10 ++++++ .../Def/xlf/ServicesVSResources.pt-BR.xlf | 10 ++++++ .../Core/Def/xlf/ServicesVSResources.ru.xlf | 10 ++++++ .../Core/Def/xlf/ServicesVSResources.tr.xlf | 10 ++++++ .../Def/xlf/ServicesVSResources.zh-Hans.xlf | 10 ++++++ .../Def/xlf/ServicesVSResources.zh-Hant.xlf | 10 ++++++ .../Options/AdvancedOptionPageControl.xaml | 7 ++++ .../Options/AdvancedOptionPageControl.xaml.vb | 4 +++ .../Impl/Options/AdvancedOptionPageStrings.vb | 34 ++++++++----------- .../Experiments/IExperimentationService.cs | 1 + 28 files changed, 287 insertions(+), 43 deletions(-) rename src/EditorFeatures/Core.Wpf/Suggestions/{SuggestedActionSource_ISuggestedActionsSourceExperimental.cs => AsyncSuggestedActionsSource.cs} (89%) create mode 100644 src/EditorFeatures/Core.Wpf/Suggestions/SuggestionsOptions.cs create mode 100644 src/EditorFeatures/Core.Wpf/Suggestions/SuggestionsOptionsProvider.cs create mode 100644 src/EditorFeatures/Core.Wpf/Suggestions/SyncSuggestedActionsSource.cs diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs b/src/EditorFeatures/Core.Wpf/Suggestions/AsyncSuggestedActionsSource.cs similarity index 89% rename from src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs rename to src/EditorFeatures/Core.Wpf/Suggestions/AsyncSuggestedActionsSource.cs index 40d10a6b0f61e..5579d7dc7b1e4 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_ISuggestedActionsSourceExperimental.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/AsyncSuggestedActionsSource.cs @@ -10,20 +10,32 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Editor.Shared; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.UnifiedSuggestions; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions { internal partial class SuggestedActionsSourceProvider { - private partial class SuggestedActionsSource : ISuggestedActionsSourceExperimental + private partial class AsyncSuggestedActionsSource : SuggestedActionsSource, ISuggestedActionsSourceExperimental { + public AsyncSuggestedActionsSource( + IThreadingContext threadingContext, + SuggestedActionsSourceProvider owner, + ITextView textView, + ITextBuffer textBuffer, + ISuggestedActionCategoryRegistryService suggestedActionCategoryRegistry) + : base(threadingContext, owner, textView, textBuffer, suggestedActionCategoryRegistry) + { + } + public async IAsyncEnumerable GetSuggestedActionsAsync( ISuggestedActionCategorySet requestedActionCategories, SnapshotSpan range, @@ -31,7 +43,7 @@ public async IAsyncEnumerable GetSuggestedActionsAsync( { AssertIsForeground(); - using var state = _state.TryAddReference(); + using var state = SourceState.TryAddReference(); if (state is null) yield break; diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.State.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.State.cs index d8b85311b3a18..ca384975401e6 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.State.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.State.cs @@ -15,7 +15,7 @@ internal partial class SuggestedActionsSourceProvider { private partial class SuggestedActionsSource { - private sealed class State : IDisposable + protected sealed class State : IDisposable { private readonly SuggestedActionsSource _source; diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 29bd0d05ef0eb..5e3819699d012 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -33,7 +33,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions { internal partial class SuggestedActionsSourceProvider { - private partial class SuggestedActionsSource : ForegroundThreadAffinitizedObject, ISuggestedActionsSource3 + private abstract partial class SuggestedActionsSource : ForegroundThreadAffinitizedObject, ISuggestedActionsSource3 { private readonly ISuggestedActionCategoryRegistryService _suggestedActionCategoryRegistry; @@ -41,7 +41,7 @@ private partial class SuggestedActionsSource : ForegroundThreadAffinitizedObject public event EventHandler? SuggestedActionsChanged; - public SuggestedActionsSource( + protected SuggestedActionsSource( IThreadingContext threadingContext, SuggestedActionsSourceProvider owner, ITextView textView, @@ -67,6 +67,8 @@ public void Dispose() _state.Dispose(); } + protected ReferenceCountedDisposable SourceState => _state; + public bool TryGetTelemetryId(out Guid telemetryId) { telemetryId = default; @@ -182,7 +184,7 @@ public bool TryGetTelemetryId(out Guid telemetryId) } } - private IEnumerable ConvertToSuggestedActionSets(ReferenceCountedDisposable state, TextSpan? selection, ImmutableArray fixes, ImmutableArray refactorings) + protected IEnumerable ConvertToSuggestedActionSets(ReferenceCountedDisposable state, TextSpan? selection, ImmutableArray fixes, ImmutableArray refactorings) { var filteredSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets(fixes, refactorings, selection); return filteredSets.SelectAsArray(s => ConvertToSuggestedActionSet(s, state.Target.Owner, state.Target.SubjectBuffer)).WhereNotNull(); @@ -242,7 +244,7 @@ static SuggestedActionSetPriority ConvertToSuggestedActionSetPriority(UnifiedSug }; } - private static Task> GetCodeFixesAsync( + protected static Task> GetCodeFixesAsync( ReferenceCountedDisposable state, ITextBufferSupportsFeatureService supportsFeatureService, ISuggestedActionCategorySet requestedActionCategories, @@ -281,7 +283,7 @@ private static string GetFixCategory(DiagnosticSeverity severity) } } - private static Task> GetRefactoringsAsync( + protected static Task> GetRefactoringsAsync( ReferenceCountedDisposable state, ITextBufferSupportsFeatureService supportsFeatureService, ISuggestedActionCategorySet requestedActionCategories, @@ -446,7 +448,7 @@ await InvokeBelowInputPriorityAsync(() => return null; } - private TextSpan? TryGetCodeRefactoringSelection(ReferenceCountedDisposable state, SnapshotSpan range) + protected TextSpan? TryGetCodeRefactoringSelection(ReferenceCountedDisposable state, SnapshotSpan range) { this.AssertIsForeground(); diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs index 01c0a2bbe9517..76aa7718c63ee 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs @@ -9,11 +9,12 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.Tags; +using Microsoft.CodeAnalysis.Experiments; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.VisualStudio.Language.Intellisense; @@ -43,7 +44,8 @@ internal partial class SuggestedActionsSourceProvider : ISuggestedActionsSourceP private readonly IDiagnosticAnalyzerService _diagnosticService; private readonly ICodeFixService _codeFixService; private readonly ISuggestedActionCategoryRegistryService _suggestedActionCategoryRegistry; - + private readonly IGlobalOptionService _optionService; + private readonly IExperimentationService _experimentationService; public readonly ICodeActionEditHandlerService EditHandler; public readonly IAsynchronousOperationListener OperationListener; public readonly IUIThreadOperationExecutor UIThreadOperationExecutor; @@ -62,6 +64,8 @@ public SuggestedActionsSourceProvider( IUIThreadOperationExecutor uiThreadOperationExecutor, ISuggestedActionCategoryRegistryService suggestedActionCategoryRegistry, IAsynchronousOperationListenerProvider listenerProvider, + IGlobalOptionService optionService, + IExperimentationService experimentationService, [ImportMany] IEnumerable> imageIdServices, [ImportMany] IEnumerable> actionCallbacks) { @@ -70,6 +74,8 @@ public SuggestedActionsSourceProvider( _diagnosticService = diagnosticService; _codeFixService = codeFixService; _suggestedActionCategoryRegistry = suggestedActionCategoryRegistry; + _optionService = optionService; + _experimentationService = experimentationService; ActionCallbacks = actionCallbacks.ToImmutableArray(); EditHandler = editHandler; UIThreadOperationExecutor = uiThreadOperationExecutor; @@ -86,11 +92,11 @@ public SuggestedActionsSourceProvider( // Disable lightbulb points when running under the LSP editor. // The LSP client will interface with the editor to display our code actions. if (textBuffer.IsInLspEditorContext()) - { return null; - } - return new SuggestedActionsSource(_threadingContext, this, textView, textBuffer, _suggestedActionCategoryRegistry); + return _optionService.GetOption(SuggestionsOptions.Asynchronous) || _experimentationService.IsExperimentEnabled(WellKnownExperimentNames.AsynchronousQuickActions) + ? new AsyncSuggestedActionsSource(_threadingContext, this, textView, textBuffer, _suggestedActionCategoryRegistry) + : new SyncSuggestedActionsSource(_threadingContext, this, textView, textBuffer, _suggestedActionCategoryRegistry); } } } diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestionsOptions.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestionsOptions.cs new file mode 100644 index 0000000000000..6d779cc836bea --- /dev/null +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestionsOptions.cs @@ -0,0 +1,15 @@ +// 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.Editor.Implementation.Suggestions +{ + internal class SuggestionsOptions + { + public static Option2 Asynchronous = + new Option2(nameof(SuggestionsOptions), nameof(Asynchronous), defaultValue: true, + storageLocations: new RoamingProfileStorageLocation("TextEditor.Specific.Suggestions.Asynchronous")); + } +} diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestionsOptionsProvider.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestionsOptionsProvider.cs new file mode 100644 index 0000000000000..1b798c6841806 --- /dev/null +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestionsOptionsProvider.cs @@ -0,0 +1,26 @@ +// 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.Composition; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Options.Providers; + +namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions +{ + [ExportOptionProvider, Shared] + internal class SuggestionsOptionsProvider : IOptionProvider + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public SuggestionsOptionsProvider() + { + } + + public ImmutableArray Options { get; } = ImmutableArray.Create( + SuggestionsOptions.Asynchronous); + } +} diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SyncSuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SyncSuggestedActionsSource.cs new file mode 100644 index 0000000000000..7c921d975b623 --- /dev/null +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SyncSuggestedActionsSource.cs @@ -0,0 +1,27 @@ +// 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.Editor.Shared.Utilities; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; + +namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions +{ + internal partial class SuggestedActionsSourceProvider + { + private partial class SyncSuggestedActionsSource : SuggestedActionsSource + { + public SyncSuggestedActionsSource( + IThreadingContext threadingContext, + SuggestedActionsSourceProvider owner, + ITextView textView, + ITextBuffer textBuffer, + ISuggestedActionCategoryRegistryService suggestedActionCategoryRegistry) + : base(threadingContext, owner, textView, textBuffer, suggestedActionCategoryRegistry) + { + } + } + } +} diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml index da1a53ea12d4c..f664e30dea17f 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml @@ -75,6 +75,13 @@ Content="{x:Static local:AdvancedOptionPageStrings.Option_Add_missing_using_directives_on_paste}" /> + + + + + diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs index 03a08ffbe17c0..9bc8e60167cae 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.DocumentationComments; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Editor.CSharp.SplitStringLiteral; +using Microsoft.CodeAnalysis.Editor.Implementation.Suggestions; using Microsoft.CodeAnalysis.Editor.Options; using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions; @@ -87,8 +88,14 @@ public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel compon BindToOption(ShowRemarksInQuickInfo, QuickInfoOptions.ShowRemarksInQuickInfo, LanguageNames.CSharp); BindToOption(DisplayLineSeparators, FeatureOnOffOptions.LineSeparator, LanguageNames.CSharp); + + // Quick Actions + BindToOption(ComputeQuickActionsAsynchronouslyExperimental, SuggestionsOptions.Asynchronous); + + // Highlighting BindToOption(EnableHighlightReferences, FeatureOnOffOptions.ReferenceHighlighting, LanguageNames.CSharp); BindToOption(EnableHighlightKeywords, FeatureOnOffOptions.KeywordHighlighting, LanguageNames.CSharp); + BindToOption(RenameTrackingPreview, FeatureOnOffOptions.RenameTrackingPreview, LanguageNames.CSharp); BindToOption(Underline_reassigned_variables, ClassificationOptions.ClassifyReassignedVariables, LanguageNames.CSharp); BindToOption(Enable_all_features_in_opened_files_from_source_generators, SourceGeneratedFileManager.EnableOpeningInWorkspace, () => diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs index 9ddfff6204ba3..bc76d580e5b62 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs @@ -154,19 +154,19 @@ public static string Option_OptimizeForSolutionSize } public static string Option_OptimizeForSolutionSize_Large - { - get { return CSharpVSResources.Large; } - } + => CSharpVSResources.Large; public static string Option_OptimizeForSolutionSize_Regular - { - get { return CSharpVSResources.Regular; } - } + => CSharpVSResources.Regular; public static string Option_OptimizeForSolutionSize_Small - { - get { return CSharpVSResources.Small; } - } + => CSharpVSResources.Small; + + public static string Option_Quick_Actions + => ServicesVSResources.Quick_Actions; + + public static string Option_Compute_Quick_Actions_asynchronously_experimental + => ServicesVSResources.Compute_Quick_Actions_asynchronously_experimental; public static string Option_Outlining => ServicesVSResources.Outlining; diff --git a/src/VisualStudio/Core/Def/ServicesVSResources.resx b/src/VisualStudio/Core/Def/ServicesVSResources.resx index 3d580778f0fdb..9f30a46337254 100644 --- a/src/VisualStudio/Core/Def/ServicesVSResources.resx +++ b/src/VisualStudio/Core/Def/ServicesVSResources.resx @@ -1770,4 +1770,10 @@ I agree to all of the foregoing: Underline reassigned variables + + Compute Quick Actions asynchronously (experimental) + + + Quick Actions + \ No newline at end of file diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf index bec647e280b15..fa70f4de0d97d 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf @@ -227,6 +227,11 @@ Komentáře + + Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental) + + Containing Member Obsahující člen @@ -892,6 +897,11 @@ Stáhnout členy + + Quick Actions + Quick Actions + + Refactoring Only Pouze refaktoring diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf index f5448ed33036b..60b91a1026d19 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf @@ -227,6 +227,11 @@ Kommentare + + Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental) + + Containing Member Enthaltender Member @@ -892,6 +897,11 @@ Member nach oben ziehen + + Quick Actions + Quick Actions + + Refactoring Only Nur Refactoring diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf index 0763bf9e591c7..7f606923372ab 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf @@ -227,6 +227,11 @@ Comentarios + + Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental) + + Containing Member Miembro contenedor @@ -892,6 +897,11 @@ Extraer miembros + + Quick Actions + Quick Actions + + Refactoring Only Solo refactorización diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf index 294f52b82382b..431ce4413af74 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf @@ -227,6 +227,11 @@ Commentaires + + Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental) + + Containing Member Membre conteneur @@ -892,6 +897,11 @@ Élever les membres + + Quick Actions + Quick Actions + + Refactoring Only Refactoring Only diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf index a6dc06e5caf1b..c20a4f118e518 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf @@ -227,6 +227,11 @@ Commenti + + Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental) + + Containing Member Membro contenitore @@ -892,6 +897,11 @@ Recupera membri + + Quick Actions + Quick Actions + + Refactoring Only Refactoring Only diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf index b08b6c2f1c833..22deb8570ecbd 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf @@ -227,6 +227,11 @@ コメント + + Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental) + + Containing Member 含んでいるメンバー @@ -892,6 +897,11 @@ メンバーをプルアップ + + Quick Actions + Quick Actions + + Refactoring Only リファクタリングのみ diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf index 784d0781c9ad8..6f85cdbd9ea8d 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf @@ -227,6 +227,11 @@ 설명 + + Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental) + + Containing Member 포함하는 멤버 @@ -892,6 +897,11 @@ 멤버 풀하기 + + Quick Actions + Quick Actions + + Refactoring Only 리팩터링만 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf index 7c7044529edc5..420d60db61083 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf @@ -227,6 +227,11 @@ Komentarze + + Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental) + + Containing Member Zawierająca składowa @@ -892,6 +897,11 @@ Podciągnij składowe w górę + + Quick Actions + Quick Actions + + Refactoring Only Tylko refaktoryzacja diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf index 3163beb18b718..50c866b8d9b2c 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf @@ -227,6 +227,11 @@ Comentários + + Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental) + + Containing Member Contendo Membro @@ -892,6 +897,11 @@ Levantar os membros + + Quick Actions + Quick Actions + + Refactoring Only Somente Refatoração diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf index c81769332f8db..72276f1cd5a50 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf @@ -227,6 +227,11 @@ Комментарии + + Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental) + + Containing Member Содержащий член @@ -892,6 +897,11 @@ Повышение элементов + + Quick Actions + Quick Actions + + Refactoring Only Только рефакторинг diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf index 3c04d08f134f8..bce04b640ec53 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf @@ -227,6 +227,11 @@ Açıklamalar + + Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental) + + Containing Member Kapsayan Üye @@ -892,6 +897,11 @@ Üyeleri Yukarı Çek + + Quick Actions + Quick Actions + + Refactoring Only Sadece Yeniden Düzenlenme diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf index 80109f410c244..f1790e56bdf08 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf @@ -227,6 +227,11 @@ 备注 + + Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental) + + Containing Member 包含成员 @@ -892,6 +897,11 @@ 拉取成员 + + Quick Actions + Quick Actions + + Refactoring Only 仅重构 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf index 81831aab2da1e..61c5469036ab4 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf @@ -227,6 +227,11 @@ 註解 + + Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental) + + Containing Member 包含的成員 @@ -892,6 +897,11 @@ 提升成員 + + Quick Actions + Quick Actions + + Refactoring Only 僅重構 diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml index 4d6d131fb3d37..6b01936c9c1ed 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml +++ b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml @@ -59,6 +59,13 @@ Content="{x:Static local:AdvancedOptionPageStrings.Option_Add_missing_imports_on_paste}" /> + + + + + diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb index 66fcb6d69b248..97af9b417a955 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb @@ -9,6 +9,7 @@ Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.DocumentationComments Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Editor.Implementation.SplitComment +Imports Microsoft.CodeAnalysis.Editor.Implementation.Suggestions Imports Microsoft.CodeAnalysis.Editor.Options Imports Microsoft.CodeAnalysis.Editor.Shared.Options Imports Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions @@ -75,6 +76,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options Return experimentationService.IsExperimentEnabled(WellKnownExperimentNames.ImportsOnPasteDefaultEnabled) End Function) + ' Quick Actions + BindToOption(ComputeQuickActionsAsynchronouslyExperimental, SuggestionsOptions.Asynchronous) + ' Highlighting BindToOption(EnableHighlightReferences, FeatureOnOffOptions.ReferenceHighlighting, LanguageNames.VisualBasic) BindToOption(EnableHighlightKeywords, FeatureOnOffOptions.KeywordHighlighting, LanguageNames.VisualBasic) diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageStrings.vb b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageStrings.vb index 2828919a0b441..f74b1ac706fc5 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageStrings.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageStrings.vb @@ -66,29 +66,23 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options Public ReadOnly Property Option_DontPutOutOrRefOnStruct As String = BasicVSResources.Don_t_put_ByRef_on_custom_structure - Public ReadOnly Property Option_EditorHelp As String - Get - Return BasicVSResources.Editor_Help - End Get - End Property + Public ReadOnly Property Option_EditorHelp As String = + BasicVSResources.Editor_Help - Public ReadOnly Property Option_EnableEndConstruct As String - Get - Return BasicVSResources.A_utomatic_insertion_of_end_constructs - End Get - End Property + Public ReadOnly Property Option_EnableEndConstruct As String = + BasicVSResources.A_utomatic_insertion_of_end_constructs - Public ReadOnly Property Option_EnableHighlightKeywords As String - Get - Return BasicVSResources.Highlight_related_keywords_under_cursor - End Get - End Property + Public ReadOnly Property Option_EnableHighlightKeywords As String = + BasicVSResources.Highlight_related_keywords_under_cursor - Public ReadOnly Property Option_EnableHighlightReferences As String - Get - Return BasicVSResources.Highlight_references_to_symbol_under_cursor - End Get - End Property + Public ReadOnly Property Option_EnableHighlightReferences As String = + BasicVSResources.Highlight_references_to_symbol_under_cursor + + Public ReadOnly Property Option_Quick_Actions As String = + ServicesVSResources.Quick_Actions + + Public ReadOnly Property Option_Compute_Quick_Actions_asynchronously_experimental As String = + ServicesVSResources.Compute_Quick_Actions_asynchronously_experimental Public ReadOnly Property Option_EnableLineCommit As String Get diff --git a/src/Workspaces/Core/Portable/Experiments/IExperimentationService.cs b/src/Workspaces/Core/Portable/Experiments/IExperimentationService.cs index 2453404b37f20..b99c0fdfc4692 100644 --- a/src/Workspaces/Core/Portable/Experiments/IExperimentationService.cs +++ b/src/Workspaces/Core/Portable/Experiments/IExperimentationService.cs @@ -42,5 +42,6 @@ internal static class WellKnownExperimentNames public const string UnnamedSymbolCompletionDisabled = "Roslyn.UnnamedSymbolCompletionDisabled"; public const string RazorLspEditorFeatureFlag = "Razor.LSP.Editor"; public const string LspPullDiagnosticsFeatureFlag = "Lsp.PullDiagnostics"; + public const string AsynchronousQuickActions = "Roslyn.AsynchronousQuickActions"; } } From 75b96cb7919834b88211cc349091748345db2e17 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 28 Jun 2021 16:37:51 -0700 Subject: [PATCH 52/53] Update version --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index 620f9b70cb292..ee36764de5697 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -32,7 +32,7 @@ 1.1.0-beta1.21322.2 3.10.0 16.10.230 - 17.0.77-preview-g95aaee7977 + 17.0.83-preview 5.0.0-alpha1.19409.1 5.0.0-preview.1.20112.8 17.0.20-g6553c6c46e From d3a74c33bfbde033727c3ba5652b88db74f8e905 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 28 Jun 2021 16:57:24 -0700 Subject: [PATCH 53/53] Rename string --- .../Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs | 5 +---- src/VisualStudio/Core/Def/ServicesVSResources.resx | 2 +- src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf | 4 ++-- .../Core/Def/xlf/ServicesVSResources.zh-Hans.xlf | 4 ++-- .../Core/Def/xlf/ServicesVSResources.zh-Hant.xlf | 4 ++-- 15 files changed, 28 insertions(+), 31 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs index 76aa7718c63ee..5573014014982 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs @@ -45,7 +45,6 @@ internal partial class SuggestedActionsSourceProvider : ISuggestedActionsSourceP private readonly ICodeFixService _codeFixService; private readonly ISuggestedActionCategoryRegistryService _suggestedActionCategoryRegistry; private readonly IGlobalOptionService _optionService; - private readonly IExperimentationService _experimentationService; public readonly ICodeActionEditHandlerService EditHandler; public readonly IAsynchronousOperationListener OperationListener; public readonly IUIThreadOperationExecutor UIThreadOperationExecutor; @@ -65,7 +64,6 @@ public SuggestedActionsSourceProvider( ISuggestedActionCategoryRegistryService suggestedActionCategoryRegistry, IAsynchronousOperationListenerProvider listenerProvider, IGlobalOptionService optionService, - IExperimentationService experimentationService, [ImportMany] IEnumerable> imageIdServices, [ImportMany] IEnumerable> actionCallbacks) { @@ -75,7 +73,6 @@ public SuggestedActionsSourceProvider( _codeFixService = codeFixService; _suggestedActionCategoryRegistry = suggestedActionCategoryRegistry; _optionService = optionService; - _experimentationService = experimentationService; ActionCallbacks = actionCallbacks.ToImmutableArray(); EditHandler = editHandler; UIThreadOperationExecutor = uiThreadOperationExecutor; @@ -94,7 +91,7 @@ public SuggestedActionsSourceProvider( if (textBuffer.IsInLspEditorContext()) return null; - return _optionService.GetOption(SuggestionsOptions.Asynchronous) || _experimentationService.IsExperimentEnabled(WellKnownExperimentNames.AsynchronousQuickActions) + return _optionService.GetOption(SuggestionsOptions.Asynchronous) ? new AsyncSuggestedActionsSource(_threadingContext, this, textView, textBuffer, _suggestedActionCategoryRegistry) : new SyncSuggestedActionsSource(_threadingContext, this, textView, textBuffer, _suggestedActionCategoryRegistry); } diff --git a/src/VisualStudio/Core/Def/ServicesVSResources.resx b/src/VisualStudio/Core/Def/ServicesVSResources.resx index 9f30a46337254..cd283d068e90a 100644 --- a/src/VisualStudio/Core/Def/ServicesVSResources.resx +++ b/src/VisualStudio/Core/Def/ServicesVSResources.resx @@ -1771,7 +1771,7 @@ I agree to all of the foregoing: Underline reassigned variables - Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental, requires restart) Quick Actions diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf index fa70f4de0d97d..e649604126ede 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf @@ -228,8 +228,8 @@ - Compute Quick Actions asynchronously (experimental) - Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental, requires restart) + Compute Quick Actions asynchronously (experimental, requires restart) diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf index 60b91a1026d19..699a25f9b3957 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf @@ -228,8 +228,8 @@ - Compute Quick Actions asynchronously (experimental) - Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental, requires restart) + Compute Quick Actions asynchronously (experimental, requires restart) diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf index 7f606923372ab..9cf54c951a721 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf @@ -228,8 +228,8 @@ - Compute Quick Actions asynchronously (experimental) - Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental, requires restart) + Compute Quick Actions asynchronously (experimental, requires restart) diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf index 431ce4413af74..d3f8c63fc315f 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf @@ -228,8 +228,8 @@ - Compute Quick Actions asynchronously (experimental) - Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental, requires restart) + Compute Quick Actions asynchronously (experimental, requires restart) diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf index c20a4f118e518..7f7cb795c4071 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf @@ -228,8 +228,8 @@ - Compute Quick Actions asynchronously (experimental) - Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental, requires restart) + Compute Quick Actions asynchronously (experimental, requires restart) diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf index 22deb8570ecbd..07f7d48f3f396 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf @@ -228,8 +228,8 @@ - Compute Quick Actions asynchronously (experimental) - Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental, requires restart) + Compute Quick Actions asynchronously (experimental, requires restart) diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf index 6f85cdbd9ea8d..5e7d87fd1232c 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf @@ -228,8 +228,8 @@ - Compute Quick Actions asynchronously (experimental) - Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental, requires restart) + Compute Quick Actions asynchronously (experimental, requires restart) diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf index 420d60db61083..750876e195609 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf @@ -228,8 +228,8 @@ - Compute Quick Actions asynchronously (experimental) - Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental, requires restart) + Compute Quick Actions asynchronously (experimental, requires restart) diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf index 50c866b8d9b2c..ad2dbde045ac1 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf @@ -228,8 +228,8 @@ - Compute Quick Actions asynchronously (experimental) - Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental, requires restart) + Compute Quick Actions asynchronously (experimental, requires restart) diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf index 72276f1cd5a50..c6190ad1f35d7 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf @@ -228,8 +228,8 @@ - Compute Quick Actions asynchronously (experimental) - Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental, requires restart) + Compute Quick Actions asynchronously (experimental, requires restart) diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf index bce04b640ec53..d1b058e056d4c 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf @@ -228,8 +228,8 @@ - Compute Quick Actions asynchronously (experimental) - Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental, requires restart) + Compute Quick Actions asynchronously (experimental, requires restart) diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf index f1790e56bdf08..b9e7b58c8e775 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf @@ -228,8 +228,8 @@ - Compute Quick Actions asynchronously (experimental) - Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental, requires restart) + Compute Quick Actions asynchronously (experimental, requires restart) diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf index 61c5469036ab4..e914f8522b24a 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf @@ -228,8 +228,8 @@ - Compute Quick Actions asynchronously (experimental) - Compute Quick Actions asynchronously (experimental) + Compute Quick Actions asynchronously (experimental, requires restart) + Compute Quick Actions asynchronously (experimental, requires restart)