Example #1
0
        private TypeDeclarationSyntax TransformProperty(PropertyTransformationResult propertyTransform, TypeDeclarationSyntax newTypeNode, TypeTransformationResult transformResult,
                                                        INamespaceTransformationMetadata namespaceMetadata, SyntaxTrivia memberWhitespace, bool onlyMissingMembers)
        {
            var propertyNode = newTypeNode.GetAnnotatedNodes(propertyTransform.Annotation)
                               .OfType <PropertyDeclarationSyntax>()
                               .First();
            var transformedNode = TransformProperty(propertyNode, !onlyMissingMembers, propertyTransform, transformResult, namespaceMetadata);

            foreach (var transformedAccessor in transformedNode.TransformedAccessors.Where(o => o.Transformed != null))
            {
                foreach (var transformer in _configuration.MethodTransformers)
                {
                    var methodTransformResult = transformer.Transform(transformedAccessor, transformResult, namespaceMetadata);
                    if (methodTransformResult == MethodTransformerResult.Skip)
                    {
                        continue;
                    }
                    transformedAccessor.Transformed = methodTransformResult.TransformedNode ?? transformedAccessor.Transformed;
                    if (methodTransformResult.Fields != null)
                    {
                        if (transformedNode.Fields == null)
                        {
                            transformedNode.Fields = new List <FieldDeclarationSyntax>(1);
                        }
                        transformedNode.Fields.AddRange(methodTransformResult.Fields);
                        // Update member names  for next transformators
                        foreach (var variable in methodTransformResult.Fields.SelectMany(o => o.Declaration.Variables))
                        {
                            transformResult.MemberNames = transformResult.MemberNames.Add(variable.Identifier.Text);
                        }
                    }
                    if (methodTransformResult.Methods != null)
                    {
                        transformedNode.AddMethods(methodTransformResult.Methods);
                        // Update member names for next transformators
                        foreach (var method in methodTransformResult.Methods)
                        {
                            transformResult.MemberNames = transformResult.MemberNames.Add(method.Identifier.Text);
                        }
                    }
                }
                propertyTransform.AddMethod(transformedAccessor.Transformed);
            }
            newTypeNode = newTypeNode.AppendMembers(propertyNode, propertyTransform.Fields, propertyTransform.Methods);
            // We need to remove the property when generating only the missing members
            if (onlyMissingMembers || propertyTransform.AnalyzationResult.Conversion == PropertyConversion.Ignore)
            {
                // We need to add a whitespace trivia to keep directives as they will not have any leading whitespace
                newTypeNode = newTypeNode.RemoveNodeKeepDirectives(propertyTransform.Annotation, memberWhitespace,
                                                                   transformResult.EndOfLineTrivia);
            }
            return(newTypeNode);
        }
