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));
            }
示例#2
0
 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);
 }
示例#3
0
        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));
            }
示例#6
0
            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));
            }