private MethodTransformationResult TransformMethod(TypeTransformationMetadata typeMetadata, IMethodAnalyzationResult methodResult) { var result = new MethodTransformationResult(methodResult); if (methodResult.Conversion == MethodConversion.Ignore) { return(result); } var methodNode = methodResult.Node; var methodBodyNode = methodResult.GetBodyNode(); if (methodBodyNode == null) { result.TransformedNode = methodNode.ReturnAsTask(methodResult.Symbol) .WithIdentifier(Identifier(methodNode.Identifier.Value + "Async")); return(result); } var startMethodSpan = methodResult.Node.Span.Start; methodNode = methodNode.WithAdditionalAnnotations(new SyntaxAnnotation(result.Annotation)); startMethodSpan -= methodNode.SpanStart; // TODO: get leading trivia for the method // 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) { 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); } var referenceAnnotations = new Dictionary <string, IFunctionReferenceAnalyzationResult>(); foreach (var referenceResult in methodResult.CrefMethodReferences .Union(methodResult.MethodReferences) .Where(o => o.GetConversion() == ReferenceConversion.ToAsync)) { var reference = referenceResult.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))); referenceAnnotations.Add(annotation, referenceResult); } // 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"))); } foreach (var pair in referenceAnnotations) { var nameNode = methodNode.GetAnnotatedNodes(pair.Key).OfType <SimpleNameSyntax>().First(); var funReferenceResult = pair.Value; var invokeFuncReferenceResult = funReferenceResult as IInvokeFunctionReferenceAnalyzationResult; // If we have a cref or a non awaitable invocation just change the name to the async counterpart if (invokeFuncReferenceResult == null || !invokeFuncReferenceResult.AwaitInvocation) { var statement = nameNode.Ancestors().OfType <StatementSyntax>().First(); var newNameNode = nameNode.WithIdentifier(Identifier(funReferenceResult.AsyncCounterpartName)); var newStatement = statement.ReplaceNode(nameNode, newNameNode); if (invokeFuncReferenceResult?.UseAsReturnValue == true) { newStatement = newStatement.ToReturnStatement(); } methodNode = methodNode .ReplaceNode(statement, newStatement); } } if (methodResult.OmitAsync) { // TODO: wrap in a task when calling non taskable method or throwing an exception in a non precondition statement } result.TransformedNode = methodNode; return(result); }
public MethodTransformationResult(IMethodAnalyzationResult methodResult) : base(methodResult.Node) { MethodAnalyzationResult = methodResult; }
public MethodTransformationResult(IMethodAnalyzationResult result) : base(result.Node) { AnalyzationResult = result; }