Example #2
0
        private RootTypeTransformationResult TransformType(ITypeAnalyzationResult rootTypeResult, INamespaceTransformationMetadata namespaceMetadata, bool onlyMissingMembers)
        {
            var rootTypeNode        = rootTypeResult.Node;
            var startRootTypeSpan   = rootTypeNode.SpanStart;
            var rootTransformResult = new RootTypeTransformationResult(rootTypeResult)
            {
                MemberNames = rootTypeResult.Symbol.MemberNames.ToImmutableHashSet()
            };

            // We do this here because we want that the root node has span start equal to 0
            rootTypeNode       = rootTypeNode.WithAdditionalAnnotations(new SyntaxAnnotation(rootTransformResult.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.
            // We need to annotate also the ignored types to be later removed
            foreach (var typeResult in rootTypeResult.GetSelfAndDescendantsTypes())
            {
                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);
                var leadingWhitespace = typeNode.GetLeadingWhitespace();
                TypeTransformationResult transformResult;
                if (typeNode == rootTypeNode)
                {
                    transformResult = rootTransformResult;
                    transformResult.IndentTrivia = typeNode.GetIndent(leadingWhitespace, namespaceMetadata.LeadingWhitespaceTrivia);
                }
                else
                {
                    transformResult = new TypeTransformationResult(typeResult)
                    {
                        MemberNames  = typeResult.Symbol.MemberNames.ToImmutableHashSet(),
                        IndentTrivia = typeNode.GetIndent(leadingWhitespace)
                    };
                    rootTypeNode = rootTypeNode.ReplaceNode(typeNode, typeNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformResult.Annotation)));
                    rootTransformResult.DescendantTransformedTypes.Add(transformResult);
                }
                transformResult.LeadingWhitespaceTrivia = leadingWhitespace;
                transformResult.EndOfLineTrivia         = typeNode.GetEndOfLine();

                if (typeResult.Conversion == TypeConversion.Ignore)
                {
                    continue;                     // The ignored type shall be only annotated
                }

                // TypeReferences can be changes only if we create a new type
                if (typeResult.Conversion == TypeConversion.NewType || typeResult.Conversion == TypeConversion.Copy)
                {
                    foreach (var typeReference in typeResult.TypeReferences.Where(o => o.TypeAnalyzationResult.Conversion == TypeConversion.NewType))
                    {
                        var reference       = typeReference.ReferenceLocation;
                        var refSpanStart    = reference.Location.SourceSpan.Start - startRootTypeSpan;
                        var refSpanLength   = reference.Location.SourceSpan.Length;
                        var nameNode        = rootTypeNode.GetSimpleName(refSpanStart, refSpanLength, typeReference.IsCref);
                        var transformedNode = new TransformationResult(nameNode)
                        {
                            Transformed = nameNode.WithIdentifier(Identifier(nameNode.Identifier.ValueText + "Async").WithTriviaFrom(nameNode.Identifier))
                        };
                        transformResult.TransformedNodes.Add(transformedNode);
                        rootTypeNode = rootTypeNode.ReplaceNode(nameNode, nameNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformedNode.Annotation)));
                    }
                }

                foreach (var fieldResult in typeResult.Fields)
                {
                    var fieldSpanStart  = fieldResult.Node.SpanStart - startRootTypeSpan;
                    var fieldSpanLength = fieldResult.Node.Span.Length;
                    var fieldNode       = rootTypeNode.DescendantNodes()
                                          .OfType <BaseFieldDeclarationSyntax>()
                                          .First(o => o.SpanStart == fieldSpanStart && o.Span.Length == fieldSpanLength);
                    var transformedNode = new FieldTransformationResult(fieldResult);
                    transformResult.TransformedFields.Add(transformedNode);
                    rootTypeNode = rootTypeNode.ReplaceNode(fieldNode, fieldNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformedNode.Annotation)));
                }

                // Annotate and save an empty method transformation result
                foreach (var methodResult in typeResult.Methods /*.Where(o => o.Conversion != MethodConversion.Ignore)*/)
                {
                    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);
                    // Only create the transformation result for the method and transform the method later as the method may change
                    // (a directive may be added to the method when removing type members)
                    var transformedNode = new MethodTransformationResult(methodResult);
                    transformResult.TransformedMethods.Add(transformedNode);
                    rootTypeNode = rootTypeNode.ReplaceNode(methodNode, methodNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformedNode.Annotation)));

                    // Annotate all locks inside the method before the transformations begins as will be easier to transform them if needed
                    foreach (var lockData in methodResult.Locks)
                    {
                        var lockSpanStart  = lockData.Node.SpanStart - startRootTypeSpan;
                        var lockSpanLength = lockData.Node.Span.Length;
                        var lockNode       = rootTypeNode.DescendantNodes()
                                             .OfType <LockStatementSyntax>()
                                             .First(o => o.SpanStart == lockSpanStart && o.Span.Length == lockSpanLength);
                        var lockTransformedNode = new LockTransformationResult(lockData);
                        transformedNode.TransformedLocks.Add(lockTransformedNode);
                        rootTypeNode = rootTypeNode.ReplaceNode(lockNode,
                                                                lockNode.WithAdditionalAnnotations(new SyntaxAnnotation(lockTransformedNode.Annotation)));
                    }
                }

                foreach (var methodResult in typeResult.SpecialMethods)
                {
                    var methodSpanStart  = methodResult.GetNode().SpanStart - startRootTypeSpan;
                    var methodSpanLength = methodResult.GetNode().Span.Length;
                    var methodNode       = rootTypeNode.DescendantNodes()
                                           .OfType <BaseMethodDeclarationSyntax>()
                                           .First(o => o.SpanStart == methodSpanStart && o.Span.Length == methodSpanLength);
                    var transformedNode = new FunctionTransformationResult(methodResult);
                    transformResult.TransformedSpecialMethods.Add(transformedNode);
                    rootTypeNode = rootTypeNode.ReplaceNode(methodNode, methodNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformedNode.Annotation)));
                }


                foreach (var propertyResult in typeResult.Properties)
                {
                    var spanStart  = propertyResult.Node.SpanStart - startRootTypeSpan;
                    var spanLength = propertyResult.Node.Span.Length;
                    var node       = rootTypeNode.DescendantNodes()
                                     .OfType <PropertyDeclarationSyntax>()
                                     .First(o => o.SpanStart == spanStart && o.Span.Length == spanLength);
                    var transformedNode = new PropertyTransformationResult(propertyResult);
                    transformResult.TransformedProperties.Add(transformedNode);
                    rootTypeNode = rootTypeNode.ReplaceNode(node, node.WithAdditionalAnnotations(new SyntaxAnnotation(transformedNode.Annotation)));
                }
            }
            // Save the orignal node that was only annotated
            var originalAnnotatedNode = rootTypeNode;

            // Now we can start transforming the type. Start from the bottom in order to preserve replaced nested types
            foreach (var transformResult in rootTransformResult.GetSelfAndDescendantTransformedTypes().OrderByDescending(o => o.OriginalNode.SpanStart))
            {
                var typeResult = transformResult.AnalyzationResult;

                // Add partial keyword on the original node if not present
                if ((typeResult.Conversion == TypeConversion.Partial || onlyMissingMembers) && !typeResult.IsPartial)
                {
                    if (rootTransformResult.OriginalModified == null)
                    {
                        rootTransformResult.OriginalModified = originalAnnotatedNode;
                    }
                    var typeNode = rootTransformResult.OriginalModified.GetAnnotatedNodes(transformResult.Annotation).OfType <TypeDeclarationSyntax>().First();
                    rootTransformResult.OriginalModified = rootTransformResult.OriginalModified.ReplaceNode(typeNode, typeNode.AddPartial());
                }
                if (typeResult.Conversion == TypeConversion.Ignore ||
                    (
                        onlyMissingMembers &&
                        !typeResult.GetSelfAndDescendantsTypes().SelectMany(o => o.MethodsAndAccessors).Any(o => o.Missing)
                    ))
                {
                    rootTypeNode = rootTypeNode.RemoveNodeKeepDirectives(transformResult.Annotation, transformResult.LeadingWhitespaceTrivia,
                                                                         transformResult.EndOfLineTrivia);
                    continue;
                }

                var memberWhitespace = Whitespace(transformResult.LeadingWhitespaceTrivia.ToFullString() + transformResult.IndentTrivia.ToFullString());

                if (typeResult.Conversion == TypeConversion.Partial || onlyMissingMembers)
                {
                    // First we need to remove ignored method
                    var typeNode = rootTypeNode.GetAnnotatedNodes(transformResult.Annotation).OfType <TypeDeclarationSyntax>().First();
                    // We need to remove the attributes as they cannot be defined in both partial classes
                    var newTypeNode = typeNode.AddPartial().WithoutAttributes();

                    // We need to remove all other members that are not methods, properties or types
                    newTypeNode = newTypeNode.RemoveMembersKeepDirectives(o =>
                                                                          !(o is BaseMethodDeclarationSyntax ||
                                                                            o is TypeDeclarationSyntax ||
                                                                            o is PropertyDeclarationSyntax ||
                                                                            o is BaseFieldDeclarationSyntax), memberWhitespace,
                                                                          transformResult.EndOfLineTrivia);

                    rootTypeNode = TransformTypeMembers(namespaceMetadata, onlyMissingMembers, transformResult, newTypeNode,
                                                        memberWhitespace, rootTypeNode, typeNode);
                }
                // If the root type has to be a new type then all nested types have to be new types
                else if (typeResult.Conversion == TypeConversion.NewType || typeResult.Conversion == TypeConversion.Copy)
                {
                    var typeNode        = rootTypeNode.GetAnnotatedNodes(transformResult.Annotation).OfType <TypeDeclarationSyntax>().First();
                    var identifierToken = typeNode.ChildTokens().First(o => o.IsKind(SyntaxKind.IdentifierToken));
                    var newTypeNode     = typeResult.Conversion == TypeConversion.NewType
                                                ? typeNode.ReplaceToken(identifierToken, Identifier(identifierToken.ValueText + "Async").WithTriviaFrom(identifierToken))
                                                : typeNode;

                    rootTypeNode = TransformTypeMembers(namespaceMetadata, onlyMissingMembers, transformResult, newTypeNode,
                                                        memberWhitespace, rootTypeNode, typeNode);
                }
            }

            rootTransformResult.Transformed = rootTypeNode;
            return(rootTransformResult);
        }
