public async Task <GeneratedCode> GenerateAsync(CancellationToken cancellationToken) { var root = SemanticDocument.Root; // should I check venus hidden position check here as well? root = root.ReplaceNode(GetOutermostCallSiteContainerToProcess(cancellationToken), await GenerateBodyForCallSiteContainerAsync(cancellationToken).ConfigureAwait(false)); var callSiteDocument = await SemanticDocument.WithSyntaxRootAsync(root, cancellationToken).ConfigureAwait(false); var newCallSiteRoot = callSiteDocument.Root; var previousMemberNode = GetPreviousMember(callSiteDocument); // it is possible in a script file case where there is no previous member. in that case, insert new text into top level script var destination = (previousMemberNode.Parent == null) ? previousMemberNode : previousMemberNode.Parent; var codeGenerationService = SemanticDocument.Document.GetLanguageService <ICodeGenerationService>(); var result = GenerateMethodDefinition(cancellationToken); var newContainer = codeGenerationService.AddMethod( destination, result.Data, new CodeGenerationOptions(afterThisLocation: previousMemberNode.GetLocation(), generateDefaultAccessibility: true, generateMethodBodies: true), cancellationToken); var newDocument = callSiteDocument.Document.WithSyntaxRoot(newCallSiteRoot.ReplaceNode(destination, newContainer)); newDocument = await Simplifier.ReduceAsync(newDocument, Simplifier.Annotation, null, cancellationToken).ConfigureAwait(false); var finalDocument = await SemanticDocument.CreateAsync(newDocument, cancellationToken).ConfigureAwait(false); var finalRoot = finalDocument.Root; var methodDefinition = finalRoot.GetAnnotatedNodesAndTokens(MethodDefinitionAnnotation).FirstOrDefault(); if (!methodDefinition.IsNode || methodDefinition.AsNode() == null) { return(await CreateGeneratedCodeAsync( result.Status.With(OperationStatus.FailedWithUnknownReason), finalDocument, cancellationToken).ConfigureAwait(false)); } if (methodDefinition.SyntaxTree.IsHiddenPosition(methodDefinition.AsNode().SpanStart, cancellationToken) || methodDefinition.SyntaxTree.IsHiddenPosition(methodDefinition.AsNode().Span.End, cancellationToken)) { return(await CreateGeneratedCodeAsync( result.Status.With(OperationStatus.OverlapsHiddenPosition), finalDocument, cancellationToken).ConfigureAwait(false)); } return(await CreateGeneratedCodeAsync(result.Status, finalDocument, cancellationToken).ConfigureAwait(false)); }
public async Task <ImmutableArray <CodeAction> > GenerateDeconstructMethodAsync( Document document, SyntaxNode leftSide, INamedTypeSymbol typeToGenerateIn, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Refactoring_GenerateMember_GenerateMethod, cancellationToken)) { var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); var state = await State.GenerateDeconstructMethodStateAsync( (TService)this, semanticDocument, leftSide, typeToGenerateIn, cancellationToken).ConfigureAwait(false); return(state != null ? await GetActionsAsync(document, state, fallbackOptions, cancellationToken).ConfigureAwait(false) : ImmutableArray <CodeAction> .Empty); } }
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 ExtractMethodGenerationOptions( ExtractOptions: new ExtractMethodOptions(dontPutOutOrRefOnStruct), CodeGenerationOptions: CodeGenerationOptions.GetDefault(document.Project.LanguageServices), AddImportOptions: AddImportPlacementOptions.Default, NamingPreferences: _ => NamingStylePreferences.Default); var semanticDocument = await SemanticDocument.CreateAsync(document, CancellationToken.None); var validator = new CSharpSelectionValidator(semanticDocument, testDocument.SelectedSpans.Single(), options.ExtractOptions, localFunction: false); 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, options, 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(CodeCleanupOptions.GetDefault(document.Project.LanguageServices), CancellationToken.None); return(doc == null ? null : await doc.GetSyntaxRootAsync()); }
protected static async Task <SyntaxNode> ExtractMethodAsync( TestWorkspace workspace, TestHostDocument testDocument, bool succeed = true, bool allowMovingDeclaration = true, bool dontPutOutOrRefOnStruct = true, bool allowBestEffort = false) { var document = workspace.CurrentSolution.GetDocument(testDocument.Id); Assert.NotNull(document); var originalOptions = await document.GetOptionsAsync(); var options = originalOptions.WithChangedOption(ExtractMethodOptions.AllowMovingDeclaration, document.Project.Language, allowMovingDeclaration) .WithChangedOption(ExtractMethodOptions.DontPutOutOrRefOnStruct, document.Project.Language, dontPutOutOrRefOnStruct); var semanticDocument = await SemanticDocument.CreateAsync(document, CancellationToken.None); var validator = new CSharpSelectionValidator(semanticDocument, testDocument.SelectedSpans.Single(), 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 = result.Document; return(doc == null ? null : await doc.GetSyntaxRootAsync()); }
private static async Task <Tuple <SemanticDocument, ISet <ExpressionSyntax> > > ComplexifyParentingStatements( SemanticDocument semanticDocument, ISet <ExpressionSyntax> matches, CancellationToken cancellationToken) { // First, track the matches so that we can get back to them later. var newRoot = semanticDocument.Root.TrackNodes(matches); var newDocument = semanticDocument.Document.WithSyntaxRoot(newRoot); var newSemanticDocument = await SemanticDocument.CreateAsync(newDocument, cancellationToken).ConfigureAwait(false); var newMatches = newSemanticDocument.Root.GetCurrentNodes(matches.AsEnumerable()).ToSet(); // Next, expand the topmost parenting expression of each match, being careful // not to expand the matches themselves. var topMostExpressions = newMatches .Select(m => m.AncestorsAndSelf().OfType <ExpressionSyntax>().Last()) .Distinct(); newRoot = await newSemanticDocument.Root .ReplaceNodesAsync( topMostExpressions, computeReplacementAsync : async(oldNode, newNode, ct) => { return(await Simplifier .ExpandAsync( oldNode, newSemanticDocument.Document, expandInsideNode: node => { var expression = node as ExpressionSyntax; return expression == null || !newMatches.Contains(expression); }, cancellationToken: ct) .ConfigureAwait(false)); }, cancellationToken : cancellationToken) .ConfigureAwait(false); newDocument = newSemanticDocument.Document.WithSyntaxRoot(newRoot); newSemanticDocument = await SemanticDocument.CreateAsync(newDocument, cancellationToken).ConfigureAwait(false); newMatches = newSemanticDocument.Root.GetCurrentNodes(matches.AsEnumerable()).ToSet(); return(Tuple.Create(newSemanticDocument, newMatches)); }
public async Task <IEnumerable <CodeAction> > GenerateVariableAsync( Document document, SyntaxNode node, CancellationToken cancellationToken) { var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); var state = await State.GenerateAsync((TService)this, semanticDocument, node, cancellationToken).ConfigureAwait(false); if (state == null) { return(SpecializedCollections.EmptyEnumerable <CodeAction>()); } var result = new List <CodeAction>(); var canGenerateMember = ICSharpCode.NRefactory6.CSharp.CodeGenerator.CanAdd(document.Project.Solution, state.TypeToGenerateIn, cancellationToken); // prefer fields over properties (and vice versa) depending on the casing of the member. // lowercase -> fields. title case -> properties. var name = state.IdentifierToken.ValueText; if (char.IsUpper(name.FirstOrDefault())) { if (canGenerateMember) { AddPropertyCodeActions(result, document, state); AddFieldCodeActions(result, document, state); } AddLocalCodeActions(result, document, state); } else { if (canGenerateMember) { AddFieldCodeActions(result, document, state); AddPropertyCodeActions(result, document, state); } AddLocalCodeActions(result, document, state); } return(result); }
public async Task <GenerateDefaultConstructorsResult> GenerateDefaultConstructorsAsync( Document document, TextSpan textSpan, CancellationToken cancellationToken) { var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); if (textSpan.IsEmpty) { var state = State.Generate((TService)this, semanticDocument, textSpan, cancellationToken); if (state != null) { return(new GenerateDefaultConstructorsResult(new CodeRefactoring(null, GetActions(document, state)))); } } return(GenerateDefaultConstructorsResult.Failure); }
private async Task <IEnumerable <SnapshotSpan> > GetExecutableSyntaxTreeNodeSelectionAsync( TextSpan selectionSpan, EditorCommandArgs args, ITextSnapshot snapshot, CancellationToken cancellationToken ) { var doc = args.SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); var semanticDocument = await SemanticDocument .CreateAsync(doc, cancellationToken) .ConfigureAwait(false); var root = semanticDocument.Root; return(GetExecutableSyntaxTreeNodeSelection(selectionSpan, root) .Select(span => new SnapshotSpan(snapshot, span.Start, span.Length))); }
public async Task <IEnumerable <CodeAction> > GenerateTypeAsync( Document document, SyntaxNode node, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Refactoring_GenerateType, cancellationToken)) { var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); var state = State.Generate((TService)this, semanticDocument, node, cancellationToken); if (state != null) { return(GetActions(semanticDocument, node, state, cancellationToken)); } return(SpecializedCollections.EmptyEnumerable <CodeAction>()); } }
public async Task <ImmutableArray <CodeAction> > GenerateConstructorAsync(Document document, SyntaxNode node, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Refactoring_GenerateMember_GenerateConstructor, cancellationToken)) { var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); var state = await State.GenerateAsync((TService)this, semanticDocument, node, fallbackOptions, cancellationToken).ConfigureAwait(false); if (state != null) { Contract.ThrowIfNull(state.TypeToGenerateIn); using var _ = ArrayBuilder <CodeAction> .GetInstance(out var result); // If we have any fields we'd like to generate, offer a code action to do that. if (state.ParameterToNewFieldMap.Count > 0) { result.Add(CodeAction.Create( string.Format(FeaturesResources.Generate_constructor_in_0_with_fields, state.TypeToGenerateIn.Name), c => state.GetChangedDocumentAsync(document, withFields: true, withProperties: false, c), nameof(FeaturesResources.Generate_constructor_in_0_with_fields) + "_" + state.TypeToGenerateIn.Name)); } // Same with a version that generates properties instead. if (state.ParameterToNewPropertyMap.Count > 0) { result.Add(CodeAction.Create( string.Format(FeaturesResources.Generate_constructor_in_0_with_properties, state.TypeToGenerateIn.Name), c => state.GetChangedDocumentAsync(document, withFields: false, withProperties: true, c), nameof(FeaturesResources.Generate_constructor_in_0_with_properties) + "_" + state.TypeToGenerateIn.Name)); } // Always offer to just generate the constructor and nothing else. result.Add(CodeAction.Create( string.Format(FeaturesResources.Generate_constructor_in_0, state.TypeToGenerateIn.Name), c => state.GetChangedDocumentAsync(document, withFields: false, withProperties: false, c), nameof(FeaturesResources.Generate_constructor_in_0) + "_" + state.TypeToGenerateIn.Name)); return(result.ToImmutable()); } } return(ImmutableArray <CodeAction> .Empty); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; if (!textSpan.IsEmpty) { return; } if (cancellationToken.IsCancellationRequested) { return; } if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var statement = root.FindToken(textSpan.Start).GetAncestor <LocalDeclarationStatementSyntax>(); if (statement == null || !statement.Span.IntersectsWith(textSpan.Start)) { return; } var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); var state = await State.GenerateAsync(semanticDocument, statement, cancellationToken).ConfigureAwait(false); if (state == null) { return; } context.RegisterRefactoring( new MyCodeAction( CSharpFeaturesResources.Move_declaration_near_reference, c => MoveDeclarationNearReferenceAsync(document, state, c))); }
public async Task <ImmutableArray <CodeAction> > GenerateMethodAsync( Document document, SyntaxNode node, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Refactoring_GenerateMember_GenerateMethod, cancellationToken)) { var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); var state = await State.GenerateMethodStateAsync((TService)this, semanticDocument, node, cancellationToken).ConfigureAwait(false); if (state == null) { return(ImmutableArray <CodeAction> .Empty); } return(GetActions(document, state, cancellationToken)); } }
protected override async Task <IEnumerable <CodeActionOperation> > ComputeOperationsAsync( CancellationToken cancellationToken ) { var semanticDocument = await SemanticDocument .CreateAsync(_document, cancellationToken) .ConfigureAwait(false); var editor = new Editor( _service, semanticDocument, _state, _intoNamespace, _inNewFile, cancellationToken: cancellationToken ); return(await editor.GetOperationsAsync().ConfigureAwait(false)); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; if (cancellationToken.IsCancellationRequested) { return; } if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); var refactoringHelperService = document.GetLanguageService <IRefactoringHelpersService>(); var lambda = await refactoringHelperService.TryGetSelectedNodeAsync <LambdaExpressionSyntax>(document, context.Span, cancellationToken).ConfigureAwait(false); if (lambda == null) { return; } if (!CanSimplify(semanticDocument, lambda as SimpleLambdaExpressionSyntax, cancellationToken) && !CanSimplify(semanticDocument, lambda as ParenthesizedLambdaExpressionSyntax, cancellationToken)) { return; } context.RegisterRefactoring( new MyCodeAction( CSharpFeaturesResources.Simplify_lambda_expression, c => SimplifyLambdaAsync(document, lambda, c))); context.RegisterRefactoring( new MyCodeAction( CSharpFeaturesResources.Simplify_all_occurrences, c => SimplifyAllLambdasAsync(document, c))); }
protected static async Task TestSelectionAsync( string codeWithMarker, bool expectedFail = false, CSharpParseOptions parseOptions = null, TextSpan?textSpanOverride = null ) { using var workspace = TestWorkspace.CreateCSharp( codeWithMarker, parseOptions: parseOptions ); var testDocument = workspace.Documents.Single(); var namedSpans = testDocument.AnnotatedSpans; var document = workspace.CurrentSolution.GetDocument(testDocument.Id); Assert.NotNull(document); var options = await document.GetOptionsAsync(CancellationToken.None); var semanticDocument = await SemanticDocument.CreateAsync( document, CancellationToken.None ); var validator = new CSharpSelectionValidator( semanticDocument, textSpanOverride ?? namedSpans["b"].Single(), options ); var result = await validator.GetValidSelectionAsync(CancellationToken.None); Assert.True(expectedFail ? result.Status.Failed() : result.Status.Succeeded()); if ( (result.Status.Succeeded() || result.Status.Flag.HasBestEffort()) && result.Status.Flag.HasSuggestion() ) { Assert.Equal(namedSpans["r"].Single(), result.FinalSpan); } }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; if (cancellationToken.IsCancellationRequested) { return; } if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); var lambda = semanticDocument.Root.FindToken(textSpan.Start).GetAncestor(n => n is SimpleLambdaExpressionSyntax || n is ParenthesizedLambdaExpressionSyntax); if (lambda == null || !lambda.Span.IntersectsWith(textSpan.Start)) { return; } if (!CanSimplify(semanticDocument, lambda as SimpleLambdaExpressionSyntax, cancellationToken) && !CanSimplify(semanticDocument, lambda as ParenthesizedLambdaExpressionSyntax, cancellationToken)) { return; } context.RegisterRefactoring( new MyCodeAction( CSharpFeaturesResources.Simplify_lambda_expression, c => SimplifyLambdaAsync(document, lambda, c))); context.RegisterRefactoring( new MyCodeAction( CSharpFeaturesResources.Simplify_all_occurrences, c => SimplifyAllLambdasAsync(document, c))); }
private async Task <State> CreateStateAsync( Document document, TextSpan textSpan, CancellationToken cancellationToken ) { var nodeToAnalyze = await GetRelevantNodeAsync(document, textSpan, cancellationToken) .ConfigureAwait(false); if (nodeToAnalyze == null) { return(null); } var semanticDocument = await SemanticDocument .CreateAsync(document, cancellationToken) .ConfigureAwait(false); return(State.Generate(semanticDocument, nodeToAnalyze, cancellationToken)); }
public async Task <ImmutableArray <CodeAction> > IntroduceVariableAsync( Document document, TextSpan textSpan, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Refactoring_IntroduceVariable, cancellationToken)) { var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); var state = State.Generate((TService)this, semanticDocument, textSpan, cancellationToken); if (state != null) { var actions = await CreateActionsAsync(state, cancellationToken).ConfigureAwait(false); if (actions.Count > 0) { return(actions.AsImmutableOrNull()); } } return(default);
public async Task <ImmutableArray <CodeAction> > GenerateDefaultConstructorsAsync( Document document, TextSpan textSpan, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Refactoring_GenerateMember_GenerateDefaultConstructors, cancellationToken)) { var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); if (textSpan.IsEmpty) { var state = State.Generate((TService)this, semanticDocument, textSpan, cancellationToken); if (state != null) { return(GetActions(document, state).AsImmutableOrNull()); } } return(default(ImmutableArray <CodeAction>)); } }
public static async Task <CSharpSelectionResult> CreateAsync( OperationStatus status, TextSpan originalSpan, TextSpan finalSpan, OptionSet 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)); } }
public async Task <ImmutableArray <CodeAction> > GenerateTypeAsync( Document document, SyntaxNode node, CancellationToken cancellationToken ) { using (Logger.LogBlock(FunctionId.Refactoring_GenerateType, cancellationToken)) { var semanticDocument = await SemanticDocument .CreateAsync(document, cancellationToken) .ConfigureAwait(false); var state = await State .GenerateAsync((TService)this, semanticDocument, node, cancellationToken) .ConfigureAwait(false); if (state != null) { var actions = GetActions(semanticDocument, node, state, cancellationToken); if (actions.Length > 1) { // Wrap the generate type actions into a single top level suggestion // so as to not clutter the list. return(ImmutableArray.Create <CodeAction>( new MyCodeAction( string.Format(FeaturesResources.Generate_type_0, state.Name), actions.AsImmutable() ) )); } else { return(actions); } } return(ImmutableArray <CodeAction> .Empty); } }
public async Task <ExtractMethodResult> ExtractMethodAsync( Document document, TextSpan textSpan, bool localFunction, OptionSet options, CancellationToken cancellationToken) { options ??= await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); var validator = CreateSelectionValidator(semanticDocument, textSpan, options); var selectionResult = await validator.GetValidSelectionAsync(cancellationToken).ConfigureAwait(false); if (!selectionResult.ContainsValidContext) { return(new FailedExtractMethodResult(selectionResult.Status)); } var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>(); if (localFunction && syntaxFacts.ContainsGlobalStatement(root)) { // ExtractLocalFunction doesn't yet support local functions in top-level statements // https://github.com/dotnet/roslyn/issues/44260 return(new FailedExtractMethodResult(OperationStatus.FailedWithUnknownReason)); } cancellationToken.ThrowIfCancellationRequested(); // extract method var extractor = CreateMethodExtractor((TResult)selectionResult, localFunction); return(await extractor.ExtractMethodAsync(cancellationToken).ConfigureAwait(false)); }
public async Task <IntroduceVariableResult> IntroduceVariableAsync( Document document, TextSpan textSpan, CancellationToken cancellationToken) { var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); var state = State.Generate((TService)this, semanticDocument, textSpan, cancellationToken); if (state == null) { return(IntroduceVariableResult.Failure); } var actions = await CreateActionsAsync(state, cancellationToken).ConfigureAwait(false); if (actions.Count == 0) { return(IntroduceVariableResult.Failure); } return(new IntroduceVariableResult(new CodeRefactoring(null, actions))); }
public async Task <ImmutableArray <CodeAction> > GetRefactoringAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if (!ShouldAnalyze(root, textSpan)) { return(default(ImmutableArray <CodeAction>)); } var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); var state = State.Generate((TService)this, semanticDocument, textSpan, cancellationToken); if (state == null) { return(default(ImmutableArray <CodeAction>)); } var actions = CreateActions(state, cancellationToken); Debug.Assert(actions.Count() != 0, "No code actions found for MoveType Refactoring"); return(actions); }
protected static async Task IterateAllAsync(string code) { using var workspace = TestWorkspace.CreateCSharp( code, CodeAnalysis.CSharp.Test.Utilities.TestOptions.Regular ); var document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id); Assert.NotNull(document); var semanticDocument = await SemanticDocument.CreateAsync( document, CancellationToken.None ); var root = await document.GetSyntaxRootAsync(); var iterator = root.DescendantNodesAndSelf().Cast <SyntaxNode>(); var originalOptions = await document.GetOptionsAsync(); foreach (var node in iterator) { var validator = new CSharpSelectionValidator( semanticDocument, node.Span, originalOptions ); var result = await validator.GetValidSelectionAsync(CancellationToken.None); // check the obvious case if (!(node is ExpressionSyntax) && !node.UnderValidContext()) { Assert.True(result.Status.FailedWithNoBestEffortSuggestion()); } } }
private Solution CreateSolutionWithEventHandler( Document document, string eventHandlerMethodName, int position, out int plusEqualTokenEndPosition, IGlobalOptionService globalOptions, CancellationToken cancellationToken) { _threadingContext.ThrowIfNotOnUIThread(); // Mark the += token with an annotation so we can find it after formatting var plusEqualsTokenAnnotation = new SyntaxAnnotation(); var documentWithNameAndAnnotationsAdded = AddMethodNameAndAnnotationsToSolution(document, eventHandlerMethodName, position, plusEqualsTokenAnnotation, cancellationToken); var semanticDocument = SemanticDocument.CreateAsync(documentWithNameAndAnnotationsAdded, cancellationToken).WaitAndGetResult(cancellationToken); var options = (CSharpCodeGenerationOptions)document.GetCodeGenerationOptionsAsync(globalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); var updatedRoot = AddGeneratedHandlerMethodToSolution(semanticDocument, options, eventHandlerMethodName, plusEqualsTokenAnnotation, cancellationToken); if (updatedRoot == null) { plusEqualTokenEndPosition = 0; return(null); } var cleanupOptions = documentWithNameAndAnnotationsAdded.GetCodeCleanupOptionsAsync(globalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); var simplifiedDocument = Simplifier.ReduceAsync(documentWithNameAndAnnotationsAdded.WithSyntaxRoot(updatedRoot), Simplifier.Annotation, cleanupOptions.SimplifierOptions, cancellationToken).WaitAndGetResult(cancellationToken); var formattedDocument = Formatter.FormatAsync(simplifiedDocument, Formatter.Annotation, cleanupOptions.FormattingOptions, cancellationToken).WaitAndGetResult(cancellationToken); var newRoot = formattedDocument.GetSyntaxRootSynchronously(cancellationToken); plusEqualTokenEndPosition = newRoot.GetAnnotatedNodesAndTokens(plusEqualsTokenAnnotation) .Single().Span.End; return(document.Project.Solution.WithDocumentText( formattedDocument.Id, formattedDocument.GetTextSynchronously(cancellationToken))); }
protected async Task IterateAllAsync(string code) { using (var workspace = await CSharpWorkspaceFactory.CreateWorkspaceFromLinesAsync(new string[] { code }, CodeAnalysis.CSharp.Test.Utilities.TestOptions.Regular)) { var document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id); Assert.NotNull(document); var semanticDocument = await SemanticDocument.CreateAsync(document, CancellationToken.None); var tree = await document.GetSyntaxTreeAsync(); var iterator = tree.GetRoot().DescendantNodesAndSelf().Cast <SyntaxNode>(); var options = document.Project.Solution.Workspace.Options .WithChangedOption(ExtractMethodOptions.AllowMovingDeclaration, document.Project.Language, true); foreach (var node in iterator) { try { var validator = new CSharpSelectionValidator(semanticDocument, node.Span, options); var result = await validator.GetValidSelectionAsync(CancellationToken.None); // check the obvious case if (!(node is ExpressionSyntax) && !node.UnderValidContext()) { Assert.True(result.Status.FailedWithNoBestEffortSuggestion()); } } catch (ArgumentException) { // catch and ignore unknown issue. currently control flow analysis engine doesn't support field initializer. } } } }
protected static SyntaxNode ExtractMethod( TestWorkspace workspace, TestHostDocument testDocument, bool succeed = true, bool allowMovingDeclaration = true, bool dontPutOutOrRefOnStruct = true) { var document = workspace.CurrentSolution.GetDocument(testDocument.Id); Assert.NotNull(document); var options = document.Project.Solution.Workspace.Options .WithChangedOption(ExtractMethodOptions.AllowMovingDeclaration, document.Project.Language, allowMovingDeclaration) .WithChangedOption(ExtractMethodOptions.DontPutOutOrRefOnStruct, document.Project.Language, dontPutOutOrRefOnStruct); var semanticDocument = SemanticDocument.CreateAsync(document, CancellationToken.None).Result; var validator = new CSharpSelectionValidator(semanticDocument, testDocument.SelectedSpans.Single(), options); var selectedCode = validator.GetValidSelectionAsync(CancellationToken.None).Result; if (!succeed && selectedCode.Status.FailedWithNoBestEffortSuggestion()) { return(null); } Assert.True(selectedCode.ContainsValidContext); // extract method var extractor = new CSharpMethodExtractor((CSharpSelectionResult)selectedCode); var result = extractor.ExtractMethodAsync(CancellationToken.None).Result; Assert.NotNull(result); Assert.Equal(succeed, result.Succeeded || result.SucceededWithSuggestion); return((SyntaxNode)result.Document.GetSyntaxRootAsync().Result); }
public async Task <GeneratedCode> GenerateAsync(CancellationToken cancellationToken) { var root = SemanticDocument.Root; // should I check venus hidden position check here as well? root = root.ReplaceNode( GetOutermostCallSiteContainerToProcess(cancellationToken), await GenerateBodyForCallSiteContainerAsync(cancellationToken) .ConfigureAwait(false) ); var callSiteDocument = await SemanticDocument .WithSyntaxRootAsync(root, cancellationToken) .ConfigureAwait(false); var newCallSiteRoot = callSiteDocument.Root; var codeGenerationService = SemanticDocument.Document.GetLanguageService <ICodeGenerationService>(); var result = GenerateMethodDefinition(LocalFunction, cancellationToken); SyntaxNode destination, newContainer; if (LocalFunction) { destination = InsertionPoint.With(callSiteDocument).GetContext(); // No valid location to insert the new method call. if (destination == null) { return(await CreateGeneratedCodeAsync( OperationStatus.NoValidLocationToInsertMethodCall, callSiteDocument, cancellationToken ) .ConfigureAwait(false)); } var localMethod = codeGenerationService.CreateMethodDeclaration( method: result.Data, options: new CodeGenerationOptions( generateDefaultAccessibility: false, generateMethodBodies: true, options: Options, parseOptions: destination?.SyntaxTree.Options ) ); newContainer = codeGenerationService.AddStatements( destination, new[] { localMethod }, cancellationToken: cancellationToken ); } else { var previousMemberNode = GetPreviousMember(callSiteDocument); // it is possible in a script file case where there is no previous member. in that case, insert new text into top level script destination = previousMemberNode.Parent ?? previousMemberNode; newContainer = codeGenerationService.AddMethod( destination, result.Data, new CodeGenerationOptions( afterThisLocation: previousMemberNode.GetLocation(), generateDefaultAccessibility: true, generateMethodBodies: true, options: Options ), cancellationToken ); } var newSyntaxRoot = newCallSiteRoot.ReplaceNode(destination, newContainer); var newDocument = callSiteDocument.Document.WithSyntaxRoot(newSyntaxRoot); newDocument = await Simplifier .ReduceAsync(newDocument, Simplifier.Annotation, null, cancellationToken) .ConfigureAwait(false); var generatedDocument = await SemanticDocument .CreateAsync(newDocument, cancellationToken) .ConfigureAwait(false); // For nullable reference types, we can provide a better experience by reducing use // of nullable reference types after a method is done being generated. If we can // determine that the method never returns null, for example, then we can // make the signature into a non-null reference type even though // the original type was nullable. This allows our code generation to // follow our recommendation of only using nullable when necessary. // This is done after method generation instead of at analyzer time because it's purely // based on the resulting code, which the generator can modify as needed. If return statements // are added, the flow analysis could change to indicate something different. It's cleaner to rely // on flow analysis of the final resulting code than to try and predict from the analyzer what // will happen in the generator. var finalDocument = await UpdateMethodAfterGenerationAsync( generatedDocument, result, cancellationToken ) .ConfigureAwait(false); var finalRoot = finalDocument.Root; var methodDefinition = finalRoot .GetAnnotatedNodesAndTokens(MethodDefinitionAnnotation) .FirstOrDefault(); if (!methodDefinition.IsNode || methodDefinition.AsNode() == null) { return(await CreateGeneratedCodeAsync( result.Status.With(OperationStatus.FailedWithUnknownReason), finalDocument, cancellationToken ) .ConfigureAwait(false)); } if ( methodDefinition.SyntaxTree.IsHiddenPosition( methodDefinition.AsNode().SpanStart, cancellationToken ) || methodDefinition.SyntaxTree.IsHiddenPosition( methodDefinition.AsNode().Span.End, cancellationToken ) ) { return(await CreateGeneratedCodeAsync( result.Status.With(OperationStatus.OverlapsHiddenPosition), finalDocument, cancellationToken ) .ConfigureAwait(false)); } return(await CreateGeneratedCodeAsync( result.Status, finalDocument, cancellationToken ) .ConfigureAwait(false)); }
public static Task <SemanticDocument> WithSyntaxRootAsync(this SemanticDocument semanticDocument, SyntaxNode root, CancellationToken cancellationToken) { return(SemanticDocument.CreateAsync(semanticDocument.Document.WithSyntaxRoot(root), cancellationToken)); }