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) { }
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()); }
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)); } }
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); }
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 },
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))); }
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);