private bool Execute( ITextBuffer textBuffer, ITextView view, CancellationToken cancellationToken) { var spans = view.Selection.GetSnapshotSpansOnBuffer(textBuffer); if (spans.Count(s => s.Length > 0) != 1) { return(false); } var document = textBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) { return(false); } var options = document.Project.Solution.Workspace.Options; var result = ExtractMethodService.ExtractMethodAsync( document, spans.Single().Span.ToTextSpan(), options, 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, options, result, cancellationToken); if (newResult != null) { var notificationService = document.Project.Solution.Workspace.Services.GetService <INotificationService>(); if (notificationService != null) { if (!notificationService.ConfirmMessageBox( string.Join(Environment.NewLine, result.Reasons) + Environment.NewLine + Environment.NewLine + EditorFeaturesResources.ExtractMethodAsyncErrorFix, EditorFeaturesResources.ExtractMethodFailedReasons, 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)) { // 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); }
private static ExtractMethodResult TryWithoutMakingValueTypesRef( Document document, NormalizedSnapshotSpanCollection spans, ExtractMethodResult result, CancellationToken cancellationToken ) { var options = document.Project.Solution.Options; if ( options.GetOption( ExtractMethodOptions.DontPutOutOrRefOnStruct, document.Project.Language ) || !result.Reasons.IsSingle() ) { return(null); } var reason = result.Reasons.FirstOrDefault(); var length = FeaturesResources.Asynchronous_method_cannot_have_ref_out_parameters_colon_bracket_0_bracket.IndexOf( ':' ); if ( reason != null && length > 0 && reason.IndexOf( FeaturesResources.Asynchronous_method_cannot_have_ref_out_parameters_colon_bracket_0_bracket.Substring( 0, length ), 0, length, StringComparison.Ordinal ) >= 0 ) { options = options.WithChangedOption( ExtractMethodOptions.DontPutOutOrRefOnStruct, document.Project.Language, true ); var newResult = ExtractMethodService .ExtractMethodAsync( document, spans.Single().Span.ToTextSpan(), localFunction: false, options, cancellationToken ) .WaitAndGetResult(cancellationToken); // retry succeeded, return new result if (newResult.Succeeded || newResult.SucceededWithSuggestion) { return(newResult); } } return(null); }
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.GetFullyLoadedOpenDocumentInCurrentContextWithChanges( waitContext, _threadingContext); if (document == null) { return(false); } var result = ExtractMethodService.ExtractMethodAsync( document, spans.Single().Span.ToTextSpan(), localFunction: false, 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); }