From 4d443fe9a91ca386f7e77ba19678f90f0585f94f Mon Sep 17 00:00:00 2001 From: tmat Date: Sun, 9 Jan 2022 20:51:25 -0800 Subject: [PATCH] CodeActionOptions --- .../Suppression/SuppressionTests.cs | 3 +- .../CSharpTest/Formatting/CodeCleanupTests.cs | 5 ++- .../AsyncSuggestedActionsSource.cs | 6 ++- .../Suggestions/SuggestedActionsSource.cs | 22 ++++++---- .../CodeActions/CodeActionOptionsFactory.cs | 22 ++++++++++ .../Handlers/CodeActions/CodeActionHelpers.cs | 5 ++- .../CodeActions/AbstractCodeActionTest.cs | 3 +- .../Test/CodeFixes/CodeFixServiceTests.cs | 24 +++++++--- .../CodeRefactoringServiceTest.cs | 6 ++- .../Test2/CodeFixes/CodeFixServiceTests.vb | 44 +++++++++++++------ .../Formatting/CodeCleanUpTests.vb | 13 ++++-- .../AbstractAddImportCodeFixProvider.cs | 4 +- .../CodeCleanup/AbstractCodeCleanupService.cs | 13 +++--- .../CodeCleanup/ICodeCleanupService.cs | 3 +- .../Core/Portable/CodeFixes/CodeFixService.cs | 22 +++++----- .../Portable/CodeFixes/ICodeFixService.cs | 13 +++--- ...actAddMissingImportsRefactoringProvider.cs | 3 +- .../CodeRefactoringService.cs | 13 +++--- .../ICodeRefactoringService.cs | 11 ++--- .../UnifiedSuggestedActionsSource.cs | 8 ++-- .../CodeCleanup/AbstractCodeCleanUpFixer.cs | 20 ++++++--- .../Portable/CodeActions/CodeActionOptions.cs | 21 +++++++++ .../Core/Portable/CodeFixes/CodeFixContext.cs | 12 ++--- .../CodeRefactoringContext.cs | 12 ++--- 24 files changed, 201 insertions(+), 107 deletions(-) create mode 100644 src/EditorFeatures/Core/Implementation/CodeActions/CodeActionOptionsFactory.cs create mode 100644 src/Workspaces/Core/Portable/CodeActions/CodeActionOptions.cs diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs index b4a447b71d4d5..2e7fffcbd1bda 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs @@ -467,7 +467,8 @@ void Method() var diagnostics = await diagnosticService.GetDiagnosticsForSpanAsync(document, span); Assert.Equal(2, diagnostics.Where(d => d.Id == "CS0219").Count()); - var allFixes = (await fixService.GetFixesAsync(document, span, cancellationToken: CancellationToken.None)) + var options = CodeActionOptions.Default; + var allFixes = (await fixService.GetFixesAsync(document, span, options, CancellationToken.None)) .SelectMany(fixCollection => fixCollection.Fixes); var cs0219Fixes = allFixes.Where(fix => fix.PrimaryDiagnostic.Id == "CS0219").ToArray(); diff --git a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs index 0d1219d77024b..7be9e54d76ab4 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; @@ -561,6 +562,8 @@ private protected static async Task AssertCodeCleanupResult(string expected, str { using var workspace = TestWorkspace.CreateCSharp(code, composition: EditorTestCompositions.EditorFeaturesWpf); + var options = CodeActionOptions.Default; + var solution = workspace.CurrentSolution .WithOptions(workspace.Options .WithChangedOption(GenerationOptions.PlaceSystemNamespaceFirst, LanguageNames.CSharp, systemUsingsFirst) @@ -586,7 +589,7 @@ private protected static async Task AssertCodeCleanupResult(string expected, str var enabledDiagnostics = codeCleanupService.GetAllDiagnostics(); var newDoc = await codeCleanupService.CleanupAsync( - document, enabledDiagnostics, new ProgressTracker(), CancellationToken.None); + document, enabledDiagnostics, new ProgressTracker(), options, CancellationToken.None); var actual = await newDoc.GetTextAsync(); diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/AsyncSuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/AsyncSuggestedActionsSource.cs index 2724752aec37f..b19d38ed68a66 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/AsyncSuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/AsyncSuggestedActionsSource.cs @@ -168,12 +168,14 @@ private async IAsyncEnumerable GetCodeFixesAndRefactoringsAs var workspace = document.Project.Solution.Workspace; var supportsFeatureService = workspace.Services.GetRequiredService(); + var options = CodeActionOptionsFactory.GetCodeActionOptions(document.Project, isBlocking: false); + var fixesTask = GetCodeFixesAsync( state, supportsFeatureService, requestedActionCategories, workspace, document, range, - addOperationScope, priority, isBlocking: false, cancellationToken); + addOperationScope, priority, options, cancellationToken); var refactoringsTask = GetRefactoringsAsync( state, supportsFeatureService, requestedActionCategories, GlobalOptions, workspace, document, selection, - addOperationScope, priority, isBlocking: false, cancellationToken); + addOperationScope, priority, options, cancellationToken); await Task.WhenAll(fixesTask, refactoringsTask).ConfigureAwait(false); diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index 65254beb59b73..ffe511d2f93da 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -177,15 +177,18 @@ public bool TryGetTelemetryId(out Guid telemetryId) Func addOperationScope = description => operationContext?.AddScope(allowCancellation: true, string.Format(EditorFeaturesResources.Gathering_Suggestions_0, description)); + var options = CodeActionOptionsFactory.GetCodeActionOptions(document.Project, isBlocking: true); + // We convert the code fixes and refactorings to UnifiedSuggestedActionSets instead of // SuggestedActionSets so that we can share logic between local Roslyn and LSP. var fixesTask = GetCodeFixesAsync( state, supportsFeatureService, requestedActionCategories, workspace, document, range, addOperationScope, CodeActionRequestPriority.None, - isBlocking: true, cancellationToken); + options, cancellationToken); + var refactoringsTask = GetRefactoringsAsync( state, supportsFeatureService, requestedActionCategories, GlobalOptions, workspace, document, selection, - addOperationScope, CodeActionRequestPriority.None, isBlocking: true, cancellationToken); + addOperationScope, CodeActionRequestPriority.None, options, cancellationToken); Task.WhenAll(fixesTask, refactoringsTask).WaitAndGetResult(cancellationToken); @@ -263,7 +266,7 @@ protected static Task> GetCodeFixesAsy SnapshotSpan range, Func addOperationScope, CodeActionRequestPriority priority, - bool isBlocking, + CodeActionOptions options, CancellationToken cancellationToken) { if (state.Target.Owner._codeFixService == null || @@ -275,7 +278,7 @@ protected static Task> GetCodeFixesAsy return UnifiedSuggestedActionsSource.GetFilterAndOrderCodeFixesAsync( workspace, state.Target.Owner._codeFixService, document, range.Span.ToTextSpan(), - priority, isBlocking, addOperationScope, cancellationToken).AsTask(); + priority, options, addOperationScope, cancellationToken).AsTask(); } private static string GetFixCategory(DiagnosticSeverity severity) @@ -303,7 +306,7 @@ protected static Task> GetRefactorings TextSpan? selection, Func addOperationScope, CodeActionRequestPriority priority, - bool isBlocking, + CodeActionOptions options, CancellationToken cancellationToken) { if (!selection.HasValue) @@ -332,7 +335,7 @@ protected static Task> GetRefactorings var filterOutsideSelection = !requestedActionCategories.Contains(PredefinedSuggestedActionCategoryNames.Refactoring); return UnifiedSuggestedActionsSource.GetFilterAndOrderCodeRefactoringsAsync( - workspace, state.Target.Owner._codeRefactoringService, document, selection.Value, priority, isBlocking, + workspace, state.Target.Owner._codeRefactoringService, document, selection.Value, priority, options, addOperationScope, filterOutsideSelection, cancellationToken); } @@ -439,6 +442,7 @@ await InvokeBelowInputPriorityAsync(() => private async Task TryGetRefactoringSuggestedActionCategoryAsync( Document document, TextSpan? selection, + CodeActionOptions options, CancellationToken cancellationToken) { using var state = _state.TryAddReference(); @@ -457,7 +461,7 @@ await InvokeBelowInputPriorityAsync(() => state.Target.SubjectBuffer.SupportsRefactorings()) { if (await state.Target.Owner._codeRefactoringService.HasRefactoringsAsync( - document, selection.Value, cancellationToken).ConfigureAwait(false)) + document, selection.Value, options, cancellationToken).ConfigureAwait(false)) { return PredefinedSuggestedActionCategoryNames.Refactoring; } @@ -610,6 +614,8 @@ private void OnSuggestedActionsChanged(Workspace currentWorkspace, DocumentId? c if (document == null) return null; + var options = CodeActionOptionsFactory.GetCodeActionOptions(document.Project, isBlocking: true); + using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); var linkedToken = linkedTokenSource.Token; @@ -621,7 +627,7 @@ private void OnSuggestedActionsChanged(Workspace currentWorkspace, DocumentId? c if (selection != null) { refactoringTask = Task.Run( - () => TryGetRefactoringSuggestedActionCategoryAsync(document, selection, linkedToken), linkedToken); + () => TryGetRefactoringSuggestedActionCategoryAsync(document, selection, options, linkedToken), linkedToken); } // If we happen to get the result of the error task before the refactoring task, diff --git a/src/EditorFeatures/Core/Implementation/CodeActions/CodeActionOptionsFactory.cs b/src/EditorFeatures/Core/Implementation/CodeActions/CodeActionOptionsFactory.cs new file mode 100644 index 0000000000000..7b696b104cb46 --- /dev/null +++ b/src/EditorFeatures/Core/Implementation/CodeActions/CodeActionOptionsFactory.cs @@ -0,0 +1,22 @@ +// 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.SymbolSearch; + +namespace Microsoft.CodeAnalysis.CodeActions +{ + internal static class CodeActionOptionsFactory + { + internal static CodeActionOptions GetCodeActionOptions(Project project, bool isBlocking) + { + var options = project.Solution.Options; + var language = project.Language; + + return new( + IsBlocking: isBlocking, + SearchReferenceAssemblies: options.GetOption(SymbolSearchOptions.SuggestForTypesInReferenceAssemblies, language), + HideAdvancedMembers: options.GetOption(CodeAnalysis.Completion.CompletionOptions.Metadata.HideAdvancedMembers, language)); + } + } +} diff --git a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionHelpers.cs b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionHelpers.cs index a4913db3c9c21..def84093afa0d 100644 --- a/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionHelpers.cs +++ b/src/EditorFeatures/Core/Implementation/LanguageServer/Handlers/CodeActions/CodeActionHelpers.cs @@ -220,14 +220,15 @@ private static async ValueTask> GetAct { var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var textSpan = ProtocolConversions.RangeToTextSpan(selection, text); + var options = CodeActionOptionsFactory.GetCodeActionOptions(document.Project, isBlocking: false); var codeFixes = await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeFixesAsync( document.Project.Solution.Workspace, codeFixService, document, textSpan, CodeActionRequestPriority.None, - isBlocking: false, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); + options, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); var codeRefactorings = await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeRefactoringsAsync( - document.Project.Solution.Workspace, codeRefactoringService, document, textSpan, CodeActionRequestPriority.None, isBlocking: false, + document.Project.Solution.Workspace, codeRefactoringService, document, textSpan, CodeActionRequestPriority.None, options, addOperationScope: _ => null, filterOutsideSelection: false, cancellationToken).ConfigureAwait(false); var actionSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets(codeFixes, codeRefactorings, textSpan, currentActionCount: 0); diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs index aed04f6f96b5b..22d99bf626f56 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs @@ -69,7 +69,8 @@ private static async Task GetCodeRefactoringAsync( var span = documentsWithSelections.Single().SelectedSpans.Single(); var actions = ArrayBuilder<(CodeAction, TextSpan?)>.GetInstance(); var document = workspace.CurrentSolution.GetDocument(documentsWithSelections.Single().Id); - var context = new CodeRefactoringContext(document, span, (a, t) => actions.Add((a, t)), isBlocking: false, CancellationToken.None); + var options = CodeActionOptionsFactory.GetCodeActionOptions(document.Project, isBlocking: false); + var context = new CodeRefactoringContext(document, span, (a, t) => actions.Add((a, t)), options, CancellationToken.None); await provider.ComputeRefactoringsAsync(context); var result = actions.Count > 0 ? new CodeRefactoring(provider, actions.ToImmutable()) : null; diff --git a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs index e3642b0df912a..0f0f4f1a4e01b 100644 --- a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs +++ b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs @@ -87,7 +87,9 @@ public async Task TestGetFixesAsyncWithDuplicateDiagnostics() GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); // Verify that we do not crash when computing fixes. - _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), cancellationToken: CancellationToken.None); + var options = CodeActionOptions.Default; + + _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), options, CancellationToken.None); // Verify that code fix is invoked with both the diagnostics in the context, // i.e. duplicate diagnostics are not silently discarded by the CodeFixService. @@ -113,7 +115,8 @@ public async Task TestGetFixesAsyncHasNoDuplicateConfigurationActions() GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); // Verify registered configuration code actions do not have duplicates. - var fixCollections = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), cancellationToken: CancellationToken.None); + var options = CodeActionOptions.Default; + var fixCollections = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), options, CancellationToken.None); var codeActions = fixCollections.SelectMany(c => c.Fixes.Select(f => f.Action)).ToImmutableArray(); Assert.Equal(7, codeActions.Length); var uniqueTitles = new HashSet(); @@ -143,16 +146,18 @@ public async Task TestGetFixesAsyncForFixableAndNonFixableAnalyzersAsync() using var workspace = tuple.workspace; GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); + var options = CodeActionOptions.Default; + // Verify only analyzerWithFix is executed when GetFixesAsync is invoked with 'CodeActionRequestPriority.Normal'. _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), - priority: CodeActionRequestPriority.Normal, isBlocking: false, + priority: CodeActionRequestPriority.Normal, options, addOperationScope: _ => null, cancellationToken: CancellationToken.None); Assert.True(analyzerWithFix.ReceivedCallback); Assert.False(analyzerWithoutFix.ReceivedCallback); // Verify both analyzerWithFix and analyzerWithoutFix are executed when GetFixesAsync is invoked with 'CodeActionRequestPriority.Lowest'. _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), - priority: CodeActionRequestPriority.Lowest, isBlocking: false, + priority: CodeActionRequestPriority.Lowest, options, addOperationScope: _ => null, cancellationToken: CancellationToken.None); Assert.True(analyzerWithFix.ReceivedCallback); Assert.True(analyzerWithoutFix.ReceivedCallback); @@ -180,8 +185,10 @@ public async Task TestGetFixesAsyncForDocumentDiagnosticAnalyzerAsync() GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); // Verify both analyzers are executed when GetFixesAsync is invoked with 'CodeActionRequestPriority.Normal'. + var options = CodeActionOptions.Default; + _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), - priority: CodeActionRequestPriority.Normal, isBlocking: false, + priority: CodeActionRequestPriority.Normal, options, addOperationScope: _ => null, cancellationToken: CancellationToken.None); Assert.True(documentDiagnosticAnalyzer.ReceivedCallback); } @@ -265,7 +272,8 @@ private static async Task> GetAddedFixesAsync( var reference = new MockAnalyzerReference(codefix, ImmutableArray.Create(diagnosticAnalyzer)); var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); document = project.Documents.Single(); - var fixes = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), cancellationToken: CancellationToken.None); + var options = CodeActionOptions.Default; + var fixes = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), options, CancellationToken.None); if (exception) { @@ -679,7 +687,9 @@ private static async Task> GetNuGetAndVsixCode var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); var document = project.Documents.Single(); - return await fixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), cancellationToken: CancellationToken.None); + var options = CodeActionOptions.Default; + + return await fixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), options, CancellationToken.None); } private sealed class NuGetCodeFixProvider : AbstractNuGetOrVsixCodeFixProvider diff --git a/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs b/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs index c71af5b7f09a4..7029f5bbc819b 100644 --- a/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs +++ b/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs @@ -43,7 +43,8 @@ public async Task TestProjectRefactoringAsync() var reference = new StubAnalyzerReference(); var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); var document = project.Documents.Single(); - var refactorings = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), CancellationToken.None); + var options = CodeActionOptions.Default; + var refactorings = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), options, CancellationToken.None); var stubRefactoringAction = refactorings.Single(refactoring => refactoring.CodeActions.FirstOrDefault().action?.Title == nameof(StubRefactoring)); Assert.True(stubRefactoringAction is object); @@ -66,7 +67,8 @@ private static async Task VerifyRefactoringDisabledAsync() var project = workspace.CurrentSolution.Projects.Single(); var document = project.Documents.Single(); var extensionManager = (EditorLayerExtensionManager.ExtensionManager)document.Project.Solution.Workspace.Services.GetRequiredService(); - var result = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), CancellationToken.None); + var options = CodeActionOptions.Default; + var result = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), options, CancellationToken.None); Assert.True(extensionManager.IsDisabled(codeRefactoring)); Assert.False(extensionManager.IsIgnored(codeRefactoring)); diff --git a/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb b/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb index a33e70d72b162..3cee366731afe 100644 --- a/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb +++ b/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb @@ -52,6 +52,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences({analyzerReference})) Dim project = workspace.CurrentSolution.Projects(0) + Dim options = CodeActionOptionsFactory.GetCodeActionOptions(project, isBlocking:=False) Assert.IsType(Of MockDiagnosticUpdateSourceRegistrationService)(workspace.GetService(Of IDiagnosticUpdateSourceRegistrationService)()) Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) @@ -73,9 +74,12 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests Assert.Equal(1, diagnostics.Count()) ' Verify available codefix with a global fixer - Dim fixes = Await codefixService.GetFixesAsync(document, + Dim fixes = Await codefixService.GetFixesAsync( + document, (Await document.GetSyntaxRootAsync()).FullSpan, - cancellationToken:=CancellationToken.None) + options, + CancellationToken.None) + Assert.Equal(0, fixes.Count()) ' Verify available codefix with a global fixer + a project fixer @@ -86,17 +90,22 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests Dim projectAnalyzerReferences = ImmutableArray.Create(Of AnalyzerReference)(projectAnalyzerReference) project = project.WithAnalyzerReferences(projectAnalyzerReferences) document = project.Documents.Single() - fixes = Await codefixService.GetFixesAsync(document, - (Await document.GetSyntaxRootAsync()).FullSpan, - cancellationToken:=CancellationToken.None) + fixes = Await codefixService.GetFixesAsync( + document, + (Await document.GetSyntaxRootAsync()).FullSpan, + options, + CancellationToken.None) Assert.Equal(1, fixes.Count()) ' Remove a project analyzer project = project.RemoveAnalyzerReference(projectAnalyzerReference) document = project.Documents.Single() - fixes = Await codefixService.GetFixesAsync(document, - (Await document.GetSyntaxRootAsync()).FullSpan, - cancellationToken:=CancellationToken.None) + fixes = Await codefixService.GetFixesAsync( + document, + (Await document.GetSyntaxRootAsync()).FullSpan, + options, + CancellationToken.None) + Assert.Equal(0, fixes.Count()) End Using End Function @@ -120,6 +129,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences({analyzerReference})) Dim project = workspace.CurrentSolution.Projects(0) + Dim options = CodeActionOptionsFactory.GetCodeActionOptions(project, isBlocking:=False) Assert.IsType(Of MockDiagnosticUpdateSourceRegistrationService)(workspace.GetService(Of IDiagnosticUpdateSourceRegistrationService)()) Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) @@ -141,9 +151,12 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests Assert.Equal(1, diagnostics.Count()) ' Verify no codefix with a global fixer - Dim fixes = Await codefixService.GetFixesAsync(document, - (Await document.GetSyntaxRootAsync()).FullSpan, - cancellationToken:=CancellationToken.None) + Dim fixes = Await codefixService.GetFixesAsync( + document, + (Await document.GetSyntaxRootAsync()).FullSpan, + options, + CancellationToken.None) + Assert.Equal(0, fixes.Count()) ' Verify no codefix with a global fixer + a project fixer @@ -154,9 +167,12 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests Dim projectAnalyzerReferences = ImmutableArray.Create(Of AnalyzerReference)(projectAnalyzerReference) project = project.WithAnalyzerReferences(projectAnalyzerReferences) document = project.Documents.Single() - fixes = Await codefixService.GetFixesAsync(document, - (Await document.GetSyntaxRootAsync()).FullSpan, - cancellationToken:=CancellationToken.None) + fixes = Await codefixService.GetFixesAsync( + document, + (Await document.GetSyntaxRootAsync()).FullSpan, + options, + CancellationToken.None) + Assert.Equal(0, fixes.Count()) End Using End Function diff --git a/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb b/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb index 78406bfccc6cc..88eba07274574 100644 --- a/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeCleanup Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Diagnostics.VisualBasic @@ -328,6 +329,8 @@ End Class Optional systemImportsFirst As Boolean = True, Optional separateImportsGroups As Boolean = False) As Task Using workspace = TestWorkspace.CreateVisualBasic(code, composition:=EditorTestCompositions.EditorFeaturesWpf) + Dim options = CodeActionOptions.Default + Dim solution = workspace.CurrentSolution _ .WithOptions(workspace.Options _ .WithChangedOption(GenerationOptions.PlaceSystemNamespaceFirst, @@ -355,10 +358,12 @@ End Class Dim enabledDiagnostics = codeCleanupService.GetAllDiagnostics() - Dim newDoc = Await codeCleanupService.CleanupAsync(document, - enabledDiagnostics, - New ProgressTracker, - CancellationToken.None) + Dim newDoc = Await codeCleanupService.CleanupAsync( + document, + enabledDiagnostics, + New ProgressTracker, + options, + CancellationToken.None) Dim actual = Await newDoc.GetTextAsync() diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs index 21d58dd3d068e..b1be5bf7d37f6 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs @@ -62,8 +62,8 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var searchNuGetPackages = solution.Options.GetOption(SymbolSearchOptions.SuggestForTypesInNuGetPackages, document.Project.Language); var options = new AddImportOptions( - SearchReferenceAssemblies: solution.Options.GetOption(SymbolSearchOptions.SuggestForTypesInReferenceAssemblies, document.Project.Language), - HideAdvancedMembers: solution.Options.GetOption(CompletionOptions.Metadata.HideAdvancedMembers, document.Project.Language)); + context.Options.SearchReferenceAssemblies, + context.Options.HideAdvancedMembers); var symbolSearchService = options.SearchReferenceAssemblies || searchNuGetPackages ? _symbolSearchService ?? solution.Workspace.Services.GetService() diff --git a/src/Features/Core/Portable/CodeCleanup/AbstractCodeCleanupService.cs b/src/Features/Core/Portable/CodeCleanup/AbstractCodeCleanupService.cs index 4856d21bda509..42ee1c96c1251 100644 --- a/src/Features/Core/Portable/CodeCleanup/AbstractCodeCleanupService.cs +++ b/src/Features/Core/Portable/CodeCleanup/AbstractCodeCleanupService.cs @@ -5,13 +5,13 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.RemoveUnnecessaryImports; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeCleanup { @@ -31,6 +31,7 @@ public async Task CleanupAsync( Document document, EnabledDiagnosticOptions enabledDiagnostics, IProgressTracker progressTracker, + CodeActionOptions options, CancellationToken cancellationToken) { // add one item for the 'format' action we'll do last @@ -48,7 +49,7 @@ public async Task CleanupAsync( } document = await ApplyCodeFixesAsync( - document, enabledDiagnostics.Diagnostics, progressTracker, cancellationToken).ConfigureAwait(false); + document, enabledDiagnostics.Diagnostics, progressTracker, options, cancellationToken).ConfigureAwait(false); // do the remove usings after code fix, as code fix might remove some code which can results in unused usings. if (organizeUsings) @@ -100,7 +101,7 @@ private static async Task RemoveSortUsingsAsync( private async Task ApplyCodeFixesAsync( Document document, ImmutableArray enabledDiagnosticSets, - IProgressTracker progressTracker, CancellationToken cancellationToken) + IProgressTracker progressTracker, CodeActionOptions options, CancellationToken cancellationToken) { // Add a progress item for each enabled option we're going to fixup. progressTracker.AddItems(enabledDiagnosticSets.Length); @@ -111,7 +112,7 @@ private async Task ApplyCodeFixesAsync( progressTracker.Description = diagnosticSet.Description; document = await ApplyCodeFixesForSpecificDiagnosticIdsAsync( - document, diagnosticSet.DiagnosticIds, progressTracker, cancellationToken).ConfigureAwait(false); + document, diagnosticSet.DiagnosticIds, progressTracker, options, cancellationToken).ConfigureAwait(false); // Mark this option as being completed. progressTracker.ItemCompleted(); @@ -121,14 +122,14 @@ private async Task ApplyCodeFixesAsync( } private async Task ApplyCodeFixesForSpecificDiagnosticIdsAsync( - Document document, ImmutableArray diagnosticIds, IProgressTracker progressTracker, CancellationToken cancellationToken) + Document document, ImmutableArray diagnosticIds, IProgressTracker progressTracker, CodeActionOptions options, CancellationToken cancellationToken) { foreach (var diagnosticId in diagnosticIds) { using (Logger.LogBlock(FunctionId.CodeCleanup_ApplyCodeFixesAsync, diagnosticId, cancellationToken)) { document = await _codeFixService.ApplyCodeFixesForSpecificDiagnosticIdAsync( - document, diagnosticId, progressTracker, cancellationToken).ConfigureAwait(false); + document, diagnosticId, progressTracker, options, cancellationToken).ConfigureAwait(false); } } diff --git a/src/Features/Core/Portable/CodeCleanup/ICodeCleanupService.cs b/src/Features/Core/Portable/CodeCleanup/ICodeCleanupService.cs index e4fe64bab3dbb..5a59c9196d52c 100644 --- a/src/Features/Core/Portable/CodeCleanup/ICodeCleanupService.cs +++ b/src/Features/Core/Portable/CodeCleanup/ICodeCleanupService.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -11,7 +12,7 @@ namespace Microsoft.CodeAnalysis.CodeCleanup { internal interface ICodeCleanupService : ILanguageService { - Task CleanupAsync(Document document, EnabledDiagnosticOptions enabledDiagnostics, IProgressTracker progressTracker, CancellationToken cancellationToken); + Task CleanupAsync(Document document, EnabledDiagnosticOptions enabledDiagnostics, IProgressTracker progressTracker, CodeActionOptions options, CancellationToken cancellationToken); EnabledDiagnosticOptions GetAllDiagnostics(); } } diff --git a/src/Features/Core/Portable/CodeFixes/CodeFixService.cs b/src/Features/Core/Portable/CodeFixes/CodeFixService.cs index a33099b6eb8bf..c28c4dcc1c907 100644 --- a/src/Features/Core/Portable/CodeFixes/CodeFixService.cs +++ b/src/Features/Core/Portable/CodeFixes/CodeFixService.cs @@ -157,7 +157,7 @@ public async Task> GetFixesAsync( Document document, TextSpan range, CodeActionRequestPriority priority, - bool isBlocking, + CodeActionOptions options, Func addOperationScope, CancellationToken cancellationToken) { @@ -219,7 +219,7 @@ public async Task> GetFixesAsync( { await AppendFixesAsync( document, spanAndDiagnostic.Key, spanAndDiagnostic.Value, fixAllForInSpan: false, - priority, isBlocking, result, addOperationScope, cancellationToken).ConfigureAwait(false); + priority, options, result, addOperationScope, cancellationToken).ConfigureAwait(false); } } @@ -266,7 +266,7 @@ Func GetFixableDiagnosticFilter(Document document) } } - public async Task GetDocumentFixAllForIdInSpanAsync(Document document, TextSpan range, string diagnosticId, CancellationToken cancellationToken) + public async Task GetDocumentFixAllForIdInSpanAsync(Document document, TextSpan range, string diagnosticId, CodeActionOptions options, CancellationToken cancellationToken) { var diagnostics = (await _diagnosticService.GetDiagnosticsForSpanAsync(document, range, diagnosticId, includeSuppressedDiagnostics: false, cancellationToken: cancellationToken).ConfigureAwait(false)).ToList(); if (diagnostics.Count == 0) @@ -275,20 +275,20 @@ Func GetFixableDiagnosticFilter(Document document) } using var resultDisposer = ArrayBuilder.GetInstance(out var result); - await AppendFixesAsync(document, range, diagnostics, fixAllForInSpan: true, CodeActionRequestPriority.None, isBlocking: false, result, addOperationScope: _ => null, cancellationToken).ConfigureAwait(false); + await AppendFixesAsync(document, range, diagnostics, fixAllForInSpan: true, CodeActionRequestPriority.None, options, 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 return result.ToImmutable().FirstOrDefault(); } - public async Task ApplyCodeFixesForSpecificDiagnosticIdAsync(Document document, string diagnosticId, IProgressTracker progressTracker, CancellationToken cancellationToken) + public async Task ApplyCodeFixesForSpecificDiagnosticIdAsync(Document document, string diagnosticId, IProgressTracker progressTracker, CodeActionOptions options, CancellationToken cancellationToken) { var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var textSpan = new TextSpan(0, tree.Length); var fixCollection = await GetDocumentFixAllForIdInSpanAsync( - document, textSpan, diagnosticId, cancellationToken).ConfigureAwait(false); + document, textSpan, diagnosticId, options, cancellationToken).ConfigureAwait(false); if (fixCollection == null) { return document; @@ -372,7 +372,7 @@ private async Task AppendFixesAsync( IEnumerable diagnostics, bool fixAllForInSpan, CodeActionRequestPriority priority, - bool isBlocking, + CodeActionOptions options, ArrayBuilder result, Func addOperationScope, CancellationToken cancellationToken) @@ -453,13 +453,13 @@ await AppendFixesOrConfigurationsAsync( if (fixAllForInSpan) { var primaryDiagnostic = dxs.First(); - return GetCodeFixesAsync(document, primaryDiagnostic.Location.SourceSpan, fixer, fixerMetadata, isBlocking, + return GetCodeFixesAsync(document, primaryDiagnostic.Location.SourceSpan, fixer, fixerMetadata, options, ImmutableArray.Create(primaryDiagnostic), uniqueDiagosticToEquivalenceKeysMap, diagnosticAndEquivalenceKeyToFixersMap, cancellationToken); } else { - return GetCodeFixesAsync(document, span, fixer, fixerMetadata, isBlocking, dxs, + return GetCodeFixesAsync(document, span, fixer, fixerMetadata, options, dxs, uniqueDiagosticToEquivalenceKeysMap, diagnosticAndEquivalenceKeyToFixersMap, cancellationToken); } } @@ -481,7 +481,7 @@ await AppendFixesOrConfigurationsAsync( } private static async Task> GetCodeFixesAsync( - Document document, TextSpan span, CodeFixProvider fixer, CodeChangeProviderMetadata? fixerMetadata, bool isBlocking, + Document document, TextSpan span, CodeFixProvider fixer, CodeChangeProviderMetadata? fixerMetadata, CodeActionOptions options, ImmutableArray diagnostics, Dictionary> uniqueDiagosticToEquivalenceKeysMap, Dictionary<(Diagnostic diagnostic, string? equivalenceKey), CodeFixProvider> diagnosticAndEquivalenceKeyToFixersMap, @@ -510,7 +510,7 @@ private static async Task> GetCodeFixesAsync( } } }, - isBlocking, + options, cancellationToken); var task = fixer.RegisterCodeFixesAsync(context) ?? Task.CompletedTask; diff --git a/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs b/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs index ffa0dcb75aebb..c001b53f37052 100644 --- a/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs +++ b/src/Features/Core/Portable/CodeFixes/ICodeFixService.cs @@ -15,19 +15,16 @@ namespace Microsoft.CodeAnalysis.CodeFixes { internal interface ICodeFixService { - Task> GetFixesAsync(Document document, TextSpan textSpan, 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); + Task> GetFixesAsync(Document document, TextSpan textSpan, CodeActionRequestPriority priority, CodeActionOptions options, Func addOperationScope, CancellationToken cancellationToken); + Task GetDocumentFixAllForIdInSpanAsync(Document document, TextSpan textSpan, string diagnosticId, CodeActionOptions options, CancellationToken cancellationToken); + Task ApplyCodeFixesForSpecificDiagnosticIdAsync(Document document, string diagnosticId, IProgressTracker progressTracker, CodeActionOptions options, CancellationToken cancellationToken); CodeFixProvider? GetSuppressionFixer(string language, IEnumerable diagnosticIds); Task GetMostSevereFixableDiagnosticAsync(Document document, TextSpan range, CancellationToken cancellationToken); } internal static class ICodeFixServiceExtensions { - public static Task> GetFixesAsync(this ICodeFixService service, Document document, TextSpan range, CancellationToken cancellationToken) - => service.GetFixesAsync(document, range, isBlocking: false, cancellationToken); - - public static Task> GetFixesAsync(this ICodeFixService service, Document document, TextSpan range, bool isBlocking, CancellationToken cancellationToken) - => service.GetFixesAsync(document, range, CodeActionRequestPriority.None, isBlocking, addOperationScope: _ => null, cancellationToken); + public static Task> GetFixesAsync(this ICodeFixService service, Document document, TextSpan range, CodeActionOptions options, CancellationToken cancellationToken) + => service.GetFixesAsync(document, range, CodeActionRequestPriority.None, options, addOperationScope: _ => null, cancellationToken); } } diff --git a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs index c08082bd87f50..9fe9fda267152 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs @@ -37,8 +37,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte // Check pasted text span for missing imports var addMissingImportsService = document.GetLanguageService(); - var options = new AddMissingImportsOptions( - HideAdvancedMembers: document.Project.Solution.Options.GetOption(CompletionOptions.Metadata.HideAdvancedMembers, document.Project.Language)); + var options = new AddMissingImportsOptions(context.Options.HideAdvancedMembers); var analysis = await addMissingImportsService.AnalyzeAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false); if (!analysis.CanAddMissingImports) diff --git a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs index 4fd43ca55d7b3..cfb19127cff22 100644 --- a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs @@ -24,7 +24,7 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings { [Export(typeof(ICodeRefactoringService)), Shared] - internal class CodeRefactoringService : ICodeRefactoringService + internal sealed class CodeRefactoringService : ICodeRefactoringService { private readonly Lazy>>> _lazyLanguageToProvidersMap; private readonly Lazy> _lazyRefactoringToMetadataMap; @@ -84,6 +84,7 @@ private ConcatImmutableArray GetProviders(Document docu public async Task HasRefactoringsAsync( Document document, TextSpan state, + CodeActionOptions options, CancellationToken cancellationToken) { var extensionManager = document.Project.Solution.Workspace.Services.GetRequiredService(); @@ -94,7 +95,7 @@ public async Task HasRefactoringsAsync( RefactoringToMetadataMap.TryGetValue(provider, out var providerMetadata); var refactoring = await GetRefactoringFromProviderAsync( - document, state, provider, providerMetadata, extensionManager, isBlocking: false, cancellationToken).ConfigureAwait(false); + document, state, provider, providerMetadata, extensionManager, options, cancellationToken).ConfigureAwait(false); if (refactoring != null) { @@ -109,7 +110,7 @@ public async Task> GetRefactoringsAsync( Document document, TextSpan state, CodeActionRequestPriority priority, - bool isBlocking, + CodeActionOptions options, Func addOperationScope, CancellationToken cancellationToken) { @@ -131,7 +132,7 @@ public async Task> GetRefactoringsAsync( using (addOperationScope(providerName)) using (RoslynEventSource.LogInformationalBlock(FunctionId.Refactoring_CodeRefactoringService_GetRefactoringsAsync, providerName, cancellationToken)) { - return GetRefactoringFromProviderAsync(document, state, provider, providerMetadata, extensionManager, isBlocking, cancellationToken); + return GetRefactoringFromProviderAsync(document, state, provider, providerMetadata, extensionManager, options, cancellationToken); } }, cancellationToken)); @@ -148,7 +149,7 @@ public async Task> GetRefactoringsAsync( CodeRefactoringProvider provider, CodeChangeProviderMetadata? providerMetadata, IExtensionManager extensionManager, - bool isBlocking, + CodeActionOptions options, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -176,7 +177,7 @@ public async Task> GetRefactoringsAsync( actions.Add((action, applicableToSpan)); } }, - isBlocking, + options, cancellationToken); var task = provider.ComputeRefactoringsAsync(context) ?? Task.CompletedTask; diff --git a/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs index 840c4835d72d4..0e43a48d39e56 100644 --- a/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs @@ -13,17 +13,14 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings { internal interface ICodeRefactoringService { - Task HasRefactoringsAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken); + Task HasRefactoringsAsync(Document document, TextSpan textSpan, CodeActionOptions options, CancellationToken cancellationToken); - Task> GetRefactoringsAsync(Document document, TextSpan textSpan, CodeActionRequestPriority priority, bool isBlocking, Func addOperationScope, CancellationToken cancellationToken); + Task> GetRefactoringsAsync(Document document, TextSpan textSpan, CodeActionRequestPriority priority, CodeActionOptions options, Func addOperationScope, CancellationToken cancellationToken); } internal static class ICodeRefactoringServiceExtensions { - public static Task> GetRefactoringsAsync(this ICodeRefactoringService service, Document document, TextSpan state, CancellationToken cancellationToken) - => 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, CodeActionRequestPriority.None, isBlocking, addOperationScope: _ => null, cancellationToken); + public static Task> GetRefactoringsAsync(this ICodeRefactoringService service, Document document, TextSpan state, CodeActionOptions options, CancellationToken cancellationToken) + => service.GetRefactoringsAsync(document, state, CodeActionRequestPriority.None, options, addOperationScope: _ => null, cancellationToken); } } diff --git a/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs b/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs index 2ca13963182aa..e51c1efe4dbd3 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, CodeActionRequestPriority priority, - bool isBlocking, + CodeActionOptions options, Func addOperationScope, CancellationToken cancellationToken) { @@ -45,7 +45,7 @@ public static async ValueTask> GetFilt document, selection, priority, - isBlocking, + options, addOperationScope, cancellationToken), cancellationToken).ConfigureAwait(false); @@ -388,7 +388,7 @@ public static async Task> GetFilterAnd Document document, TextSpan selection, CodeActionRequestPriority priority, - bool isBlocking, + CodeActionOptions options, Func addOperationScope, bool filterOutsideSelection, CancellationToken cancellationToken) @@ -399,7 +399,7 @@ public static async Task> GetFilterAnd // the UI thread. var refactorings = await Task.Run( () => codeRefactoringService.GetRefactoringsAsync( - document, selection, priority, isBlocking, addOperationScope, + document, selection, priority, options, addOperationScope, cancellationToken), cancellationToken).ConfigureAwait(false); var filteredRefactorings = FilterOnAnyThread(refactorings, selection, filterOutsideSelection); diff --git a/src/VisualStudio/Core/Def/Implementation/CodeCleanup/AbstractCodeCleanUpFixer.cs b/src/VisualStudio/Core/Def/Implementation/CodeCleanup/AbstractCodeCleanUpFixer.cs index 38943b89d3ebc..85783095c3cec 100644 --- a/src/VisualStudio/Core/Def/Implementation/CodeCleanup/AbstractCodeCleanUpFixer.cs +++ b/src/VisualStudio/Core/Def/Implementation/CodeCleanup/AbstractCodeCleanUpFixer.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; @@ -127,7 +128,9 @@ private async Task FixHierarchyContentAsync(IVsHierarchyCodeCleanupScope h return false; } - return await FixDocumentAsync(solution.GetRequiredDocument(documentId), context).ConfigureAwait(true); + var document = solution.GetRequiredDocument(documentId); + var options = CodeActionOptionsFactory.GetCodeActionOptions(document.Project, isBlocking: false); + return await FixDocumentAsync(document, options, context).ConfigureAwait(true); } } @@ -157,14 +160,14 @@ async Task ApplyFixAsync(ProgressTracker progressTracker, Cancellation } } - private Task FixDocumentAsync(Document document, ICodeCleanUpExecutionContext context) + private Task FixDocumentAsync(Document document, CodeActionOptions options, ICodeCleanUpExecutionContext context) { return FixAsync(document.Project.Solution.Workspace, ApplyFixAsync, context); // Local function async Task ApplyFixAsync(ProgressTracker progressTracker, CancellationToken cancellationToken) { - var newDocument = await FixDocumentAsync(document, context.EnabledFixIds, progressTracker, cancellationToken).ConfigureAwait(true); + var newDocument = await FixDocumentAsync(document, context.EnabledFixIds, progressTracker, options, cancellationToken).ConfigureAwait(true); return newDocument.Project.Solution; } } @@ -194,7 +197,9 @@ async Task ApplyFixAsync(ProgressTracker progressTracker, Cancellation { var document = buffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); Contract.ThrowIfNull(document); - var newDoc = await FixDocumentAsync(document, context.EnabledFixIds, progressTracker, cancellationToken).ConfigureAwait(true); + + var options = CodeActionOptionsFactory.GetCodeActionOptions(document.Project, isBlocking: false); + var newDoc = await FixDocumentAsync(document, context.EnabledFixIds, progressTracker, options, cancellationToken).ConfigureAwait(true); return newDoc.Project.Solution; } } @@ -280,6 +285,8 @@ private async Task FixProjectAsync( progressTracker.AddItems(project.DocumentIds.Count); } + var options = CodeActionOptionsFactory.GetCodeActionOptions(project, isBlocking: false); + foreach (var documentId in project.DocumentIds) { cancellationToken.ThrowIfCancellationRequested(); @@ -291,7 +298,7 @@ private async Task FixProjectAsync( // to the current document. var documentProgressTracker = new ProgressTracker(); - var fixedDocument = await FixDocumentAsync(document, enabledFixIds, documentProgressTracker, cancellationToken).ConfigureAwait(false); + var fixedDocument = await FixDocumentAsync(document, enabledFixIds, documentProgressTracker, options, cancellationToken).ConfigureAwait(false); project = fixedDocument.Project; progressTracker.ItemCompleted(); } @@ -306,6 +313,7 @@ private async Task FixDocumentAsync( Document document, FixIdContainer enabledFixIds, ProgressTracker progressTracker, + CodeActionOptions options, CancellationToken cancellationToken) { if (document.IsGeneratedCode(cancellationToken)) @@ -340,7 +348,7 @@ private async Task FixDocumentAsync( new OrganizeUsingsSet(isRemoveUnusedUsingsEnabled, isSortUsingsEnabled)); return await codeCleanupService.CleanupAsync( - document, enabledDiagnostics, progressTracker, cancellationToken).ConfigureAwait(false); + document, enabledDiagnostics, progressTracker, options, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/Workspaces/Core/Portable/CodeActions/CodeActionOptions.cs b/src/Workspaces/Core/Portable/CodeActions/CodeActionOptions.cs new file mode 100644 index 0000000000000..4faf8c7096fb7 --- /dev/null +++ b/src/Workspaces/Core/Portable/CodeActions/CodeActionOptions.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.CodeAnalysis.CodeActions +{ + /// + /// Options available to code fixes that are supplied by the IDE (i.e. not stored in editorconfig). + /// + internal readonly record struct CodeActionOptions( + bool IsBlocking, + bool SearchReferenceAssemblies, + bool HideAdvancedMembers) + { + public static readonly CodeActionOptions Default = new( + IsBlocking: false, + SearchReferenceAssemblies: true, + HideAdvancedMembers: false); + + } +} diff --git a/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs b/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs index f7c41df235f9d..47a020c75426f 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs @@ -45,8 +45,8 @@ namespace Microsoft.CodeAnalysis.CodeFixes /// public CancellationToken CancellationToken => _cancellationToken; - private readonly bool _isBlocking; - bool ITypeScriptCodeFixContext.IsBlocking => _isBlocking; + internal readonly CodeActionOptions Options; + bool ITypeScriptCodeFixContext.IsBlocking => Options.IsBlocking; /// /// Creates a code fix context to be passed into method. @@ -75,7 +75,7 @@ public CodeFixContext( span, VerifyDiagnosticsArgument(diagnostics, span), registerCodeFix ?? throw new ArgumentNullException(nameof(registerCodeFix)), - isBlocking: false, + CodeActionOptions.Default, cancellationToken) { } @@ -100,7 +100,7 @@ public CodeFixContext( (diagnostic ?? throw new ArgumentNullException(nameof(diagnostic))).Location.SourceSpan, ImmutableArray.Create(diagnostic), registerCodeFix ?? throw new ArgumentNullException(nameof(registerCodeFix)), - isBlocking: false, + CodeActionOptions.Default, cancellationToken) { } @@ -110,7 +110,7 @@ internal CodeFixContext( TextSpan span, ImmutableArray diagnostics, Action> registerCodeFix, - bool isBlocking, + CodeActionOptions options, CancellationToken cancellationToken) { Debug.Assert(diagnostics.Any(d => d.Location.SourceSpan == span)); @@ -119,7 +119,7 @@ internal CodeFixContext( _span = span; _diagnostics = diagnostics; _registerCodeFix = registerCodeFix; - _isBlocking = isBlocking; + Options = options; _cancellationToken = cancellationToken; } diff --git a/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringContext.cs b/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringContext.cs index f53126a650902..09e1442f9d76b 100644 --- a/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringContext.cs +++ b/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringContext.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings /// /// Context for code refactorings provided by a . /// - public struct CodeRefactoringContext : ITypeScriptCodeRefactoringContext + public readonly struct CodeRefactoringContext : ITypeScriptCodeRefactoringContext { /// /// Document corresponding to the to refactor. @@ -29,8 +29,8 @@ public struct CodeRefactoringContext : ITypeScriptCodeRefactoringContext /// public CancellationToken CancellationToken { get; } - private readonly bool _isBlocking; - bool ITypeScriptCodeRefactoringContext.IsBlocking => _isBlocking; + internal readonly CodeActionOptions Options; + bool ITypeScriptCodeRefactoringContext.IsBlocking => Options.IsBlocking; private readonly Action _registerRefactoring; @@ -42,7 +42,7 @@ public CodeRefactoringContext( TextSpan span, Action registerRefactoring, CancellationToken cancellationToken) - : this(document, span, (action, textSpan) => registerRefactoring(action), isBlocking: false, cancellationToken) + : this(document, span, (action, textSpan) => registerRefactoring(action), CodeActionOptions.Default, cancellationToken) { } /// @@ -52,7 +52,7 @@ internal CodeRefactoringContext( Document document, TextSpan span, Action registerRefactoring, - bool isBlocking, + CodeActionOptions options, CancellationToken cancellationToken) { // NOTE/TODO: Don't make this overload public & obsolete the `Action registerRefactoring` @@ -60,7 +60,7 @@ internal CodeRefactoringContext( Document = document ?? throw new ArgumentNullException(nameof(document)); Span = span; _registerRefactoring = registerRefactoring ?? throw new ArgumentNullException(nameof(registerRefactoring)); - _isBlocking = isBlocking; + Options = options; CancellationToken = cancellationToken; }