private MethodTransformationResult TransformMethod(MethodDeclarationSyntax methodNode, bool canCopy, MethodTransformationResult result, ITypeTransformationMetadata typeMetadata, INamespaceTransformationMetadata namespaceMetadata) { //var result = new MethodTransformationResult(methodResult); var methodResult = result.AnalyzationResult; var methodConversion = methodResult.Conversion; if (!canCopy) { methodConversion &= ~MethodConversion.Copy; } //var methodNode = customNode ?? methodResult.Node; var methodBodyNode = methodResult.GetBodyNode(); // Calculate whitespace method trivias result.EndOfLineTrivia = methodNode.GetEndOfLine(); result.LeadingWhitespaceTrivia = methodNode.GetLeadingWhitespace(); result.IndentTrivia = methodNode.GetIndent(result.LeadingWhitespaceTrivia, typeMetadata.LeadingWhitespaceTrivia); result.BodyLeadingWhitespaceTrivia = Whitespace(result.LeadingWhitespaceTrivia.ToFullString() + result.IndentTrivia.ToFullString()); if (methodConversion == MethodConversion.Ignore) { return(result); } if (methodBodyNode == null) { if (methodConversion.HasFlag(MethodConversion.ToAsync)) { result.Transformed = methodNode; if (methodConversion.HasFlag(MethodConversion.Copy)) { result.AddMethod(methodResult.Node); } return(result); } if (methodConversion.HasFlag(MethodConversion.Copy)) { result.Transformed = methodResult.Node; } return(result); } var startMethodSpan = methodResult.Node.Span.Start; methodNode = methodNode.WithAdditionalAnnotations(new SyntaxAnnotation(result.Annotation)); startMethodSpan -= methodNode.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 = methodNode.GetSimpleName(startSpan, reference.Location.SourceSpan.Length); var annotation = Guid.NewGuid().ToString(); methodNode = methodNode.ReplaceNode(nameNode, nameNode.WithAdditionalAnnotations(new SyntaxAnnotation(annotation))); typeReferencesAnnotations.Add(annotation); } // For copied methods we need just to replace type references if (methodConversion.HasFlag(MethodConversion.Copy)) { var copiedMethod = methodNode; // Modify references foreach (var refAnnotation in typeReferencesAnnotations) { var nameNode = copiedMethod.GetAnnotatedNodes(refAnnotation).OfType <SimpleNameSyntax>().First(); copiedMethod = copiedMethod .ReplaceNode(nameNode, nameNode.WithIdentifier(Identifier(nameNode.Identifier.Value + "Async").WithTriviaFrom(nameNode.Identifier))); } if (!methodConversion.HasFlag(MethodConversion.ToAsync)) { result.Transformed = copiedMethod; return(result); } result.AddMethod(copiedMethod.WithoutAnnotations(result.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 = methodNode.DescendantNodesAndSelf() .First(o => o.IsKind(functionKind) && o.SpanStart == typeSpanStart && o.Span.Length == typeSpanLength); var transformFuncResult = TransformFunction(childFunction, result, typeMetadata, namespaceMetadata); result.TransformedFunctions.Add(transformFuncResult); methodNode = methodNode.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 = methodNode.GetSimpleName(startSpan, reference.Location.SourceSpan.Length, isCref); methodNode = methodNode.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 = methodNode.DescendantNodes().First(o => o.SpanStart == startSpan && o.Span.Length == refNode.Span.Length); methodNode = methodNode.ReplaceNode(referenceNode, referenceNode.WithAdditionalAnnotations(new SyntaxAnnotation(Annotations.TaskReturned))); } } // Before modifying, fixup method body formatting in order to prevent weird formatting when adding additinal code methodNode = FixupBodyFormatting(methodNode, result); // Modify references foreach (var refAnnotation in typeReferencesAnnotations) { var nameNode = methodNode.GetAnnotatedNodes(refAnnotation).OfType <SimpleNameSyntax>().First(); methodNode = methodNode .ReplaceNode(nameNode, nameNode.WithIdentifier(Identifier(nameNode.Identifier.Value + "Async").WithTriviaFrom(nameNode.Identifier))); } foreach (var transformFunction in result.TransformedFunctions) { var funcNode = methodNode.GetAnnotatedNodes(transformFunction.Annotation).First(); methodNode = methodNode .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)) { methodNode = TransformFunctionReference(methodNode, methodResult, transfromReference, typeMetadata, namespaceMetadata); } result.Transformed = methodNode; return(result); }