From 7f406fa5d8f1daa256d6f3582c7a42f2aaccb5d9 Mon Sep 17 00:00:00 2001 From: tmat Date: Sun, 9 Jan 2022 18:24:38 -0800 Subject: [PATCH 1/5] Move reading HideAdvancedMembers option up --- .../AbstractAddImportsPasteCommandHandler.cs | 6 +++- .../AbstractAddImportCodeFixProvider.cs | 13 +++++---- .../AbstractAddImportFeatureService.cs | 28 +++++++++---------- .../AddImport/IAddImportFeatureService.cs | 14 +++++++--- .../IRemoteMissingImportDiscoveryService.cs | 5 ++-- .../AddImport/SymbolReferenceFinder.cs | 17 +++++------ ...olReferenceFinder_PackageAssemblySearch.cs | 2 +- ...AbstractAddMissingImportsFeatureService.cs | 13 ++++++--- ...actAddMissingImportsRefactoringProvider.cs | 6 +++- .../IAddMissingImportsFeatureService.cs | 11 ++++++-- .../AbstractFullyQualifyCodeFixProvider.cs | 7 ++--- .../RemoteMissingImportDiscoveryService.cs | 8 +++--- 12 files changed, 79 insertions(+), 51 deletions(-) diff --git a/src/EditorFeatures/Core/Implementation/AddImports/AbstractAddImportsPasteCommandHandler.cs b/src/EditorFeatures/Core/Implementation/AddImports/AbstractAddImportsPasteCommandHandler.cs index d49e1eb3154d2..b63c21f4e6a49 100644 --- a/src/EditorFeatures/Core/Implementation/AddImports/AbstractAddImportsPasteCommandHandler.cs +++ b/src/EditorFeatures/Core/Implementation/AddImports/AbstractAddImportsPasteCommandHandler.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; using Microsoft.CodeAnalysis.AddMissingImports; +using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; @@ -114,6 +115,9 @@ private void ExecuteCommandWorker( return; } + var options = new AddMissingImportsOptions( + HideAdvancedMembers: document.Project.Solution.Options.GetOption(CompletionOptions.Metadata.HideAdvancedMembers, document.Project.Language)); + using var _ = executionContext.OperationContext.AddScope(allowCancellation: true, DialogText); var cancellationToken = executionContext.OperationContext.UserCancellationToken; @@ -123,7 +127,7 @@ private void ExecuteCommandWorker( var addMissingImportsService = document.GetRequiredLanguageService(); #pragma warning disable VSTHRD102 // Implement internal logic asynchronously - var updatedDocument = _threadingContext.JoinableTaskFactory.Run(() => addMissingImportsService.AddMissingImportsAsync(document, textSpan, cancellationToken)); + var updatedDocument = _threadingContext.JoinableTaskFactory.Run(() => addMissingImportsService.AddMissingImportsAsync(document, textSpan, options, cancellationToken)); #pragma warning restore VSTHRD102 // Implement internal logic asynchronously if (updatedDocument is null) { diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs index d08056166d630..21d58dd3d068e 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Packaging; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SymbolSearch; @@ -57,12 +58,14 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var addImportService = document.GetLanguageService(); var solution = document.Project.Solution; - var options = solution.Options; - var searchReferenceAssemblies = options.GetOption(SymbolSearchOptions.SuggestForTypesInReferenceAssemblies, document.Project.Language); - var searchNuGetPackages = options.GetOption(SymbolSearchOptions.SuggestForTypesInNuGetPackages, document.Project.Language); + var searchNuGetPackages = solution.Options.GetOption(SymbolSearchOptions.SuggestForTypesInNuGetPackages, document.Project.Language); - var symbolSearchService = searchReferenceAssemblies || searchNuGetPackages + var options = new AddImportOptions( + SearchReferenceAssemblies: solution.Options.GetOption(SymbolSearchOptions.SuggestForTypesInReferenceAssemblies, document.Project.Language), + HideAdvancedMembers: solution.Options.GetOption(CompletionOptions.Metadata.HideAdvancedMembers, document.Project.Language)); + + var symbolSearchService = options.SearchReferenceAssemblies || searchNuGetPackages ? _symbolSearchService ?? solution.Workspace.Services.GetService() : null; @@ -72,7 +75,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) : ImmutableArray.Empty; var fixesForDiagnostic = await addImportService.GetFixesForDiagnosticsAsync( - document, span, diagnostics, MaxResults, symbolSearchService, searchReferenceAssemblies, packageSources, cancellationToken).ConfigureAwait(false); + document, span, diagnostics, MaxResults, symbolSearchService, options, packageSources, cancellationToken).ConfigureAwait(false); foreach (var (diagnostic, fixes) in fixesForDiagnostic) { diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs index c0cc1aaf35ae1..09631827585c8 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs @@ -56,7 +56,7 @@ internal abstract partial class AbstractAddImportFeatureService> GetFixesAsync( Document document, TextSpan span, string diagnosticId, int maxResults, bool allowInHiddenRegions, - ISymbolSearchService symbolSearchService, bool searchReferenceAssemblies, + ISymbolSearchService symbolSearchService, AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken) { var client = await RemoteHostClient.TryGetClientAsync(document.Project, cancellationToken).ConfigureAwait(false); @@ -65,7 +65,7 @@ public async Task> GetFixesAsync( var result = await client.TryInvokeAsync>( document.Project.Solution, (service, solutionInfo, callbackId, cancellationToken) => - service.GetFixesAsync(solutionInfo, callbackId, document.Id, span, diagnosticId, maxResults, allowInHiddenRegions, searchReferenceAssemblies, packageSources, cancellationToken), + service.GetFixesAsync(solutionInfo, callbackId, document.Id, span, diagnosticId, maxResults, allowInHiddenRegions, options, packageSources, cancellationToken), callbackTarget: symbolSearchService, cancellationToken).ConfigureAwait(false); @@ -75,14 +75,14 @@ public async Task> GetFixesAsync( return await GetFixesInCurrentProcessAsync( document, span, diagnosticId, maxResults, allowInHiddenRegions, - symbolSearchService, searchReferenceAssemblies, + symbolSearchService, options, packageSources, cancellationToken).ConfigureAwait(false); } private async Task> GetFixesInCurrentProcessAsync( Document document, TextSpan span, string diagnosticId, int maxResults, bool allowInHiddenRegions, - ISymbolSearchService symbolSearchService, bool searchReferenceAssemblies, + ISymbolSearchService symbolSearchService, AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken) { var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); @@ -102,7 +102,7 @@ private async Task> GetFixesInCurrentProcessAsy var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var allSymbolReferences = await FindResultsAsync( document, semanticModel, diagnosticId, node, maxResults, symbolSearchService, - searchReferenceAssemblies, packageSources, cancellationToken).ConfigureAwait(false); + options, packageSources, cancellationToken).ConfigureAwait(false); // Nothing found at all. No need to proceed. foreach (var reference in allSymbolReferences) @@ -122,7 +122,7 @@ private async Task> GetFixesInCurrentProcessAsy private async Task> FindResultsAsync( Document document, SemanticModel semanticModel, string diagnosticId, SyntaxNode node, int maxResults, ISymbolSearchService symbolSearchService, - bool searchReferenceAssemblies, ImmutableArray packageSources, CancellationToken cancellationToken) + AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken) { // Caches so we don't produce the same data multiple times while searching // all over the solution. @@ -132,7 +132,7 @@ private async Task> FindResultsAsync( var finder = new SymbolReferenceFinder( this, document, semanticModel, diagnosticId, node, symbolSearchService, - searchReferenceAssemblies, packageSources, cancellationToken); + options, packageSources, cancellationToken); // Look for exact matches first: var exactReferences = await FindResultsAsync(projectToAssembly, referenceToCompilation, project, maxResults, finder, exact: true, cancellationToken: cancellationToken).ConfigureAwait(false); @@ -488,7 +488,7 @@ private static bool NotNull(SymbolReference reference) public async Task Fixes)>> GetFixesForDiagnosticsAsync( Document document, TextSpan span, ImmutableArray diagnostics, int maxResultsPerDiagnostic, - ISymbolSearchService symbolSearchService, bool searchReferenceAssemblies, + ISymbolSearchService symbolSearchService, AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken) { // We might have multiple different diagnostics covering the same span. Have to @@ -506,7 +506,7 @@ private static bool NotNull(SymbolReference reference) var fixes = await GetFixesAsync( document, span, diagnostic.Id, maxResultsPerDiagnostic, allowInHiddenRegions, - symbolSearchService, searchReferenceAssemblies, + symbolSearchService, options, packageSources, cancellationToken).ConfigureAwait(false); fixesForDiagnosticBuilder.Add((diagnostic, fixes)); @@ -517,7 +517,7 @@ private static bool NotNull(SymbolReference reference) public async Task> GetUniqueFixesAsync( Document document, TextSpan span, ImmutableArray diagnosticIds, - ISymbolSearchService symbolSearchService, bool searchReferenceAssemblies, + ISymbolSearchService symbolSearchService, AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken) { var client = await RemoteHostClient.TryGetClientAsync(document.Project, cancellationToken).ConfigureAwait(false); @@ -526,7 +526,7 @@ public async Task> GetUniqueFixesAsync( var result = await client.TryInvokeAsync>( document.Project.Solution, (service, solutionInfo, callbackId, cancellationToken) => - service.GetUniqueFixesAsync(solutionInfo, callbackId, document.Id, span, diagnosticIds, searchReferenceAssemblies, packageSources, cancellationToken), + service.GetUniqueFixesAsync(solutionInfo, callbackId, document.Id, span, diagnosticIds, options, packageSources, cancellationToken), callbackTarget: symbolSearchService, cancellationToken).ConfigureAwait(false); @@ -535,7 +535,7 @@ public async Task> GetUniqueFixesAsync( return await GetUniqueFixesAsyncInCurrentProcessAsync( document, span, diagnosticIds, - symbolSearchService, searchReferenceAssemblies, + symbolSearchService, options, packageSources, cancellationToken).ConfigureAwait(false); } @@ -544,7 +544,7 @@ private async Task> GetUniqueFixesAsyncInCurren TextSpan span, ImmutableArray diagnosticIds, ISymbolSearchService symbolSearchService, - bool searchReferenceAssemblies, + AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken) { @@ -561,7 +561,7 @@ private async Task> GetUniqueFixesAsyncInCurren .GroupBy(diagnostic => diagnostic.Location.SourceSpan) .Select(diagnosticsForSourceSpan => GetFixesForDiagnosticsAsync( document, diagnosticsForSourceSpan.Key, diagnosticsForSourceSpan.AsImmutable(), - maxResultsPerDiagnostic: 2, symbolSearchService, searchReferenceAssemblies, packageSources, cancellationToken)); + maxResultsPerDiagnostic: 2, symbolSearchService, options, packageSources, cancellationToken)); using var _ = ArrayBuilder.GetInstance(out var fixes); foreach (var getFixesForDiagnosticsTask in getFixesForDiagnosticsTasks) diff --git a/src/Features/Core/Portable/AddImport/IAddImportFeatureService.cs b/src/Features/Core/Portable/AddImport/IAddImportFeatureService.cs index d46eae6061bea..c4cec9de43066 100644 --- a/src/Features/Core/Portable/AddImport/IAddImportFeatureService.cs +++ b/src/Features/Core/Portable/AddImport/IAddImportFeatureService.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; +using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; @@ -13,6 +14,11 @@ namespace Microsoft.CodeAnalysis.AddImport { + [DataContract] + internal readonly record struct AddImportOptions( + [property: DataMember(Order = 0)] bool SearchReferenceAssemblies, + [property: DataMember(Order = 1)] bool HideAdvancedMembers); + internal interface IAddImportFeatureService : ILanguageService { /// @@ -22,7 +28,7 @@ internal interface IAddImportFeatureService : ILanguageService Task> GetFixesAsync( Document document, TextSpan span, string diagnosticId, int maxResults, bool allowInHiddenRegions, - ISymbolSearchService symbolSearchService, bool searchReferenceAssemblies, + ISymbolSearchService symbolSearchService, AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken); /// @@ -31,7 +37,7 @@ Task> GetFixesAsync( /// Task Fixes)>> GetFixesForDiagnosticsAsync( Document document, TextSpan span, ImmutableArray diagnostics, int maxResultsPerDiagnostic, - ISymbolSearchService symbolSearchService, bool searchReferenceAssemblies, + ISymbolSearchService symbolSearchService, AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken); /// @@ -44,12 +50,12 @@ ImmutableArray GetCodeActionsForFixes( /// /// Gets data for how to fix a particular id within the specified Document. - /// Similar to + /// Similar to /// except it only returns fix data when there is a single using fix for a given span /// Task> GetUniqueFixesAsync( Document document, TextSpan span, ImmutableArray diagnosticIds, - ISymbolSearchService symbolSearchService, bool searchReferenceAssemblies, + ISymbolSearchService symbolSearchService, AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/AddImport/Remote/IRemoteMissingImportDiscoveryService.cs b/src/Features/Core/Portable/AddImport/Remote/IRemoteMissingImportDiscoveryService.cs index 58e4d3b03b9af..31e5cb5ef3e0c 100644 --- a/src/Features/Core/Portable/AddImport/Remote/IRemoteMissingImportDiscoveryService.cs +++ b/src/Features/Core/Portable/AddImport/Remote/IRemoteMissingImportDiscoveryService.cs @@ -25,9 +25,10 @@ internal interface ICallback ValueTask> GetFixesAsync( PinnedSolutionInfo solutionInfo, RemoteServiceCallbackId callbackId, DocumentId documentId, TextSpan span, string diagnosticId, int maxResults, - bool allowInHiddenRegions, bool searchReferenceAssemblies, ImmutableArray packageSources, CancellationToken cancellationToken); + bool allowInHiddenRegions, AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken); + ValueTask> GetUniqueFixesAsync( PinnedSolutionInfo solutionInfo, RemoteServiceCallbackId callbackId, DocumentId id, TextSpan span, ImmutableArray diagnosticIds, - bool searchReferenceAssemblies, ImmutableArray packageSources, CancellationToken cancellationToken); + AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs index e5ef181bb091e..d85f70bf82b99 100644 --- a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs +++ b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs @@ -39,15 +39,17 @@ private partial class SymbolReferenceFinder private readonly SyntaxNode _node; private readonly ISymbolSearchService _symbolSearchService; - private readonly bool _searchReferenceAssemblies; + private readonly AddImportOptions _options; private readonly ImmutableArray _packageSources; public SymbolReferenceFinder( AbstractAddImportFeatureService owner, - Document document, SemanticModel semanticModel, - string diagnosticId, SyntaxNode node, + Document document, + SemanticModel semanticModel, + string diagnosticId, + SyntaxNode node, ISymbolSearchService symbolSearchService, - bool searchReferenceAssemblies, + AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken) { @@ -58,10 +60,10 @@ public SymbolReferenceFinder( _node = node; _symbolSearchService = symbolSearchService; - _searchReferenceAssemblies = searchReferenceAssemblies; + _options = options; _packageSources = packageSources; - if (_searchReferenceAssemblies || packageSources.Length > 0) + if (options.SearchReferenceAssemblies || packageSources.Length > 0) { Contract.ThrowIfNull(symbolSearchService); } @@ -217,14 +219,13 @@ private async Task> GetReferencesForMatchingType var typeSymbols = OfType(symbols); - var hideAdvancedMembers = _document.Project.Solution.Options.GetOption(CompletionOptions.Metadata.HideAdvancedMembers, _document.Project.Language); var editorBrowserInfo = new EditorBrowsableInfo(_semanticModel.Compilation); // Only keep symbols which are accessible from the current location and that are allowed by the current // editor browsable rules. var accessibleTypeSymbols = typeSymbols.WhereAsArray( s => ArityAccessibilityAndAttributeContextAreCorrect(s.Symbol, arity, inAttributeContext, hasIncompleteParentMember, looksGeneric) && - s.Symbol.IsEditorBrowsable(hideAdvancedMembers, _semanticModel.Compilation, editorBrowserInfo)); + s.Symbol.IsEditorBrowsable(_options.HideAdvancedMembers, _semanticModel.Compilation, editorBrowserInfo)); // These types may be contained within namespaces, or they may be nested // inside generic types. Record these namespaces/types if it would be diff --git a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder_PackageAssemblySearch.cs b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder_PackageAssemblySearch.cs index 293fafcd0faaa..cc556990f14e1 100644 --- a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder_PackageAssemblySearch.cs +++ b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder_PackageAssemblySearch.cs @@ -66,7 +66,7 @@ private async Task FindNugetOrReferenceAssemblyTypeReferencesWorkerAsync( ArrayBuilder allReferences, TSimpleNameSyntax nameNode, string name, int arity, bool isAttributeSearch, CancellationToken cancellationToken) { - if (_searchReferenceAssemblies) + if (_options.SearchReferenceAssemblies) { cancellationToken.ThrowIfCancellationRequested(); await FindReferenceAssemblyTypeReferencesAsync( diff --git a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsFeatureService.cs b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsFeatureService.cs index 55d6bdcacbbb5..de18a5ca7b3e5 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsFeatureService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsFeatureService.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Options; @@ -28,9 +29,9 @@ internal abstract class AbstractAddMissingImportsFeatureService : IAddMissingImp protected abstract ImmutableArray FixableDiagnosticIds { get; } /// - public async Task AddMissingImportsAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken) + public async Task AddMissingImportsAsync(Document document, TextSpan textSpan, AddMissingImportsOptions options, CancellationToken cancellationToken) { - var analysisResult = await AnalyzeAsync(document, textSpan, cancellationToken).ConfigureAwait(false); + var analysisResult = await AnalyzeAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false); return await AddMissingImportsAsync(document, analysisResult, cancellationToken).ConfigureAwait(false); } @@ -48,7 +49,7 @@ public async Task AddMissingImportsAsync(Document document, AddMissing } /// - public async Task AnalyzeAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken) + public async Task AnalyzeAsync(Document document, TextSpan textSpan, AddMissingImportsOptions options, CancellationToken cancellationToken) { // Get the diagnostics that indicate a missing import. var addImportFeatureService = document.GetRequiredLanguageService(); @@ -59,9 +60,13 @@ public async Task AnalyzeAsync(Document documen // Since we are not currently considering NuGet packages, pass an empty array var packageSources = ImmutableArray.Empty; + var addImportOptions = new AddImportOptions( + SearchReferenceAssemblies: true, + HideAdvancedMembers: options.HideAdvancedMembers); + var unambiguousFixes = await addImportFeatureService.GetUniqueFixesAsync( document, textSpan, FixableDiagnosticIds, symbolSearchService, - searchReferenceAssemblies: true, packageSources, cancellationToken).ConfigureAwait(false); + addImportOptions, packageSources, cancellationToken).ConfigureAwait(false); // We do not want to add project or framework references without the user's input, so filter those out. var usableFixes = unambiguousFixes.WhereAsArray(fixData => DoesNotAddReference(fixData, document.Project.Id)); diff --git a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs index 1917ba0a01f11..c08082bd87f50 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.PasteTracking; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -36,7 +37,10 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte // Check pasted text span for missing imports var addMissingImportsService = document.GetLanguageService(); - var analysis = await addMissingImportsService.AnalyzeAsync(document, textSpan, cancellationToken).ConfigureAwait(false); + var options = new AddMissingImportsOptions( + HideAdvancedMembers: document.Project.Solution.Options.GetOption(CompletionOptions.Metadata.HideAdvancedMembers, document.Project.Language)); + + var analysis = await addMissingImportsService.AnalyzeAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false); if (!analysis.CanAddMissingImports) { return; diff --git a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/IAddMissingImportsFeatureService.cs b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/IAddMissingImportsFeatureService.cs index a05c56f33d20e..3250f12d3e84b 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/IAddMissingImportsFeatureService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/IAddMissingImportsFeatureService.cs @@ -2,6 +2,7 @@ // 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.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; @@ -9,6 +10,10 @@ namespace Microsoft.CodeAnalysis.AddMissingImports { + [DataContract] + internal readonly record struct AddMissingImportsOptions( + [property: DataMember(Order = 0)] bool HideAdvancedMembers); + internal interface IAddMissingImportsFeatureService : ILanguageService { /// @@ -17,15 +22,15 @@ internal interface IAddMissingImportsFeatureService : ILanguageService /// if there are ambiguous imports, no known resolutions to import, or if no imports that would be provided /// would be added without adding a reference for the project. /// - Task AddMissingImportsAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken); + Task AddMissingImportsAsync(Document document, TextSpan textSpan, AddMissingImportsOptions options, CancellationToken cancellationToken); /// /// Analyzes the document inside the texstpan to determine if imports can be added. /// - Task AnalyzeAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken); + Task AnalyzeAsync(Document document, TextSpan textSpan, AddMissingImportsOptions options, CancellationToken cancellationToken); /// - /// Performs the same action as but + /// Performs the same action as but /// with a predetermined analysis of the input instead of recalculating it /// Task AddMissingImportsAsync(Document document, AddMissingImportsAnalysisResult analysisResult, CancellationToken cancellationToken); diff --git a/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs b/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs index 7ba03575fce08..3b5d01e93d959 100644 --- a/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs +++ b/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs @@ -63,9 +63,10 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) return; } + var hideAdvancedMembers = document.Project.Solution.Options.GetOption(CompletionOptions.Metadata.HideAdvancedMembers, document.Project.Language); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var matchingTypes = await GetMatchingTypesAsync(document, semanticModel, node, cancellationToken).ConfigureAwait(false); + var matchingTypes = await GetMatchingTypesAsync(document, semanticModel, node, hideAdvancedMembers, cancellationToken).ConfigureAwait(false); var matchingNamespaces = await GetMatchingNamespacesAsync(project, semanticModel, node, cancellationToken).ConfigureAwait(false); if (matchingTypes.IsEmpty && matchingNamespaces.IsEmpty) @@ -147,7 +148,7 @@ private async Task ProcessNodeAsync(Document document, SyntaxNode node } private async Task> GetMatchingTypesAsync( - Document document, SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken) + Document document, SemanticModel semanticModel, SyntaxNode node, bool hideAdvancedMembers, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -171,8 +172,6 @@ private async Task> GetMatchingTypesAsync( symbols = symbols.Concat(attributeSymbols); } - var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); - var hideAdvancedMembers = options.GetOption(CompletionOptions.Metadata.HideAdvancedMembers); var editorBrowserInfo = new EditorBrowsableInfo(semanticModel.Compilation); var validSymbols = symbols diff --git a/src/Workspaces/Remote/ServiceHub/Services/MissingImportDiscovery/RemoteMissingImportDiscoveryService.cs b/src/Workspaces/Remote/ServiceHub/Services/MissingImportDiscovery/RemoteMissingImportDiscoveryService.cs index 13540f3c42b0c..ddf96fd968acc 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/MissingImportDiscovery/RemoteMissingImportDiscoveryService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/MissingImportDiscovery/RemoteMissingImportDiscoveryService.cs @@ -39,7 +39,7 @@ public ValueTask> GetFixesAsync( string diagnosticId, int maxResults, bool allowInHiddenRegions, - bool searchReferenceAssemblies, + AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken) { @@ -55,7 +55,7 @@ public ValueTask> GetFixesAsync( var result = await service.GetFixesAsync( document, span, diagnosticId, maxResults, allowInHiddenRegions, - symbolSearchService, searchReferenceAssemblies, + symbolSearchService, options, packageSources, cancellationToken).ConfigureAwait(false); return result; @@ -68,7 +68,7 @@ public ValueTask> GetUniqueFixesAsync( DocumentId documentId, TextSpan span, ImmutableArray diagnosticIds, - bool searchReferenceAssemblies, + AddImportOptions options, ImmutableArray packageSources, CancellationToken cancellationToken) { @@ -83,7 +83,7 @@ public ValueTask> GetUniqueFixesAsync( var result = await service.GetUniqueFixesAsync( document, span, diagnosticIds, - symbolSearchService, searchReferenceAssemblies, + symbolSearchService, options, packageSources, cancellationToken).ConfigureAwait(false); return result; From 4d443fe9a91ca386f7e77ba19678f90f0585f94f Mon Sep 17 00:00:00 2001 From: tmat Date: Sun, 9 Jan 2022 20:51:25 -0800 Subject: [PATCH 2/5] 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; } From a2a89ee300e1cdba3a9af9bd05d88072c70ce79c Mon Sep 17 00:00:00 2001 From: tmat Date: Mon, 10 Jan 2022 09:48:26 -0800 Subject: [PATCH 3/5] Fix tests --- .../CSharpTest/AddUsing/AddUsingTests.cs | 7 +-- .../FullyQualify/FullyQualifyTests.cs | 6 +-- .../CodeActions/CodeActionOptionsFactory.cs | 3 +- .../AbstractCodeActionOrUserDiagnosticTest.cs | 26 +++++---- ...agnosticProviderBasedUserDiagnosticTest.cs | 2 +- .../AbstractSuppressionDiagnosticTest.cs | 2 +- ...ractUnncessarySuppressionDiagnosticTest.cs | 2 +- .../Diagnostics/AbstractUserDiagnosticTest.cs | 53 +++++++------------ .../AbstractFullyQualifyCodeFixProvider.cs | 2 +- .../Portable/CodeActions/CodeActionOptions.cs | 1 - 10 files changed, 48 insertions(+), 56 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/AddUsing/AddUsingTests.cs b/src/EditorFeatures/CSharpTest/AddUsing/AddUsingTests.cs index b880fd532cebf..8139305e4ba92 100644 --- a/src/EditorFeatures/CSharpTest/AddUsing/AddUsingTests.cs +++ b/src/EditorFeatures/CSharpTest/AddUsing/AddUsingTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; @@ -6503,7 +6504,7 @@ static void Main(string[] args) [WorkItem(1266354, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1266354")] public async Task TestAddUsingsEditorBrowsableAdvancedDifferentProjectOptionOff(TestHost testHost) { - const string InitialWorkspace = @" + var initialWorkspace = @" @@ -6529,8 +6530,8 @@ static void Main(string[] args) "; - await TestMissingAsync(InitialWorkspace, new TestParameters( - options: Option(CompletionOptions.Metadata.HideAdvancedMembers, true), + await TestMissingAsync(initialWorkspace, new TestParameters( + codeActionOptions: CodeActionOptions.Default with { HideAdvancedMembers = true }, testHost: testHost)); } } diff --git a/src/EditorFeatures/CSharpTest/FullyQualify/FullyQualifyTests.cs b/src/EditorFeatures/CSharpTest/FullyQualify/FullyQualifyTests.cs index 06c437d0a5d95..68f5385c5b729 100644 --- a/src/EditorFeatures/CSharpTest/FullyQualify/FullyQualifyTests.cs +++ b/src/EditorFeatures/CSharpTest/FullyQualify/FullyQualifyTests.cs @@ -1618,7 +1618,7 @@ static void Main(string[] args) [WorkItem(54544, "https://github.com/dotnet/roslyn/issues/54544")] public async Task TestAddUsingsEditorBrowsableAdvancedDifferentProjectOptionOff() { - const string InitialWorkspace = @" + var initialWorkspace = @" @@ -1644,8 +1644,8 @@ static void Main(string[] args) "; - await TestMissingAsync(InitialWorkspace, new TestParameters( - options: Option(CompletionOptions.Metadata.HideAdvancedMembers, true))); + await TestMissingAsync(initialWorkspace, new TestParameters( + codeActionOptions: CodeActionOptions.Default with { HideAdvancedMembers = true })); } } } diff --git a/src/EditorFeatures/Core/Implementation/CodeActions/CodeActionOptionsFactory.cs b/src/EditorFeatures/Core/Implementation/CodeActions/CodeActionOptionsFactory.cs index 7b696b104cb46..c3e84d80f354a 100644 --- a/src/EditorFeatures/Core/Implementation/CodeActions/CodeActionOptionsFactory.cs +++ b/src/EditorFeatures/Core/Implementation/CodeActions/CodeActionOptionsFactory.cs @@ -2,6 +2,7 @@ // 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.Completion; using Microsoft.CodeAnalysis.SymbolSearch; namespace Microsoft.CodeAnalysis.CodeActions @@ -16,7 +17,7 @@ internal static CodeActionOptions GetCodeActionOptions(Project project, bool isB return new( IsBlocking: isBlocking, SearchReferenceAssemblies: options.GetOption(SymbolSearchOptions.SuggestForTypesInReferenceAssemblies, language), - HideAdvancedMembers: options.GetOption(CodeAnalysis.Completion.CompletionOptions.Metadata.HideAdvancedMembers, language)); + HideAdvancedMembers: options.GetOption(CompletionOptions.Metadata.HideAdvancedMembers, language)); } } } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs index 255c1149b57f6..35d68193e2611 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs @@ -47,6 +47,7 @@ public abstract partial class AbstractCodeActionOrUserDiagnosticTest { public struct TestParameters { + internal readonly CodeActionOptions codeActionOptions; internal readonly OptionsCollection options; internal readonly TestHost testHost; internal readonly string workspaceKind; @@ -63,6 +64,7 @@ internal TestParameters( ParseOptions parseOptions = null, CompilationOptions compilationOptions = null, OptionsCollection options = null, + CodeActionOptions? codeActionOptions = null, object fixProviderData = null, int index = 0, CodeActionPriority? priority = null, @@ -75,6 +77,7 @@ internal TestParameters( this.parseOptions = parseOptions; this.compilationOptions = compilationOptions; this.options = options; + this.codeActionOptions = codeActionOptions ?? CodeActionOptions.Default; this.fixProviderData = fixProviderData; this.index = index; this.priority = priority; @@ -86,28 +89,31 @@ internal TestParameters( } public TestParameters WithParseOptions(ParseOptions parseOptions) - => new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithCompilationOptions(CompilationOptions compilationOptions) - => new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); internal TestParameters WithOptions(OptionsCollection options) - => new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + + internal TestParameters WithCodeActionOptions(CodeActionOptions codeActionOptions) + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithFixProviderData(object fixProviderData) - => new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithIndex(int index) - => new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithRetainNonFixableDiagnostics(bool retainNonFixableDiagnostics) - => new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithIncludeDiagnosticsOutsideSelection(bool includeDiagnosticsOutsideSelection) - => new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithWorkspaceKind(string workspaceKind) - => new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); } #pragma warning disable IDE0052 // Remove unread private members (unused when CODE_STYLE is set) @@ -379,7 +385,7 @@ internal Task TestInRegularAndScriptAsync( { return TestInRegularAndScript1Async( initialMarkup, expectedMarkup, index, - new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, title: title, testHost: testHost)); + new TestParameters(parseOptions, compilationOptions, options, CodeActionOptions.Default, fixProviderData, index, priority, title: title, testHost: testHost)); } internal Task TestInRegularAndScript1Async( @@ -419,7 +425,7 @@ internal Task TestAsync( return TestAsync( initialMarkup, expectedMarkup, - new TestParameters(parseOptions, compilationOptions, options, fixProviderData, index, priority, testHost: testHost)); + new TestParameters(parseOptions, compilationOptions, options, CodeActionOptions.Default, fixProviderData, index, priority, testHost: testHost)); } private async Task TestAsync( diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractDiagnosticProviderBasedUserDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractDiagnosticProviderBasedUserDiagnosticTest.cs index ccdb7364ed8fc..70647df757344 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractDiagnosticProviderBasedUserDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractDiagnosticProviderBasedUserDiagnosticTest.cs @@ -166,7 +166,7 @@ internal override async Task> GetDiagnosticsAsync( var ids = new HashSet(fixer.FixableDiagnosticIds); var dxs = diagnostics.Where(d => ids.Contains(d.Id)).ToList(); var (resultDiagnostics, codeActions, actionToInvoke) = await GetDiagnosticAndFixesAsync( - dxs, fixer, testDriver, document, span, annotation, parameters.index); + dxs, fixer, testDriver, document, span, parameters.codeActionOptions, annotation, parameters.index); // If we are also testing non-fixable diagnostics, // then the result diagnostics need to include all diagnostics, diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionDiagnosticTest.cs index 3809f0ddb1021..153893ffa064d 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionDiagnosticTest.cs @@ -98,7 +98,7 @@ internal override async Task> GetDiagnosticsAsync( var wrapperCodeFixer = new WrapperCodeFixProvider(fixer, filteredDiagnostics.Select(d => d.Id)); return await GetDiagnosticAndFixesAsync( filteredDiagnostics, wrapperCodeFixer, testDriver, document, - span, annotation, parameters.index); + span, CodeActionOptions.Default, annotation, parameters.index); } } } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUnncessarySuppressionDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUnncessarySuppressionDiagnosticTest.cs index 815643c37d0a3..dde2727fe3d0c 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUnncessarySuppressionDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUnncessarySuppressionDiagnosticTest.cs @@ -63,7 +63,7 @@ internal override async Task> GetDiagnosticsAsync( return await GetDiagnosticAndFixesAsync( diagnostics, CodeFixProvider, testDriver, document, - span, annotation, parameters.index); + span, CodeActionOptions.Default, annotation, parameters.index); } } } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs index e658351e39cc3..4a5445c0d774d 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs @@ -172,6 +172,7 @@ protected static Document GetDocumentAndAnnotatedSpan(TestWorkspace workspace, o TestDiagnosticAnalyzerDriver testDriver, Document document, TextSpan span, + CodeActionOptions options, string annotation, int index) { @@ -181,20 +182,6 @@ protected static Document GetDocumentAndAnnotatedSpan(TestWorkspace workspace, o } var scope = GetFixAllScope(annotation); - return await GetDiagnosticAndFixesAsync( - diagnostics, fixer, testDriver, document, span, scope, index); - } - - private async Task<(ImmutableArray, ImmutableArray, CodeAction actionToinvoke)> GetDiagnosticAndFixesAsync( - IEnumerable diagnostics, - CodeFixProvider fixer, - TestDiagnosticAnalyzerDriver testDriver, - Document document, - TextSpan span, - FixAllScope? scope, - int index) - { - Assert.NotEmpty(diagnostics); var intersectingDiagnostics = diagnostics.Where(d => d.Location.SourceSpan.IntersectsWith(span)) .ToImmutableArray(); @@ -204,8 +191,11 @@ protected static Document GetDocumentAndAnnotatedSpan(TestWorkspace workspace, o foreach (var diagnostic in intersectingDiagnostics) { var context = new CodeFixContext( - document, diagnostic, + document, + diagnostic.Location.SourceSpan, + ImmutableArray.Create(diagnostic), (a, d) => fixes.Add(new CodeFix(document.Project, a, d)), + options, CancellationToken.None); await fixer.RegisterCodeFixesAsync(context); @@ -213,34 +203,29 @@ protected static Document GetDocumentAndAnnotatedSpan(TestWorkspace workspace, o VerifyCodeActionsRegisteredByProvider(fixer, fixes); - var actions = fixes.SelectAsArray(f => f.Action); - - actions = MassageActions(actions); + var actions = MassageActions(fixes.SelectAsArray(f => f.Action)); if (scope == null) { // Simple code fix. return (intersectingDiagnostics, actions, actions.Length == 0 ? null : actions[index]); } - else - { - var equivalenceKey = actions[index].EquivalenceKey; + var equivalenceKey = actions[index].EquivalenceKey; - // Fix all fix. - var fixAllProvider = fixer.GetFixAllProvider(); - Assert.NotNull(fixAllProvider); + // Fix all fix. + var fixAllProvider = fixer.GetFixAllProvider(); + Assert.NotNull(fixAllProvider); - var fixAllState = GetFixAllState( - fixAllProvider, diagnostics, fixer, testDriver, document, - scope.Value, equivalenceKey); - var fixAllContext = new FixAllContext(fixAllState, new ProgressTracker(), CancellationToken.None); - var fixAllFix = await fixAllProvider.GetFixAsync(fixAllContext); + var fixAllState = GetFixAllState( + fixAllProvider, diagnostics, fixer, testDriver, document, + scope.Value, equivalenceKey); + var fixAllContext = new FixAllContext(fixAllState, new ProgressTracker(), CancellationToken.None); + var fixAllFix = await fixAllProvider.GetFixAsync(fixAllContext); - // We have collapsed the fixes down to the single fix-all fix, so we just let our - // caller know they should pull that entry out of the result. - return (intersectingDiagnostics, ImmutableArray.Create(fixAllFix), fixAllFix); - } + // We have collapsed the fixes down to the single fix-all fix, so we just let our + // caller know they should pull that entry out of the result. + return (intersectingDiagnostics, ImmutableArray.Create(fixAllFix), fixAllFix); } private static FixAllState GetFixAllState( @@ -280,7 +265,7 @@ private protected Task TestActionCountInAllFixesAsync( { return TestActionCountInAllFixesAsync( initialMarkup, - new TestParameters(parseOptions, compilationOptions, options, fixProviderData), + new TestParameters(parseOptions, compilationOptions, options, CodeActionOptions.Default, fixProviderData), count); } diff --git a/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs b/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs index 3b5d01e93d959..9fb65c4415f99 100644 --- a/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs +++ b/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs @@ -63,7 +63,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) return; } - var hideAdvancedMembers = document.Project.Solution.Options.GetOption(CompletionOptions.Metadata.HideAdvancedMembers, document.Project.Language); + var hideAdvancedMembers = context.Options.HideAdvancedMembers; var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var matchingTypes = await GetMatchingTypesAsync(document, semanticModel, node, hideAdvancedMembers, cancellationToken).ConfigureAwait(false); diff --git a/src/Workspaces/Core/Portable/CodeActions/CodeActionOptions.cs b/src/Workspaces/Core/Portable/CodeActions/CodeActionOptions.cs index 4faf8c7096fb7..c26901b5feda9 100644 --- a/src/Workspaces/Core/Portable/CodeActions/CodeActionOptions.cs +++ b/src/Workspaces/Core/Portable/CodeActions/CodeActionOptions.cs @@ -16,6 +16,5 @@ internal readonly record struct CodeActionOptions( IsBlocking: false, SearchReferenceAssemblies: true, HideAdvancedMembers: false); - } } From ac16f375ea34a310a8389c963ae98fdc823576e4 Mon Sep 17 00:00:00 2001 From: tmat Date: Mon, 10 Jan 2022 13:33:20 -0800 Subject: [PATCH 4/5] Fix --- .../CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs index 35d68193e2611..8192887e6048b 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs @@ -113,7 +113,7 @@ public TestParameters WithIncludeDiagnosticsOutsideSelection(bool includeDiagnos => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithWorkspaceKind(string workspaceKind) - => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, codeActionOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); } #pragma warning disable IDE0052 // Remove unread private members (unused when CODE_STYLE is set) From 0fa2dedde8694b39696b476bea67f8e82b46ea41 Mon Sep 17 00:00:00 2001 From: tmat Date: Tue, 18 Jan 2022 12:49:48 -0800 Subject: [PATCH 5/5] Fix --- .../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 ffe511d2f93da..017f4900378d5 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -614,7 +614,7 @@ private void OnSuggestedActionsChanged(Workspace currentWorkspace, DocumentId? c if (document == null) return null; - var options = CodeActionOptionsFactory.GetCodeActionOptions(document.Project, isBlocking: true); + var options = CodeActionOptionsFactory.GetCodeActionOptions(document.Project, isBlocking: false); using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); var linkedToken = linkedTokenSource.Token;