Example #3
0
        private void TransformPropertyAccessor(SyntaxNode node, PropertyTransformationResult propertyResult, AccessorTransformationResult result, ITypeTransformationMetadata typeMetadata,
                                               INamespaceTransformationMetadata namespaceMetadata)
        {
            var methodResult = result.AnalyzationResult;

            result.BodyLeadingWhitespaceTrivia = propertyResult.BodyLeadingWhitespaceTrivia;
            result.LeadingWhitespaceTrivia     = propertyResult.LeadingWhitespaceTrivia;
            result.EndOfLineTrivia             = propertyResult.EndOfLineTrivia;
            result.IndentTrivia = propertyResult.IndentTrivia;

            var methodConversion = methodResult.Conversion;

            if (!methodConversion.HasFlag(MethodConversion.ToAsync))
            {
                return;
            }
            var methodNode = MethodDeclaration(
                methodResult.Symbol.MethodKind != MethodKind.PropertySet
                                        ? propertyResult.OriginalNode.Type
                                        : IdentifierName(nameof(Task)).WithTriviaFrom(propertyResult.OriginalNode.Type),
                methodResult.AsyncCounterpartName
                )
                             .WithModifiers(propertyResult.OriginalNode.Modifiers)
                             .WithLeadingTrivia(propertyResult.OriginalNode.GetLeadingTrivia());
            var methodBodyNode = methodResult.GetBodyNode();

            if (methodBodyNode == null)
            {
                methodNode = methodNode
                             .WithSemicolonToken(Token(TriviaList(), SyntaxKind.SemicolonToken, TriviaList(propertyResult.EndOfLineTrivia)));
                result.Transformed = methodNode;
                return;
            }

            var startMethodSpan = methodResult.Node.Span.Start;

            node             = node.WithAdditionalAnnotations(new SyntaxAnnotation(result.Annotation));
            startMethodSpan -= node.SpanStart;

            // First we need to annotate nodes that will be modified in order to find them later on.
            // We cannot rely on spans after the first modification as they will change
            var typeReferencesAnnotations = new List <string>();

            foreach (var typeReference in methodResult.TypeReferences.Where(o => o.TypeAnalyzationResult.Conversion == TypeConversion.NewType))
            {
                var reference  = typeReference.ReferenceLocation;
                var startSpan  = reference.Location.SourceSpan.Start - startMethodSpan;
                var nameNode   = node.GetSimpleName(startSpan, reference.Location.SourceSpan.Length);
                var annotation = Guid.NewGuid().ToString();
                node = node.ReplaceNode(nameNode, nameNode.WithAdditionalAnnotations(new SyntaxAnnotation(annotation)));
                typeReferencesAnnotations.Add(annotation);
            }

            foreach (var childFunction in methodResult.ChildFunctions.Where(o => o.Conversion != MethodConversion.Ignore))
            {
                var functionNode   = childFunction.GetNode();
                var functionKind   = functionNode.Kind();
                var typeSpanStart  = functionNode.SpanStart - startMethodSpan;
                var typeSpanLength = functionNode.Span.Length;
                var funcNode       = node.DescendantNodesAndSelf()
                                     .First(o => o.IsKind(functionKind) && o.SpanStart == typeSpanStart && o.Span.Length == typeSpanLength);
                var transformFuncResult = TransformFunction(childFunction, result, typeMetadata, namespaceMetadata);
                result.TransformedFunctions.Add(transformFuncResult);
                node = node.ReplaceNode(funcNode, funcNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformFuncResult.Annotation)));
            }


            foreach (var referenceResult in methodResult.FunctionReferences
                     .Where(o => o.GetConversion() == ReferenceConversion.ToAsync))
            {
                var transfromReference = new FunctionReferenceTransformationResult(referenceResult);
                var isCref             = referenceResult.IsCref;
                var reference          = referenceResult.ReferenceLocation;
                var startSpan          = reference.Location.SourceSpan.Start - startMethodSpan;
                var nameNode           = node.GetSimpleName(startSpan, reference.Location.SourceSpan.Length, isCref);
                node = node.ReplaceNode(nameNode, nameNode.WithAdditionalAnnotations(new SyntaxAnnotation(transfromReference.Annotation)));
                result.TransformedFunctionReferences.Add(transfromReference);

                if (isCref || referenceResult.IsNameOf || !methodResult.OmitAsync)
                {
                    continue;
                }
                // We need to annotate the reference node (InvocationExpression, IdentifierName) in order to know if we need to wrap the node in a Task.FromResult
                var refNode       = referenceResult.ReferenceNode;
                var bodyReference = (IBodyFunctionReferenceAnalyzationResult)referenceResult;
                if (bodyReference.UseAsReturnValue || refNode.IsReturned())
                {
                    startSpan = refNode.SpanStart - startMethodSpan;
                    var referenceNode = node.DescendantNodes().First(o => o.SpanStart == startSpan && o.Span.Length == refNode.Span.Length);
                    node = node.ReplaceNode(referenceNode, referenceNode.WithAdditionalAnnotations(new SyntaxAnnotation(Annotations.TaskReturned)));
                }
            }

            // Modify references
            foreach (var refAnnotation in typeReferencesAnnotations)
            {
                var nameNode = node.GetAnnotatedNodes(refAnnotation).OfType <SimpleNameSyntax>().First();
                node = node
                       .ReplaceNode(nameNode, nameNode.WithIdentifier(Identifier(nameNode.Identifier.Value + "Async")));
            }

            foreach (var transformFunction in result.TransformedFunctions)
            {
                var funcNode = node.GetAnnotatedNodes(transformFunction.Annotation).First();
                node = node
                       .ReplaceNode(funcNode, transformFunction.Transformed);
            }

            // We have to order by OriginalStartSpan in order to have consistent formatting when adding awaits
            foreach (var transfromReference in result.TransformedFunctionReferences.OrderByDescending(o => o.OriginalStartSpan))
            {
                node = TransformFunctionReference(node, methodResult, transfromReference, typeMetadata, namespaceMetadata);
            }

            if (methodResult.Symbol.MethodKind == MethodKind.PropertySet)
            {
                methodNode = methodNode.WithParameterList(
                    methodNode.ParameterList.WithParameters(
                        SingletonSeparatedList(
                            Parameter(Identifier(TriviaList(), "value", TriviaList()))
                            .WithType(propertyResult.OriginalNode.Type.WithoutTrivia().WithTrailingTrivia(TriviaList(Space)))
                            )
                        )
                    );
            }

            if (node is ArrowExpressionClauseSyntax arrowNode)
            {
                methodNode = methodNode
                             .WithExpressionBody(arrowNode)
                             .WithSemicolonToken(Token(TriviaList(), SyntaxKind.SemicolonToken, TriviaList(propertyResult.EndOfLineTrivia)));
            }
            else if (node is AccessorDeclarationSyntax accessorNode)
            {
                if (accessorNode.ExpressionBody != null)
                {
                    methodNode = methodNode
                                 .WithExpressionBody(accessorNode.ExpressionBody)
                                 .WithSemicolonToken(Token(TriviaList(), SyntaxKind.SemicolonToken, TriviaList(propertyResult.EndOfLineTrivia)));
                }
                else
                {
                    methodNode = methodNode
                                 .WithBody(accessorNode.Body);
                }
            }
            methodNode         = FixupBodyFormatting(methodNode, result);
            result.Transformed = methodNode;
        }
