Ejemplo n.º 1
0
        private void CommitCore(IUIThreadOperationContext operationContext, bool previewChanges)
        {
            var eventName = previewChanges ? FunctionId.Rename_CommitCoreWithPreview : FunctionId.Rename_CommitCore;

            using (Logger.LogBlock(eventName, KeyValueLogMessage.Create(LogType.UserAction), operationContext.UserCancellationToken))
            {
                var newSolution = _conflictResolutionTask.Join(operationContext.UserCancellationToken).NewSolution;

                if (previewChanges)
                {
                    var previewService = _workspace.Services.GetService <IPreviewDialogService>();

                    operationContext.TakeOwnership();
                    newSolution = previewService.PreviewChanges(
                        string.Format(EditorFeaturesResources.Preview_Changes_0, EditorFeaturesResources.Rename),
                        "vs.csharp.refactoring.rename",
                        string.Format(EditorFeaturesResources.Rename_0_to_1_colon, this.OriginalSymbolName, this.ReplacementText),
                        _renameInfo.FullDisplayName,
                        _renameInfo.Glyph,
                        newSolution,
                        _triggerDocument.Project.Solution);

                    if (newSolution == null)
                    {
                        // User clicked cancel.
                        return;
                    }
                }

                // The user hasn't cancelled by now, so we're done waiting for them. Off to
                // rename!
                using var _ = operationContext.AddScope(allowCancellation: false, EditorFeaturesResources.Updating_files);

                Dismiss(rollbackTemporaryEdits: true);
                CancelAllOpenDocumentTrackingTasks();

                _triggerView.Caret.PositionChanged += LogPositionChanged;

                ApplyRename(newSolution, operationContext);

                LogRenameSession(RenameLogMessage.UserActionOutcome.Committed, previewChanges);

                EndRenameSession();

                _triggerView.Caret.PositionChanged -= LogPositionChanged;

                void LogPositionChanged(object sender, CaretPositionChangedEventArgs e)
                {
                    try
                    {
                        throw new InvalidOperationException("Caret position changed during application of rename");
                    }
                    catch (InvalidOperationException ex) when(FatalError.ReportAndCatch(ex))
                    {
                        // Unreachable code due to ReportAndCatch
                        Contract.ThrowIfTrue(true);
                    }
                }
            }
        }
Ejemplo n.º 2
0
        public void Invoke(IUIThreadOperationContext context)
        {
            // we're going to return immediately from Invoke and kick off our own async work to invoke the
            // code action. Once this returns, the editor will close the threaded wait dialog it created.
            // So we need to take ownership of it and start our own TWD instead to track this.
            context.TakeOwnership();

            _ = InvokeAsync();
        }
Ejemplo n.º 3
0
        /// <returns>
        /// True: if a failure notification was displayed or the user did not want to proceed in a best effort scenario.
        ///       Extract Method does not proceed further and is done.
        /// False: the user proceeded to a best effort scenario.
        /// </returns>
        private bool TryNotifyFailureToUser(Document document, ExtractMethodResult result, IUIThreadOperationContext waitContext)
        {
            // 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.
            waitContext.TakeOwnership();
            var project             = document.Project;
            var solution            = project.Solution;
            var notificationService = solution.Workspace.Services.GetService <INotificationService>();

            // see whether we will allow best effort extraction and if it is possible.
            if (!solution.Options.GetOption(ExtractMethodOptions.AllowBestEffort, project.Language) ||
                !result.Status.HasBestEffort() ||
                result.Document == null)
            {
                if (notificationService != null)
                {
                    notificationService.SendNotification(
                        EditorFeaturesResources.Extract_method_encountered_the_following_issues + Environment.NewLine +
                        string.Join("", result.Reasons.Select(r => Environment.NewLine + "  " + r)),
                        title: EditorFeaturesResources.Extract_Method,
                        severity: NotificationSeverity.Error);
                }

                return(true);
            }

            // okay, best effort is turned on, let user know it is an best effort
            if (notificationService != null)
            {
                if (!notificationService.ConfirmMessageBox(
                        EditorFeaturesResources.Extract_method_encountered_the_following_issues + Environment.NewLine +
                        string.Join("", result.Reasons.Select(r => Environment.NewLine + "  " + r)) + Environment.NewLine + Environment.NewLine +
                        EditorFeaturesResources.Do_you_still_want_to_proceed_This_may_produce_broken_code,
                        title: EditorFeaturesResources.Extract_Method,
                        severity: NotificationSeverity.Warning))
                {
                    return(true);
                }
            }

            return(false);
        }
