private async Task <ImmutableArray <CodeActionOperation> > GetCodeFixOperationsAsync(
            CodeFixProvider provider,
            Document document,
            TextSpan span,
            ImmutableArray <Diagnostic> diagnostics)
        {
            var codeFixes = new List <CodeAction>();
            var context   = OmniSharpCodeFixContextFactory.CreateCodeFixContext(
                document, span, diagnostics,
                registerCodeFix: (a, d) => codeFixes.Add(a),
                CodeActionOptionsFactory.Create(_options),
                cancellationToken: CancellationToken.None);

            // Note: We're intentionally not checking CodeFixProvider.FixableDiagnosticIds here.
            // The problem is that some providers (like Remove Unnecessary Usings) only listen
            // for custom IDs produced by their associated diagnostic analyzer. Once we have a
            // proper diagnostic engine in OmniSharp, we may be able remove this.

            await provider.RegisterCodeFixesAsync(context);

            var getOperationsTasks = codeFixes
                                     .Select(a => a.GetOperationsAsync(CancellationToken.None));

            // Wait until all tasks to produce CodeActionOperations finish running in parallel.
            await Task.WhenAll(getOperationsTasks);

            return(getOperationsTasks
                   .Select(t => t.Result)
                   .SelectMany(ops => ops)
                   .ToImmutableArray());
        }
            private async IAsyncEnumerable <SuggestedActionSet> GetCodeFixesAndRefactoringsAsync(
                ReferenceCountedDisposable <State> state,
                ISuggestedActionCategorySet requestedActionCategories,
                Document document,
                SnapshotSpan range,
                TextSpan?selection,
                Func <string, IDisposable?> addOperationScope,
                CodeActionRequestPriority priority,
                int currentActionCount,
                [EnumeratorCancellation] CancellationToken cancellationToken)
            {
                var workspace = document.Project.Solution.Workspace;
                var supportsFeatureService = workspace.Services.GetRequiredService <ITextBufferSupportsFeatureService>();

                var options = CodeActionOptionsFactory.GetCodeActionOptions(document.Project, isBlocking: false);

                var fixesTask = GetCodeFixesAsync(
                    state, supportsFeatureService, requestedActionCategories, workspace, document, range,
                    addOperationScope, priority, options, cancellationToken);
                var refactoringsTask = GetRefactoringsAsync(
                    state, supportsFeatureService, requestedActionCategories, GlobalOptions, workspace, document, selection,
                    addOperationScope, priority, options, cancellationToken);

                await Task.WhenAll(fixesTask, refactoringsTask).ConfigureAwait(false);

                var fixes = await fixesTask.ConfigureAwait(false);

                var refactorings = await refactoringsTask.ConfigureAwait(false);

                foreach (var set in ConvertToSuggestedActionSets(state, selection, fixes, refactorings, currentActionCount))
                {
                    yield return(set);
                }
            }
        private async Task AppendFixesAsync(Document document, TextSpan span, IEnumerable <Diagnostic> diagnostics, List <CodeAction> codeActions)
        {
            var codeActionOptions = CodeActionOptionsFactory.Create(Options);

            foreach (var codeFixProvider in GetSortedCodeFixProviders(document))
            {
                var fixableDiagnostics = diagnostics.Where(d => HasFix(codeFixProvider, d.Id)).ToImmutableArray();

                if (fixableDiagnostics.Length > 0)
                {
                    var context = OmniSharpCodeFixContextFactory.CreateCodeFixContext(
                        document,
                        span,
                        fixableDiagnostics,
                        (a, _) => codeActions.Add(a),
                        codeActionOptions,
                        CancellationToken.None);

                    try
                    {
                        await codeFixProvider.RegisterCodeFixesAsync(context);
                    }
                    catch (Exception ex)
                    {
                        this.Logger.LogError(ex, $"Error registering code fixes for {codeFixProvider.GetType().FullName}");
                    }
                }
            }
        }
Exemple #4
0
        private static async Task <CodeRefactoring> GetCodeRefactoringAsync(
            CodeRefactoringProvider provider,
            TestWorkspace workspace)
        {
            var documentsWithSelections = workspace.Documents.Where(d => !d.IsLinkFile && d.SelectedSpans.Count == 1);

            Debug.Assert(documentsWithSelections.Count() == 1, "One document must have a single span annotation");
            var span    = documentsWithSelections.Single().SelectedSpans.Single();
            var actions = ArrayBuilder <(CodeAction, TextSpan?)> .GetInstance();

            var document = workspace.CurrentSolution.GetDocument(documentsWithSelections.Single().Id);
            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;

            actions.Free();
            return(result);
        }
            private ImmutableArray <SuggestedActionSet>?GetSuggestedActions(
                ISuggestedActionCategorySet requestedActionCategories,
                SnapshotSpan range,
                IUIThreadOperationContext?operationContext,
                CancellationToken cancellationToken)
            {
                AssertIsForeground();

                using var state = _state.TryAddReference();
                if (state is null)
                {
                    return(null);
                }

                if (state.Target.Workspace == null)
                {
                    return(null);
                }

                using (operationContext?.AddScope(allowCancellation: true, description: EditorFeaturesResources.Gathering_Suggestions_Waiting_for_the_solution_to_fully_load))
                {
                    // This needs to run under threading context otherwise, we can deadlock on VS
                    var statusService = state.Target.Workspace.Services.GetRequiredService <IWorkspaceStatusService>();
                    ThreadingContext.JoinableTaskFactory.Run(() => statusService.WaitUntilFullyLoadedAsync(cancellationToken));
                }

                using (Logger.LogBlock(FunctionId.SuggestedActions_GetSuggestedActions, cancellationToken))
                {
                    var document = range.Snapshot.GetOpenDocumentInCurrentContextWithChanges();
                    if (document == null)
                    {
                        // this is here to fail test and see why it is failed.
                        Trace.WriteLine("given range is not current");
                        return(null);
                    }

                    var workspace = document.Project.Solution.Workspace;
                    var supportsFeatureService = workspace.Services.GetRequiredService <ITextBufferSupportsFeatureService>();

                    var selection = TryGetCodeRefactoringSelection(state, range);

                    Func <string, IDisposable?> 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,
                        options, cancellationToken);

                    var refactoringsTask = GetRefactoringsAsync(
                        state, supportsFeatureService, requestedActionCategories, GlobalOptions, workspace, document, selection,
                        addOperationScope, CodeActionRequestPriority.None, options, cancellationToken);

                    Task.WhenAll(fixesTask, refactoringsTask).WaitAndGetResult(cancellationToken);

                    return(ConvertToSuggestedActionSets(
                               state, selection,
                               fixesTask.WaitAndGetResult(cancellationToken),
                               refactoringsTask.WaitAndGetResult(cancellationToken),
                               currentActionCount: 0));
                }
            }