private void ApplyChange_OnUIThread(
            Document formattedDocument, ITextBuffer textBuffer, IBackgroundWorkIndicatorContext waitContext)
        {
            _threadingContext.ThrowIfNotOnUIThread();

            var cancellationToken = waitContext.UserCancellationToken;

            using var undoTransaction = _undoManager.GetTextBufferUndoManager(textBuffer).TextBufferUndoHistory.CreateTransaction("Extract Method");

            // We're about to make an edit ourselves.  so disable the cancellation that happens on editing.
            waitContext.CancelOnEdit = false;
            formattedDocument.Project.Solution.Workspace.ApplyDocumentChanges(formattedDocument, cancellationToken);

            // apply changes
            undoTransaction.Complete();
        }
        private async Task ExecuteWorkerAsync(
            ITextView view,
            ITextBuffer textBuffer,
            TextSpan span,
            IBackgroundWorkIndicatorContext waitContext)
        {
            _threadingContext.ThrowIfNotOnUIThread();

            var cancellationToken = waitContext.UserCancellationToken;

            var document = await textBuffer.CurrentSnapshot.GetFullyLoadedOpenDocumentInCurrentContextWithChangesAsync(waitContext).ConfigureAwait(false);

            if (document is null)
            {
                return;
            }

            var options = await document.GetExtractMethodGenerationOptionsAsync(_globalOptions, cancellationToken).ConfigureAwait(false);

            var result = await ExtractMethodService.ExtractMethodAsync(
                document, span, localFunction : false, options, cancellationToken).ConfigureAwait(false);

            Contract.ThrowIfNull(result);

            if (!result.Succeeded && !result.SucceededWithSuggestion)
            {
                // if it failed due to out/ref parameter in async method, try it with different option
                var newResult = await TryWithoutMakingValueTypesRefAsync(
                    document, span, result, options, cancellationToken).ConfigureAwait(false);

                if (newResult != null)
                {
                    var notificationService = document.Project.Solution.Workspace.Services.GetService <INotificationService>();
                    if (notificationService != null)
                    {
                        // We are about to show a modal UI dialog so we should take over the command execution
                        // wait context. That means the command system won't attempt to show its own wait dialog
                        // and also will take it into consideration when measuring command handling duration.
                        await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

                        if (!notificationService.ConfirmMessageBox(
                                EditorFeaturesResources.Extract_method_encountered_the_following_issues + Environment.NewLine + Environment.NewLine +
                                string.Join(Environment.NewLine, result.Reasons) + Environment.NewLine + Environment.NewLine +
                                EditorFeaturesResources.We_can_fix_the_error_by_not_making_struct_out_ref_parameter_s_Do_you_want_to_proceed,
                                title: EditorFeaturesResources.Extract_Method,
                                severity: NotificationSeverity.Error))
                        {
                            // We handled the command, displayed a notification and did not produce code.
                            return;
                        }

                        await TaskScheduler.Default;
                    }

                    // reset result
                    result = newResult;
                }
                else if (await TryNotifyFailureToUserAsync(document, result, cancellationToken).ConfigureAwait(false))
                {
                    // We handled the command, displayed a notification and did not produce code.
                    return;
                }
            }

            var cleanupOptions = await document.GetCodeCleanupOptionsAsync(_globalOptions, cancellationToken).ConfigureAwait(false);

            var(formattedDocument, methodNameAtInvocation) = await result.GetFormattedDocumentAsync(cleanupOptions, cancellationToken).ConfigureAwait(false);

            await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

            ApplyChange_OnUIThread(formattedDocument, textBuffer, waitContext);

            // start inline rename to allow the user to change the name if they want.
            var textSnapshot = textBuffer.CurrentSnapshot;

            document = textSnapshot.GetOpenDocumentInCurrentContextWithChanges();
            if (document != null)
            {
                _renameService.StartInlineSession(document, methodNameAtInvocation.Span, cancellationToken);
            }

            // select invocation span
            view.TryMoveCaretToAndEnsureVisible(new SnapshotPoint(textSnapshot, methodNameAtInvocation.Span.End));
            view.SetSelection(methodNameAtInvocation.Span.ToSnapshotSpan(textSnapshot));
        }