Ejemplo n.º 4
0
        private void CommitCore(IUIThreadOperationContext operationContext, bool previewChanges)
        {
            var eventName = previewChanges ? FunctionId.Rename_CommitCoreWithPreview : FunctionId.Rename_CommitCore;

            using (Logger.LogBlock(eventName, KeyValueLogMessage.Create(LogType.UserAction), operationContext.UserCancellationToken))
            {
                var newSolution = _conflictResolutionTask.Join(operationContext.UserCancellationToken).NewSolution;

                if (previewChanges)
                {
                    var previewService = _workspace.Services.GetService <IPreviewDialogService>();

                    operationContext.TakeOwnership();
                    newSolution = previewService.PreviewChanges(
                        string.Format(EditorFeaturesResources.Preview_Changes_0, EditorFeaturesResources.Rename),
                        "vs.csharp.refactoring.rename",
                        string.Format(EditorFeaturesResources.Rename_0_to_1_colon, this.OriginalSymbolName, this.ReplacementText),
                        _renameInfo.FullDisplayName,
                        _renameInfo.Glyph,
                        newSolution,
                        _triggerDocument.Project.Solution);

                    if (newSolution == null)
                    {
                        // User clicked cancel.
                        return;
                    }
                }

                // The user hasn't cancelled by now, so we're done waiting for them. Off to
                // rename!
                using var _ = operationContext.AddScope(allowCancellation: false, EditorFeaturesResources.Updating_files);

                Dismiss(rollbackTemporaryEdits: true);
                CancelAllOpenDocumentTrackingTasks();

                ApplyRename(newSolution, operationContext);

                LogRenameSession(RenameLogMessage.UserActionOutcome.Committed, previewChanges);

                EndRenameSession();
            }
        }
