Пример #1
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);
        }
Пример #2
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;
        }