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 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 async Task<InsertionPoint> CreateAsync(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken) { var root = document.Root; var annotation = new SyntaxAnnotation(); var newRoot = root.AddAnnotations(SpecializedCollections.SingletonEnumerable(Tuple.Create(node, annotation))); return new InsertionPoint(await document.WithSyntaxRootAsync(newRoot, cancellationToken).ConfigureAwait(false), annotation); }
public static async Task <InsertionPoint> CreateAsync(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken) { var root = document.Root; var annotation = new SyntaxAnnotation(); var newRoot = root.AddAnnotations(SpecializedCollections.SingletonEnumerable(Tuple.Create(node, annotation))); return(new InsertionPoint(await document.WithSyntaxRootAsync(newRoot, cancellationToken).ConfigureAwait(false), annotation)); }
private Task <SemanticDocument> CreateDocumentWithAnnotationsAsync(SemanticDocument document, IList <VariableInfo> variables, CancellationToken cancellationToken) { var annotations = new List <Tuple <SyntaxToken, SyntaxAnnotation> >(variables.Count); variables.Do(v => v.AddIdentifierTokenAnnotationPair(annotations, cancellationToken)); if (annotations.Count == 0) { return(Task.FromResult(document)); } return(document.WithSyntaxRootAsync(document.Root.AddAnnotations(annotations), cancellationToken)); }
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)); }
protected override async Task <GeneratedCode> CreateGeneratedCodeAsync(OperationStatus status, SemanticDocument newDocument, CancellationToken cancellationToken) { if (status.Succeeded()) { // in hybrid code cases such as extract method, formatter will have some difficulties on where it breaks lines in two. // here, we explicitly insert newline at the end of "{" of auto generated method decl so that anchor knows how to find out // indentation of inserted statements (from users code) with user code style preserved var root = newDocument.Root; var methodDefinition = root.GetAnnotatedNodes <MethodDeclarationSyntax>(this.MethodDefinitionAnnotation).First(); var newMethodDefinition = TweakNewLinesInMethod(methodDefinition); newDocument = await newDocument.WithSyntaxRootAsync( root.ReplaceNode(methodDefinition, newMethodDefinition), cancellationToken).ConfigureAwait(false); } return(await base.CreateGeneratedCodeAsync(status, newDocument, cancellationToken).ConfigureAwait(false)); }