Exemplo n.º 1
0
        // TODO: Missing members
        private TypeTransformationResult TransformType(ITypeAnalyzationResult rootTypeResult)
        {
            var rootTypeNode        = rootTypeResult.Node;
            var startRootTypeSpan   = rootTypeNode.SpanStart;
            var typeResultMetadatas = new Dictionary <ITypeAnalyzationResult, TypeTransformationMetadata>();
            var rootMetadata        = new TypeTransformationMetadata
            {
                ReservedFieldNames = new HashSet <string>(rootTypeResult.Symbol.MemberNames)
            };

            // We do this here because we want that the root node has span start equal to 0
            rootTypeNode       = rootTypeNode.WithAdditionalAnnotations(new SyntaxAnnotation(rootMetadata.Annotation));
            startRootTypeSpan -= rootTypeNode.SpanStart;

            // Before any modification we need to annotate nodes that will be transformed in order to find them later on.
            // We cannot rely on spans as they changes each time the node is modified.
            foreach (var typeResult in rootTypeResult.GetSelfAndDescendantsTypes(o => o.Conversion != TypeConversion.Ignore))
            {
                var typeSpanStart  = typeResult.Node.SpanStart - startRootTypeSpan;
                var typeSpanLength = typeResult.Node.Span.Length;
                var typeNode       = rootTypeNode.DescendantNodesAndSelf().OfType <TypeDeclarationSyntax>()
                                     .First(o => o.SpanStart == typeSpanStart && o.Span.Length == typeSpanLength);
                TypeTransformationMetadata metadata;
                if (typeNode == rootTypeNode)
                {
                    metadata = rootMetadata;
                }
                else
                {
                    metadata = new TypeTransformationMetadata
                    {
                        ReservedFieldNames = new HashSet <string>(typeResult.Symbol.MemberNames)
                    };
                    rootTypeNode = rootTypeNode.ReplaceNode(typeNode, typeNode.WithAdditionalAnnotations(new SyntaxAnnotation(metadata.Annotation)));
                }

                // TypeReferences can be changes only if we create a new type
                if (rootTypeResult.Conversion == TypeConversion.NewType)
                {
                    foreach (var typeReference in typeResult.TypeReferences)
                    {
                        var reference     = typeReference.ReferenceLocation;
                        var refSpanStart  = reference.Location.SourceSpan.Start - startRootTypeSpan;
                        var refSpanLength = reference.Location.SourceSpan.Length;
                        if (refSpanStart < 0)
                        {
                            // TODO: cref
                            //var startSpan = reference.Location.SourceSpan.Start - rootTypeInfo.Node.GetLeadingTrivia().Span.Start;
                            //var crefNode = leadingTrivia.First(o => o.SpanStart == startSpan && o.Span.Length == refSpanLength);
                            continue;
                        }

                        var nameNode        = rootTypeNode.GetSimpleName(refSpanStart, refSpanLength);
                        var transformedNode = new TransformationResult(nameNode)
                        {
                            TransformedNode = nameNode.WithIdentifier(Identifier(nameNode.Identifier.ValueText + "Async"))
                        };
                        metadata.TransformedNodes.Add(transformedNode);
                        rootTypeNode = rootTypeNode.ReplaceNode(nameNode, nameNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformedNode.Annotation)));
                    }
                }

                // Annotate and save the transformed methods
                foreach (var methodResult in typeResult.Methods)
                {
                    var methodSpanStart  = methodResult.Node.SpanStart - startRootTypeSpan;
                    var methodSpanLength = methodResult.Node.Span.Length;
                    var methodNode       = rootTypeNode.DescendantNodes()
                                           .OfType <MethodDeclarationSyntax>()
                                           .First(o => o.SpanStart == methodSpanStart && o.Span.Length == methodSpanLength);
                    var transformedNode = TransformMethod(metadata, methodResult);
                    metadata.TransformedMethods.Add(transformedNode);
                    rootTypeNode = rootTypeNode.ReplaceNode(methodNode, methodNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformedNode.Annotation)));
                }
                typeResultMetadatas.Add(typeResult, metadata);
            }
            // Save the orignal node that was only annotated
            var result = new TypeTransformationResult(rootTypeNode);

            // Now we can start transforming the type. Start from the bottom in order to preserve replaced nested types
            foreach (var typeResult in rootTypeResult.GetSelfAndDescendantsTypes(o => o.Conversion != TypeConversion.Ignore)
                     .OrderByDescending(o => o.Node.SpanStart))
            {
                var metadata = typeResultMetadatas[typeResult];
                // Add partial keyword on the original node if not present
                if (typeResult.Conversion == TypeConversion.Partial && !typeResult.IsPartial)
                {
                    var typeNode = rootTypeNode.GetAnnotatedNodes(metadata.Annotation).OfType <TypeDeclarationSyntax>().First();
                    result.OriginalModifiedNode = result.Node.ReplaceNode(typeNode, typeNode.AddPartial());
                }
                // If the root type has to be a new type then all nested types have to be new types
                if (typeResult.Conversion == TypeConversion.NewType)
                {
                    // Replace all rewritten nodes
                    foreach (var rewNode in metadata.TransformedNodes)
                    {
                        var node = rootTypeNode.GetAnnotatedNodes(rewNode.Annotation).First();
                        if (rewNode.TransformedNode == null)
                        {
                            //TODO: fix regions
                            rootTypeNode = rootTypeNode.RemoveNode(node, SyntaxRemoveOptions.KeepNoTrivia);
                        }
                        else
                        {
                            rootTypeNode = rootTypeNode.ReplaceNode(node, rewNode.TransformedNode);
                        }
                    }
                }
                else if (typeResult.Conversion == TypeConversion.Partial)
                {
                    var typeNode = rootTypeNode.GetAnnotatedNodes(metadata.Annotation).OfType <TypeDeclarationSyntax>().First();
                    var newNodes = metadata.TransformedNodes
                                   .Union(metadata.TransformedMethods)
                                   .Where(o => o.TransformedNode != null)
                                   .OrderBy(o => o.Node.SpanStart)
                                   .Select(o => o.TransformedNode)
                                   .Union(typeNode.DescendantNodes().OfType <TypeDeclarationSyntax>())
                                   .ToList();
                    if (!newNodes.Any())
                    {
                        //TODO: fix regions
                        rootTypeNode = rootTypeNode.RemoveNode(typeNode, SyntaxRemoveOptions.KeepNoTrivia);
                    }
                    else
                    {
                        // We need to remove the attributes as they cannot be defined in both partial classes
                        var newTypeNode = typeNode.AddPartial().WithoutAttributes();
                        // Add fields for async lock if any. We need a lock field for each synchronized method
                        foreach (var methodTransform in metadata.TransformedMethods.Where(o => o.AsyncLockField != null).OrderBy(o => o.Node.SpanStart))
                        {
                            newNodes.Insert(0, methodTransform.AsyncLockField);
                        }
                        newTypeNode = newTypeNode.WithMembers(List(newNodes));

                        //TODO: fix regions
                        rootTypeNode = rootTypeNode.ReplaceNode(typeNode, newTypeNode /*.RemoveLeadingDirectives()*/);
                    }
                }
            }

            result.TransformedNode = rootTypeNode;

            return(result);
        }
