public async Task <object> HandleRequestAsync(LSP.ExecuteCommandParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var runRequest = ((JToken)request.Arguments.Single()).ToObject <CodeActionResolveData>();
            var document   = _solutionProvider.GetDocument(runRequest.TextDocument);

            Contract.ThrowIfNull(document);

            var codeActions = await CodeActionHelpers.GetCodeActionsAsync(
                _codeActionsCache, document, runRequest.Range, _codeFixService, _codeRefactoringService, cancellationToken).ConfigureAwait(false);

            var actionToRun = CodeActionHelpers.GetCodeActionToResolve(runRequest.UniqueIdentifier, codeActions);

            Contract.ThrowIfNull(actionToRun);

            var operations = await actionToRun.GetOperationsAsync(cancellationToken).ConfigureAwait(false);

            // TODO - This UI thread dependency should be removed.
            // https://github.com/dotnet/roslyn/projects/45#card-20619668
            await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

            foreach (var operation in operations)
            {
                operation.Apply(document.Project.Solution.Workspace, cancellationToken);
            }

            return(true);
        }
Exemple #2
0
        public override async Task <LSP.VSCodeAction> HandleRequestAsync(LSP.VSCodeAction codeAction, RequestContext context, CancellationToken cancellationToken)
        {
            var data     = ((JToken)codeAction.Data).ToObject <CodeActionResolveData>();
            var document = SolutionProvider.GetDocument(data.TextDocument, context.ClientName);

            Contract.ThrowIfNull(document);

            var codeActions = await CodeActionHelpers.GetCodeActionsAsync(
                document,
                _codeFixService,
                _codeRefactoringService,
                _threadingContext,
                data.Range,
                cancellationToken).ConfigureAwait(false);

            var codeActionToResolve = CodeActionHelpers.GetCodeActionToResolve(
                data.UniqueIdentifier, codeActions);

            Contract.ThrowIfNull(codeActionToResolve);

            var operations = await codeActionToResolve.GetOperationsAsync(cancellationToken).ConfigureAwait(false);

            if (operations.IsEmpty)
            {
                return(codeAction);
            }

            // If we have all non-ApplyChangesOperations, set up to run as command on the server
            // instead of using WorkspaceEdits.
            if (operations.All(operation => !(operation is ApplyChangesOperation)))
            {
                codeAction.Command = SetCommand(codeAction.Title, data);
                return(codeAction);
            }

            // TO-DO: We currently must execute code actions which add new documents on the server as commands,
            // since there is no LSP support for adding documents yet. In the future, we should move these actions
            // to execute on the client.
            // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1147293/

            // Add workspace edits
            var applyChangesOperations = operations.OfType <ApplyChangesOperation>();

            if (applyChangesOperations.Any())
            {
                using var _ = ArrayBuilder <TextDocumentEdit> .GetInstance(out var textDocumentEdits);

                foreach (var applyChangesOperation in applyChangesOperations)
                {
                    var solution       = document.Project.Solution;
                    var changes        = applyChangesOperation.ChangedSolution.GetChanges(solution);
                    var projectChanges = changes.GetProjectChanges();

                    // TO-DO: If the change involves adding or removing a document, execute via command instead of WorkspaceEdit
                    // until adding/removing documents is supported in LSP: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1147293/
                    // After support is added, remove the below if-statement and add code to support adding/removing documents.
                    var addedDocuments = projectChanges.SelectMany(
                        pc => pc.GetAddedDocuments().Concat(pc.GetAddedAdditionalDocuments().Concat(pc.GetAddedAnalyzerConfigDocuments())));
                    var removedDocuments = projectChanges.SelectMany(
                        pc => pc.GetRemovedDocuments().Concat(pc.GetRemovedAdditionalDocuments().Concat(pc.GetRemovedAnalyzerConfigDocuments())));
                    if (addedDocuments.Any() || removedDocuments.Any())
                    {
                        codeAction.Command = SetCommand(codeAction.Title, data);
                        return(codeAction);
                    }

                    // TO-DO: If the change involves adding or removing a project reference, execute via command instead of
                    // WorkspaceEdit until adding/removing project references is supported in LSP:
                    // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1166040
                    var projectReferences = projectChanges.SelectMany(
                        pc => pc.GetAddedProjectReferences().Concat(pc.GetRemovedProjectReferences()));
                    if (projectReferences.Any())
                    {
                        codeAction.Command = SetCommand(codeAction.Title, data);
                        return(codeAction);
                    }

                    var changedDocuments = projectChanges.SelectMany(pc => pc.GetChangedDocuments());
                    var changedAnalyzerConfigDocuments = projectChanges.SelectMany(pc => pc.GetChangedAnalyzerConfigDocuments());
                    var changedAdditionalDocuments     = projectChanges.SelectMany(pc => pc.GetChangedAdditionalDocuments());

                    // Changed documents
                    await AddTextDocumentEdits(
                        textDocumentEdits, applyChangesOperation, solution, changedDocuments,
                        applyChangesOperation.ChangedSolution.GetDocument, solution.GetDocument,
                        cancellationToken).ConfigureAwait(false);

                    // Changed analyzer config documents
                    await AddTextDocumentEdits(
                        textDocumentEdits, applyChangesOperation, solution, changedAnalyzerConfigDocuments,
                        applyChangesOperation.ChangedSolution.GetAnalyzerConfigDocument, solution.GetAnalyzerConfigDocument,
                        cancellationToken).ConfigureAwait(false);

                    // Changed additional documents
                    await AddTextDocumentEdits(
                        textDocumentEdits, applyChangesOperation, solution, changedAdditionalDocuments,
                        applyChangesOperation.ChangedSolution.GetAdditionalDocument, solution.GetAdditionalDocument,
                        cancellationToken).ConfigureAwait(false);
                }

                codeAction.Edit = new LSP.WorkspaceEdit {
                    DocumentChanges = textDocumentEdits.ToArray()
                };
            }

            return(codeAction);