示例#1
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            // Don't bother if there isn't a selection
            var(document, textSpan, cancellationToken) = context;
            if (textSpan.IsEmpty)
            {
                return;
            }

            var workspace = document.Project.Solution.Workspace;

            if (workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }

            var activeInlineRenameSession = workspace.Services.GetService <ICodeRefactoringHelpersService>().ActiveInlineRenameSession;

            if (activeInlineRenameSession)
            {
                return;
            }

            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }

            var options = ExtractMethodOptions.From(document.Project);
            var actions = await GetCodeActionsAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false);

            context.RegisterRefactorings(actions);
        }
 public CSharpSelectionValidator(
     SemanticDocument document,
     TextSpan textSpan,
     ExtractMethodOptions options,
     bool localFunction)
     : base(document, textSpan, options)
 {
     _localFunction = localFunction;
 }
 public ExpressionResult(
     OperationStatus status,
     TextSpan originalSpan,
     TextSpan finalSpan,
     ExtractMethodOptions options,
     bool selectionInExpression,
     SemanticDocument document,
     SyntaxAnnotation firstTokenAnnotation,
     SyntaxAnnotation lastTokenAnnotation)
     : base(status, originalSpan, finalSpan, options, selectionInExpression, document, firstTokenAnnotation, lastTokenAnnotation)
 {
 }
示例#4
0
        private static async Task <ImmutableArray <CodeAction> > GetCodeActionsAsync(
            Document document,
            TextSpan textSpan,
            ExtractMethodOptions options,
            CancellationToken cancellationToken)
        {
            using var _ = ArrayBuilder <CodeAction> .GetInstance(out var actions);

            var methodAction = await ExtractMethodAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false);

            actions.AddIfNotNull(methodAction);

            var localFunctionAction = await ExtractLocalFunctionAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false);

            actions.AddIfNotNull(localFunctionAction);

            return(actions.ToImmutable());
        }
示例#5
0
        protected static async Task <SyntaxNode> ExtractMethodAsync(
            TestWorkspace workspace,
            TestHostDocument testDocument,
            bool succeed = true,
            bool dontPutOutOrRefOnStruct = true,
            bool allowBestEffort         = false)
        {
            var document = workspace.CurrentSolution.GetDocument(testDocument.Id);

            Assert.NotNull(document);

            var options          = new ExtractMethodOptions(DontPutOutOrRefOnStruct: dontPutOutOrRefOnStruct);
            var semanticDocument = await SemanticDocument.CreateAsync(document, CancellationToken.None);

            var validator = new CSharpSelectionValidator(semanticDocument, testDocument.SelectedSpans.Single(), localFunction: false, options);

            var selectedCode = await validator.GetValidSelectionAsync(CancellationToken.None);

            if (!succeed && selectedCode.Status.FailedWithNoBestEffortSuggestion())
            {
                return(null);
            }

            Assert.True(selectedCode.ContainsValidContext);

            // extract method
            var extractor = new CSharpMethodExtractor((CSharpSelectionResult)selectedCode, localFunction: false);
            var result    = await extractor.ExtractMethodAsync(CancellationToken.None);

            Assert.NotNull(result);
            Assert.Equal(succeed,
                         result.Succeeded ||
                         result.SucceededWithSuggestion ||
                         (allowBestEffort && result.Status.HasBestEffort()));

            var(doc, _) = await result.GetFormattedDocumentAsync(CancellationToken.None);

            return(doc == null
                ? null
                : await doc.GetSyntaxRootAsync());
        }
        public static async Task <CSharpSelectionResult> CreateAsync(
            OperationStatus status,
            TextSpan originalSpan,
            TextSpan finalSpan,
            ExtractMethodOptions options,
            bool selectionInExpression,
            SemanticDocument document,
            SyntaxToken firstToken,
            SyntaxToken lastToken,
            CancellationToken cancellationToken)
        {
            Contract.ThrowIfNull(status);
            Contract.ThrowIfNull(document);

            var firstTokenAnnotation = new SyntaxAnnotation();
            var lastTokenAnnotation  = new SyntaxAnnotation();

            var root = await document.Document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var newDocument = await SemanticDocument.CreateAsync(document.Document.WithSyntaxRoot(root.AddAnnotations(
                                                                                                      new[]
            {
                Tuple.Create <SyntaxToken, SyntaxAnnotation>(firstToken, firstTokenAnnotation),
                Tuple.Create <SyntaxToken, SyntaxAnnotation>(lastToken, lastTokenAnnotation)
            })), cancellationToken).ConfigureAwait(false);

            if (selectionInExpression)
            {
                return(new ExpressionResult(
                           status, originalSpan, finalSpan, options, selectionInExpression,
                           newDocument, firstTokenAnnotation, lastTokenAnnotation));
            }
            else
            {
                return(new StatementResult(
                           status, originalSpan, finalSpan, options, selectionInExpression,
                           newDocument, firstTokenAnnotation, lastTokenAnnotation));
            }
        }