Ejemplo n.º 5
0
        private void ApplyRename(Solution newSolution, IUIThreadOperationContext operationContext)
        {
            var changes            = _baseSolution.GetChanges(newSolution);
            var changedDocumentIDs = changes.GetProjectChanges().SelectMany(c => c.GetChangedDocuments()).ToList();

            if (!_renameInfo.TryOnBeforeGlobalSymbolRenamed(_workspace, changedDocumentIDs, this.ReplacementText))
            {
                var notificationService = _workspace.Services.GetService <INotificationService>();
                notificationService.SendNotification(
                    EditorFeaturesResources.Rename_operation_was_cancelled_or_is_not_valid,
                    EditorFeaturesResources.Rename_Symbol,
                    NotificationSeverity.Error);
                return;
            }

            using var undoTransaction = _workspace.OpenGlobalUndoTransaction(EditorFeaturesResources.Inline_Rename);
            var finalSolution = newSolution.Workspace.CurrentSolution;

            foreach (var id in changedDocumentIDs)
            {
                // If the document supports syntax tree, then create the new solution from the
                // updated syntax root.  This should ensure that annotations are preserved, and
                // prevents the solution from having to reparse documents when we already have
                // the trees for them.  If we don't support syntax, then just use the text of
                // the document.
                var newDocument = newSolution.GetDocument(id);

                if (newDocument.SupportsSyntaxTree)
                {
                    // We pass CancellationToken.None here because we don't have a usable token to pass. The IUIThreadOperationContext
                    // passed here as a cancellation token, but the caller in CommitCore has already turned off cancellation
                    // because we're committed to the update at this point. If we ever want to pass cancellation here, we'd want to move this
                    // part back out of this method and before the point where we've already opened a global transaction.
                    var root = newDocument.GetSyntaxRootSynchronously(CancellationToken.None);
                    finalSolution = finalSolution.WithDocumentSyntaxRoot(id, root);
                }
                else
                {
                    var newText = newDocument.GetTextSynchronously(CancellationToken.None);
                    finalSolution = finalSolution.WithDocumentText(id, newText);
                }

                // Make sure to include any document rename as well
                finalSolution = finalSolution.WithDocumentName(id, newDocument.Name);
            }

            if (_workspace.TryApplyChanges(finalSolution))
            {
                // Since rename can apply file changes as well, and those file
                // changes can generate new document ids, include added documents
                // as well as changed documents. This also ensures that any document
                // that was removed is not included
                var finalChanges = _workspace.CurrentSolution.GetChanges(_baseSolution);

                var finalChangedIds = finalChanges
                                      .GetProjectChanges()
                                      .SelectMany(c => c.GetChangedDocuments().Concat(c.GetAddedDocuments()))
                                      .ToList();

                if (!_renameInfo.TryOnAfterGlobalSymbolRenamed(_workspace, finalChangedIds, this.ReplacementText))
                {
                    var notificationService = _workspace.Services.GetService <INotificationService>();
                    operationContext.TakeOwnership();
                    notificationService.SendNotification(
                        EditorFeaturesResources.Rename_operation_was_not_properly_completed_Some_file_might_not_have_been_updated,
                        EditorFeaturesResources.Rename_Symbol,
                        NotificationSeverity.Information);
                }

                undoTransaction.Commit();
            }
        }
Ejemplo n.º 6
0
        private bool Execute(
            ITextBuffer textBuffer,
            ITextView view,
            IUIThreadOperationContext waitContext)
        {
            var cancellationToken = waitContext.UserCancellationToken;

            var spans = view.Selection.GetSnapshotSpansOnBuffer(textBuffer);

            if (spans.Count(s => s.Length > 0) != 1)
            {
                return(false);
            }

            var document = textBuffer.CurrentSnapshot.GetFullyLoadedOpenDocumentInCurrentContextWithChangesAsync(waitContext).WaitAndGetResult(cancellationToken);

            if (document == null)
            {
                return(false);
            }

            var result = ExtractMethodService.ExtractMethodAsync(
                document, spans.Single().Span.ToTextSpan(), cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken);

            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 = TryWithoutMakingValueTypesRef(document, spans, result, cancellationToken);
                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.
                        waitContext.TakeOwnership();
                        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(true);
                        }
                    }

                    // reset result
                    result = newResult;
                }
                else if (TryNotifyFailureToUser(document, result, waitContext))
                {
                    // We handled the command, displayed a notification and did not produce code.
                    return(true);
                }
            }

            // apply the change to buffer
            // get method name token
            ApplyChangesToBuffer(result, textBuffer, cancellationToken);

            // start inline rename
            var methodNameAtInvocation  = result.InvocationNameToken;
            var snapshotAfterFormatting = textBuffer.CurrentSnapshot;
            var documentAfterFormatting = snapshotAfterFormatting.GetOpenDocumentInCurrentContextWithChanges();

            _renameService.StartInlineSession(documentAfterFormatting, methodNameAtInvocation.Span, cancellationToken);

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

            return(true);
        }
Ejemplo n.º 7
0
 static void ShowMessage(string errorMessage, NotificationSeverity severity, IUIThreadOperationContext operationContext, INotificationService notificationService)
 {
     operationContext.TakeOwnership();
     notificationService.SendNotification(errorMessage, severity: severity);
 }
 public void TakeOwnership()
 => _context.TakeOwnership();