Example #4
0
        private PropertyTransformationResult TransformProperty(PropertyDeclarationSyntax propertyNode, bool canCopy, PropertyTransformationResult result, ITypeTransformationMetadata typeMetadata,
                                                               INamespaceTransformationMetadata namespaceMetadata)
        {
            var analyzeResult = result.AnalyzationResult;
            var startRootSpan = analyzeResult.Node.SpanStart;

            // Calculate whitespace method trivias
            result.EndOfLineTrivia             = propertyNode.GetEndOfLine();
            result.LeadingWhitespaceTrivia     = propertyNode.GetLeadingWhitespace();
            result.IndentTrivia                = propertyNode.GetIndent(result.LeadingWhitespaceTrivia, typeMetadata.LeadingWhitespaceTrivia);
            result.BodyLeadingWhitespaceTrivia = Whitespace(result.LeadingWhitespaceTrivia.ToFullString() + result.IndentTrivia.ToFullString());

            if (analyzeResult.Conversion == PropertyConversion.Ignore && analyzeResult.GetAccessors().All(o => o.Conversion == MethodConversion.Ignore))
            {
                return(result);
            }

            propertyNode   = propertyNode.WithAdditionalAnnotations(new SyntaxAnnotation(result.Annotation));
            startRootSpan -= propertyNode.SpanStart;

            foreach (var accessorResult in analyzeResult.GetAccessors().Where(o => o.Conversion != MethodConversion.Ignore))
            {
                var spanStart    = accessorResult.Node.SpanStart - startRootSpan;
                var spanLength   = accessorResult.Node.Span.Length;
                var accessorNode = propertyNode.DescendantNodes()
                                   .First(o => o.SpanStart == spanStart && o.Span.Length == spanLength);
                var transformedNode = new AccessorTransformationResult(accessorResult);
                result.TransformedAccessors.Add(transformedNode);
                propertyNode = propertyNode.ReplaceNode(accessorNode, accessorNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformedNode.Annotation)));
            }

            if (canCopy && result.AnalyzationResult.Conversion == PropertyConversion.Copy)
            {
                result.Transformed = result.OriginalNode;
            }

            foreach (var accessorResult in result.TransformedAccessors.OrderByDescending(o => o.OriginalStartSpan))
            {
                var accessorNode = propertyNode.GetAnnotatedNodes(accessorResult.Annotation)
                                   .First();
                TransformPropertyAccessor(accessorNode, result, accessorResult, typeMetadata, namespaceMetadata);
            }

            return(result);
        }