示例#7
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.GetFullyLoadedOpenDocumentInCurrentContextWithChanges(
                waitContext, _threadingContext);

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

            var options = ExtractMethodOptions.From(document.Project);
            var result  = ExtractMethodService.ExtractMethodAsync(
                document, spans.Single().Span.ToTextSpan(), localFunction: false, 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, result, options, 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);
        }
示例#8
0
        private static ExtractMethodResult TryWithoutMakingValueTypesRef(
            Document document, NormalizedSnapshotSpanCollection spans, ExtractMethodResult result, ExtractMethodOptions options, CancellationToken cancellationToken)
        {
            if (options.DontPutOutOrRefOnStruct || !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)
            {
                var newResult = ExtractMethodService.ExtractMethodAsync(
                    document,
                    spans.Single().Span.ToTextSpan(),
                    localFunction: false,
                    options with {
                    DontPutOutOrRefOnStruct = true
                },
示例#9
0
        private static async Task <CodeAction> ExtractMethodAsync(Document document, TextSpan textSpan, ExtractMethodOptions options, CancellationToken cancellationToken)
        {
            var result = await ExtractMethodService.ExtractMethodAsync(
                document,
                textSpan,
                localFunction : false,
                options,
                cancellationToken).ConfigureAwait(false);

            Contract.ThrowIfNull(result);

            if (!result.Succeeded && !result.SucceededWithSuggestion)
            {
                return(null);
            }

            return(new MyCodeAction(
                       FeaturesResources.Extract_method,
                       async c =>
            {
                var(document, invocationNameToken) = await result.GetFormattedDocumentAsync(c).ConfigureAwait(false);
                return await AddRenameAnnotationAsync(document, invocationNameToken, c).ConfigureAwait(false);
            },
                       nameof(FeaturesResources.Extract_method)));
        }
示例#10
0
        private static async Task <CodeAction> ExtractLocalFunctionAsync(Document document, TextSpan textSpan, ExtractMethodOptions options, CancellationToken cancellationToken)
        {
            var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

            var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>();

            if (!syntaxFacts.SupportsLocalFunctionDeclaration(syntaxTree.Options))
            {
                return(null);
            }

            var localFunctionResult = await ExtractMethodService.ExtractMethodAsync(
                document,
                textSpan,
                localFunction : true,
                options,
                cancellationToken).ConfigureAwait(false);

            Contract.ThrowIfNull(localFunctionResult);

            if (localFunctionResult.Succeeded || localFunctionResult.SucceededWithSuggestion)
            {
                var codeAction = new MyCodeAction(
                    FeaturesResources.Extract_local_function,
                    async c =>
                {
                    var(document, invocationNameToken) = await localFunctionResult.GetFormattedDocumentAsync(c).ConfigureAwait(false);
                    return(await AddRenameAnnotationAsync(document, invocationNameToken, c).ConfigureAwait(false));
                },
                    nameof(FeaturesResources.Extract_local_function));
                return(codeAction);
            }

            return(null);
        }
 protected override CSharpSelectionValidator CreateSelectionValidator(SemanticDocument document, TextSpan textSpan, bool localFunction, ExtractMethodOptions options)
 => new CSharpSelectionValidator(document, textSpan, localFunction, options);