Exemplo n.º 2
0
        private DocumentTransformationResult TransformDocument(IDocumentAnalyzationResult documentResult)
        {
            var rootNode       = documentResult.Node;
            var result         = new DocumentTransformationResult(rootNode);
            var rewrittenNodes = new List <TransformationResult>();
            var namespaceNodes = new List <MemberDeclarationSyntax>();
            var hasTaskUsing   = rootNode.Usings.Any(o => o.Name.ToString() == "System.Threading.Tasks");

            foreach (var namespaceResult in documentResult.Namespaces.OrderBy(o => o.Node.SpanStart))
            {
                var namespaceNode = namespaceResult.Node;
                var typeNodes     = new List <MemberDeclarationSyntax>();
                foreach (var typeResult in namespaceResult.Types.Where(o => o.Conversion != TypeConversion.Ignore).OrderBy(o => o.Node.SpanStart))
                {
                    var transformResult = TransformType(typeResult);
                    if (transformResult.TransformedNode == null)
                    {
                        continue;
                    }
                    typeNodes.Add(transformResult.TransformedNode);

                    // We need to update the original file if it was modified
                    if (transformResult.OriginalModifiedNode != null)
                    {
                        var typeSpanStart  = typeResult.Node.SpanStart;
                        var typeSpanLength = typeResult.Node.Span.Length;
                        var typeNode       = rootNode.DescendantNodesAndSelf().OfType <TypeDeclarationSyntax>()
                                             .First(o => o.SpanStart == typeSpanStart && o.Span.Length == typeSpanLength);
                        var rewritenNode = new TransformationResult(typeNode)
                        {
                            TransformedNode = transformResult.OriginalModifiedNode
                        };
                        rootNode = rootNode.ReplaceNode(typeNode, typeNode.WithAdditionalAnnotations(new SyntaxAnnotation(rewritenNode.Annotation)));
                        rewrittenNodes.Add(rewritenNode);
                    }

                    // TODO: missing members
                    //if (typeInfo.TypeTransformation == TypeTransformation.NewType && typeInfo.HasMissingMembers)
                    //{
                    //	transformResult = TransformType(typeInfo, true);
                    //	if (transformResult.Node == null)
                    //	{
                    //		continue;
                    //	}
                    //	typeNodes.Add(transformResult.Node);
                    //}
                }
                if (typeNodes.Any())
                {
                    var leadingTrivia = namespaceResult.Types.First().Node.GetFirstToken().LeadingTrivia.First(o => o.IsKind(SyntaxKind.WhitespaceTrivia));

                    //TODO: check if Task is conflicted inside namespace
                    if (!hasTaskUsing && namespaceNode.Usings.All(o => o.Name.ToString() != "System.Threading.Tasks"))
                    {
                        namespaceNode = namespaceNode.AddUsing("System.Threading.Tasks", TriviaList(leadingTrivia));
                    }
                    // TODO: add locking namespaces

                    namespaceNodes.Add(namespaceNode
                                       .WithMembers(List(typeNodes)));
                }
            }
            if (!namespaceNodes.Any())
            {
                return(result);
            }
            // Update the original node
            var origRootNode = rootNode;

            foreach (var rewrittenNode in rewrittenNodes)
            {
                origRootNode = rootNode.ReplaceNode(rootNode.GetAnnotatedNodes(rewrittenNode.Annotation).First(), rewrittenNode.TransformedNode);
            }
            if (rootNode != origRootNode)
            {
                result.OriginalModifiedNode = origRootNode;
            }

            // Create the new node
            rootNode = rootNode
                       .WithMembers(List(namespaceNodes));
            // Add auto-generated comment
            var token = rootNode.DescendantTokens().First();

            rootNode = rootNode.ReplaceToken(token, token.AddAutoGeneratedTrivia());

            result.TransformedNode = rootNode;
            return(result);
        }