コード例 #1
0
        public SyntaxNode Transform(IFunctionTransformationResult transformResult, ITypeTransformationMetadata typeMetadata,
                                    INamespaceTransformationMetadata namespaceMetadata)
        {
            var methodResult = transformResult.AnalyzationResult;

            if (!methodResult.Conversion.HasFlag(MethodConversion.ToAsync))
            {
                return(null);
            }
            var functionNode = transformResult.Transformed;

            if (functionNode.GetFunctionBody() == null)
            {
                return(Update(functionNode, methodResult, namespaceMetadata));
            }
            if (methodResult.SplitTail || methodResult.PreserveReturnType || !methodResult.OmitAsync)
            {
                if (!methodResult.OmitAsync)
                {
                    functionNode = functionNode.AddAsync();
                }
                return(Update(functionNode, methodResult, namespaceMetadata));
            }
            var rewriter = new ReturnTaskFunctionRewriter(transformResult, namespaceMetadata);

            functionNode = rewriter.Visit(functionNode);
            return(Update(functionNode, methodResult, namespaceMetadata));
        }
コード例 #2
0
        public MethodTransformerResult Transform(IMethodOrAccessorTransformationResult transformResult,
                                                 ITypeTransformationMetadata typeMetadata, INamespaceTransformationMetadata namespaceMetadata)
        {
            var methodResult = transformResult.AnalyzationResult;

            if (!methodResult.Conversion.HasFlag(MethodConversion.ToAsync))
            {
                return(MethodTransformerResult.Skip);
            }
            var methodNode = transformResult.Transformed;

            if (methodNode.GetFunctionBody() == null)
            {
                return(Update(methodNode, methodResult, namespaceMetadata));
            }
            if (methodResult.SplitTail || methodResult.PreserveReturnType || !methodResult.OmitAsync)
            {
                if (!methodResult.OmitAsync)
                {
                    methodNode = methodNode.AddAsync();
                }
                return(Update(methodNode, methodResult, namespaceMetadata));
            }
            var rewriter = new ReturnTaskFunctionRewriter(transformResult, namespaceMetadata);

            methodNode = (MethodDeclarationSyntax)rewriter.VisitMethodDeclaration(methodNode);
            return(Update(methodNode, methodResult, namespaceMetadata));
        }
コード例 #3
0
        // TODO: helper method
        private static string GetLockFieldName(ISymbol symbol, bool isStatic, ITypeTransformationMetadata typeTransformMetadata, string prefix = "", string postfix = "")
        {
            var fieldName    = GetLockFieldName(symbol, isStatic, prefix, postfix);
            var currentIdx   = 2;
            var newFieldName = fieldName;

            while (typeTransformMetadata.MemberNames.Contains(newFieldName))
            {
                newFieldName = fieldName + currentIdx;
                currentIdx++;
            }
            return(newFieldName);
        }
コード例 #4
0
        public MethodTransformerResult Transform(IMethodOrAccessorTransformationResult transformResult,
                                                 ITypeTransformationMetadata typeMetadata, INamespaceTransformationMetadata namespaceMetadata)
        {
            if (transformResult.AnalyzationResult.OmitAsync)
            {
                return(MethodTransformerResult.Skip);
            }

            var result = _rewriter.VisitMethod(transformResult.Transformed);

            return(result == null
                                ? MethodTransformerResult.Skip
                                : MethodTransformerResult.Update(result));
        }
コード例 #5
0
        public MethodTransformerResult Transform(IMethodOrAccessorTransformationResult methodTransformResult,
                                                 ITypeTransformationMetadata typeMetadata, INamespaceTransformationMetadata namespaceMetadata)
        {
            if (!_isEnabled)
            {
                return(MethodTransformerResult.Skip);
            }

            var leadingTrivia        = methodTransformResult.Transformed.GetLeadingTrivia();
            var documentation        = leadingTrivia.FirstOrDefault(o => o.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia));
            var documentationNode    = (DocumentationCommentTriviaSyntax)documentation.GetStructure();
            var newDocumentationNode = documentationNode ??
                                       DocumentationCommentTrivia(SyntaxKind.SingleLineDocumentationCommentTrivia);

            // Summary
            newDocumentationNode = ProcessTag(
                newDocumentationNode,
                methodTransformResult,
                "summary",
                _configuration.AddOrReplaceMethodSummary,
                _configuration.CanRemoveMethodSummary, true);

            // Remarks
            newDocumentationNode = ProcessTag(
                newDocumentationNode,
                methodTransformResult,
                "remarks",
                _configuration.AddOrReplaceMethodRemarks,
                _configuration.CanRemoveMethodRemarks, false);


            var transformed = methodTransformResult.Transformed;

            if (documentationNode != null)
            {
                transformed = transformed.ReplaceNode(documentationNode, newDocumentationNode);
            }
            else
            {
                // We have to append our documentation before the whitespace trivia
                var whitespaceIndex = leadingTrivia.IndexOf(SyntaxKind.WhitespaceTrivia);
                if (whitespaceIndex <= 0)
                {
                    whitespaceIndex = 0;
                }
                transformed = transformed.WithLeadingTrivia(transformed.GetLeadingTrivia().Insert(whitespaceIndex, Trivia(newDocumentationNode)));
            }

            return(MethodTransformerResult.Update(transformed));
        }
コード例 #6
0
        public MethodTransformerResult Transform(IMethodOrAccessorTransformationResult transformResult,
                                                 ITypeTransformationMetadata typeMetadata, INamespaceTransformationMetadata namespaceMetadata)
        {
            var methodResult = transformResult.AnalyzationResult;

            if (!methodResult.HasYields || !methodResult.Conversion.HasFlag(MethodConversion.ToAsync))
            {
                return(MethodTransformerResult.Skip);
            }
            var methodNode = transformResult.Transformed;
            var rewriter   = new YieldRewriter(transformResult);

            methodNode = (MethodDeclarationSyntax)rewriter.VisitMethodDeclaration(methodNode);
            return(MethodTransformerResult.Update(methodNode));
        }
コード例 #7
0
 private SyntaxNode RunFunctionTransformers(
     FunctionTransformationResult functionTransform,
     ITypeTransformationMetadata transformResult,
     INamespaceTransformationMetadata namespaceMetadata)
 {
     if (functionTransform.Transformed == null)
     {
         return(null);
     }
     foreach (var transformer in _configuration.FunctionTransformers)
     {
         functionTransform.Transformed = transformer.Transform(functionTransform, transformResult, namespaceMetadata) ??
                                         functionTransform.Transformed;
     }
     return(functionTransform.Transformed);
 }
        public SyntaxNode Transform(IFunctionTransformationResult transformResult, ITypeTransformationMetadata typeMetadata,
                                    INamespaceTransformationMetadata namespaceMetadata)
        {
            var methodResult = transformResult.AnalyzationResult;
            var functionNode = transformResult.Transformed;

            if (
                !methodResult.Conversion.HasFlag(MethodConversion.ToAsync) ||
                methodResult.OmitAsync ||
                !methodResult.GetMethodOrAccessor().CancellationTokenRequired ||
                functionNode.GetFunctionBody() == null)
            {
                return(null);
            }

            var rewriter = new OperationCanceledExceptionFunctionRewriter(transformResult.EndOfLineTrivia, namespaceMetadata);

            return(rewriter.Visit(functionNode));
        }
        public MethodTransformerResult Transform(IMethodOrAccessorTransformationResult transformResult,
                                                 ITypeTransformationMetadata typeMetadata, INamespaceTransformationMetadata namespaceMetadata)
        {
            var methodResult = transformResult.AnalyzationResult;
            var methodNode   = transformResult.Transformed;

            if (
                !methodResult.Conversion.HasFlag(MethodConversion.ToAsync) ||
                methodResult.OmitAsync ||
                !methodResult.CancellationTokenRequired ||
                methodNode.GetFunctionBody() == null)
            {
                return(MethodTransformerResult.Skip);
            }

            var rewriter = new OperationCanceledExceptionFunctionRewriter(transformResult.EndOfLineTrivia, namespaceMetadata);

            methodNode = (MethodDeclarationSyntax)rewriter.VisitMethodDeclaration(methodNode);
            return(MethodTransformerResult.Update(methodNode));
        }
コード例 #10
0
        /// <summary>
        /// The method with SplitTail needs to be splitted into two methods
        /// </summary>
        public MethodTransformerResult Transform(IMethodOrAccessorTransformationResult transformResult,
                                                 ITypeTransformationMetadata typeMetadata, INamespaceTransformationMetadata namespaceMetadata)
        {
            var methodResult = transformResult.AnalyzationResult;

            if (!methodResult.SplitTail)
            {
                return(MethodTransformerResult.Skip);
            }

            var methodNode = transformResult.Transformed;
            // Tail method body shall contain all statements after preconditions
            var skipStatements = methodResult.Preconditions.Count;

            // If a cancellation guard was generated we need to skip also that
            if (_analyzeConfiguration.UseCancellationTokens && _analyzeConfiguration.CancellationTokens.Guards && methodResult.CancellationTokenRequired)
            {
                skipStatements++;
            }
            var tailMethodBody = methodNode.Body
                                 .WithStatements(new SyntaxList <StatementSyntax>()
                                                 .AddRange(methodNode.Body.Statements.Skip(skipStatements)));
            // Main method shall contain only preconditions and a call to the tail method
            var bodyStatements = new SyntaxList <StatementSyntax>()
                                 .AddRange(methodNode.Body.Statements.Take(skipStatements));
            ParameterListSyntax tailCallParameterList;
            // TODO: handle name collisions
            var tailIdentifier = Identifier("Internal" + methodNode.Identifier.Value);             // The transformed method has already the Async postfix
            MethodDeclarationSyntax      tailMethod   = null;
            LocalFunctionStatementSyntax tailFunction = null;

            if (_configuration.LocalFunctions)
            {
                tailFunction = LocalFunctionStatement(
                    methodNode.ReturnType.WithoutLeadingTrivia(),
                    tailIdentifier)
                               .WithParameterList(ParameterList()
                                                  .WithCloseParenToken(Token(TriviaList(), SyntaxKind.CloseParenToken, TriviaList(transformResult.EndOfLineTrivia))))
                               .AddAsync()
                               .WithLeadingTrivia(transformResult.LeadingWhitespaceTrivia)
                               .WithBody(tailMethodBody)
                               .AppendIndent(transformResult.IndentTrivia.ToFullString());
                // We do not need any parameter for the local function as we already have the parameters from the parent method
                tailCallParameterList = ParameterList();
            }
            else
            {
                var tailMethodModifiers = TokenList(
                    Token(TriviaList(transformResult.EndOfLineTrivia, transformResult.LeadingWhitespaceTrivia), SyntaxKind.PrivateKeyword, TriviaList(Space)));
                if (methodNode.Modifiers.Any(o => o.IsKind(SyntaxKind.StaticKeyword)))
                {
                    tailMethodModifiers = tailMethodModifiers.Add(Token(TriviaList(), SyntaxKind.StaticKeyword, TriviaList(Space)));
                }
                tailMethod = methodNode
                             .WithReturnType(methodNode.ReturnType.WithLeadingTrivia())            // Remove lead trivia in case the return type is the first node (eg. void Method())
                             .WithIdentifier(tailIdentifier)
                             .WithModifiers(tailMethodModifiers)
                             .AddAsync()
                             .WithBody(tailMethodBody);
                // Tail call shall contain the cancellation token parameter
                tailCallParameterList = methodNode.ParameterList;
            }

            var tailCall = ReturnStatement(
                Token(TriviaList(transformResult.BodyLeadingWhitespaceTrivia), SyntaxKind.ReturnKeyword, TriviaList(Space)),
                IdentifierName(tailIdentifier).Invoke(tailCallParameterList),
                Token(TriviaList(), SyntaxKind.SemicolonToken, TriviaList(transformResult.EndOfLineTrivia))
                );

            bodyStatements = bodyStatements.Add(tailCall);
            // Append local function at the end for easier reading
            if (tailFunction != null)
            {
                bodyStatements = bodyStatements.Add(tailFunction);
            }
            methodNode = methodNode.WithBody(methodNode.Body
                                             .WithStatements(bodyStatements));

            var result = MethodTransformerResult.Update(methodNode);

            if (tailMethod != null)
            {
                result.AddMethod(tailMethod);
            }
            return(result);
        }
コード例 #11
0
        private T TransformConditionalAccessToIfStatements <T>(
            T node,
            SimpleNameSyntax nameNode,
            ITypeTransformationMetadata typeMetadata,
            ConditionalAccessExpressionSyntax conditionalAccessNode,
            InvocationExpressionSyntax invokeNode) where T : SyntaxNode
        {
            var statement = (StatementSyntax)conditionalAccessNode.Ancestors().FirstOrDefault(o => o is StatementSyntax);

            if (statement == null || !(statement.Parent is BlockSyntax block))
            {
                // TODO: convert arrow method/property/function to a normal one
                // TODO: convert to block if there is no block
                throw new NotSupportedException(
                          $"Arrow method with null-conditional is not supported. Node: {conditionalAccessNode}");
            }

            var fnName = nameNode.Identifier.ValueText;
            // TODO: handle name collisions
            var variableName             = $"{char.ToLowerInvariant(fnName[0])}{fnName.Substring(1)}Task";
            var leadingTrivia            = statement.GetLeadingTrivia();
            var newConditionalAccessNode = ConditionalAccessExpression(
                conditionalAccessNode.Expression,
                invokeNode)
                                           .WithTriviaFrom(conditionalAccessNode);
            var localVar = LocalDeclarationStatement(
                VariableDeclaration(
                    IdentifierName(Identifier(leadingTrivia, "var", TriviaList(Space))),
                    SingletonSeparatedList(
                        VariableDeclarator(
                            Identifier(TriviaList(), variableName, TriviaList(Space)))
                        .WithInitializer(
                            EqualsValueClause(newConditionalAccessNode.WithoutTrivia())
                            .WithEqualsToken(Token(TriviaList(), SyntaxKind.EqualsToken, TriviaList(Space)))
                            )
                        )))
                           .WithSemicolonToken(Token(TriviaList(), SyntaxKind.SemicolonToken, TriviaList(typeMetadata.EndOfLineTrivia)));
            var index = block.Statements.IndexOf(statement);

            var variableAnnotation = Guid.NewGuid().ToString();
            var newBlock           = block.ReplaceNode(conditionalAccessNode,
                                                       conditionalAccessNode.WhenNotNull.ReplaceNode(invokeNode,
                                                                                                     IdentifierName(variableName)
                                                                                                     .WithAdditionalAnnotations(new SyntaxAnnotation(variableAnnotation))
                                                                                                     .WithLeadingTrivia(conditionalAccessNode.GetLeadingTrivia())
                                                                                                     .WithTrailingTrivia(conditionalAccessNode.GetTrailingTrivia())
                                                                                                     ));

            var variable = newBlock.GetAnnotatedNodes(variableAnnotation).OfType <IdentifierNameSyntax>().First();

            newBlock = newBlock.ReplaceNode(variable, variable.AddAwait(_configuration.ConfigureAwaitArgument));

            var ifBlock = Block()
                          .WithOpenBraceToken(
                Token(TriviaList(leadingTrivia), SyntaxKind.OpenBraceToken, TriviaList(typeMetadata.EndOfLineTrivia)))
                          .WithCloseBraceToken(
                Token(TriviaList(leadingTrivia), SyntaxKind.CloseBraceToken, TriviaList(typeMetadata.EndOfLineTrivia)))
                          .WithStatements(SingletonList(newBlock.Statements[index].AppendIndent(typeMetadata.IndentTrivia.ToFullString())));

            var ifStatement = IfStatement(
                BinaryExpression(
                    SyntaxKind.NotEqualsExpression,
                    IdentifierName(Identifier(TriviaList(), variableName, TriviaList(Space))),
                    LiteralExpression(SyntaxKind.NullLiteralExpression))
                .WithOperatorToken(
                    Token(TriviaList(), SyntaxKind.ExclamationEqualsToken, TriviaList(Space))),
                ifBlock
                )
                              .WithIfKeyword(
                Token(TriviaList(leadingTrivia), SyntaxKind.IfKeyword, TriviaList(Space)))
                              .WithCloseParenToken(
                Token(TriviaList(), SyntaxKind.CloseParenToken, TriviaList(typeMetadata.EndOfLineTrivia)));

            newBlock = block.WithStatements(
                block.Statements
                .RemoveAt(index)
                .InsertRange(index, new StatementSyntax[] { localVar, ifStatement })
                );

            return(node.ReplaceNode(block, newBlock));
        }
コード例 #12
0
        private T TransformFunctionReference <T>(T node, IFunctionAnalyzationResult funcResult, FunctionReferenceTransformationResult transfromReference,
                                                 ITypeTransformationMetadata typeMetadata,
                                                 INamespaceTransformationMetadata namespaceMetadata)
            where T : SyntaxNode
        {
            var nameNode                = node.GetAnnotatedNodes(transfromReference.Annotation).OfType <SimpleNameSyntax>().First();
            var funReferenceResult      = transfromReference.AnalyzationResult;
            var bodyFuncReferenceResult = funReferenceResult as IBodyFunctionReferenceAnalyzationResult;
            var newNameNode             = nameNode
                                          .WithIdentifier(Identifier(funReferenceResult.AsyncCounterpartName))
                                          .WithTriviaFrom(nameNode);

            transfromReference.Transformed = newNameNode;

            var cancellationTokenParamName = funcResult.GetMethodOrAccessor().CancellationTokenRequired ? "cancellationToken" : null;             // TODO: remove

            // If we have a cref change the name to the async counterpart and add/update arguments
            if (bodyFuncReferenceResult == null)
            {
                if (funReferenceResult.IsCref)
                {
                    var crefNode  = (NameMemberCrefSyntax)nameNode.Parent;
                    var paramList = new List <CrefParameterSyntax>();
                    // If the cref has already the parameters set then use them
                    if (crefNode.Parameters != null)
                    {
                        paramList.AddRange(crefNode.Parameters.Parameters);
                        // If the external async counterpart has a cancellation token, add it
                        if (funReferenceResult.AsyncCounterpartFunction == null &&
                            funReferenceResult.ReferenceSymbol.Parameters.Length <
                            funReferenceResult.AsyncCounterpartSymbol.Parameters.Length)
                        {
                            paramList.Add(CrefParameter(IdentifierName(nameof(CancellationToken))));
                        }
                    }
                    else
                    {
                        // We have to add the parameters to avoid ambiguity
                        var asyncSymbol = funReferenceResult.AsyncCounterpartSymbol;
                        paramList.AddRange(asyncSymbol.Parameters
                                           .Select(o => CrefParameter(o.Type
                                                                      .CreateTypeSyntax(true, namespaceMetadata.AnalyzationResult.IsIncluded(o.Type.ContainingNamespace?.ToString())))));
                    }

                    // If the async counterpart is internal and a token is required add a token parameter
                    if (funReferenceResult.AsyncCounterpartFunction?.GetMethodOrAccessor()?.CancellationTokenRequired == true)
                    {
                        paramList.Add(CrefParameter(IdentifierName(nameof(CancellationToken))));
                    }

                    node = node.ReplaceNestedNodes(
                        crefNode.Parent as QualifiedCrefSyntax,
                        crefNode,
                        crefNode
                        .ReplaceNode(nameNode, newNameNode)
                        .WithParameters(CrefParameterList(SeparatedList(paramList))),
                        rootNode => UpdateTypeAndRunReferenceTransformers(rootNode, funcResult, funReferenceResult, namespaceMetadata,
                                                                          (type, fullName) => rootNode.WithContainer(type.CreateTypeSyntax(true, fullName).WithTriviaFrom(rootNode.Container))),
                        childNode => RunReferenceTransformers(childNode, funcResult, funReferenceResult, namespaceMetadata)
                        );
                }
                else if (funReferenceResult.IsNameOf)
                {
                    node = node.ReplaceNestedNodes(
                        nameNode.Parent as MemberAccessExpressionSyntax,
                        nameNode,
                        newNameNode,
                        rootNode => UpdateTypeAndRunReferenceTransformers(rootNode, funcResult, funReferenceResult, namespaceMetadata,
                                                                          (type, fullName) => rootNode.WithExpression(type.CreateTypeSyntax(false, fullName).WithTriviaFrom(rootNode.Expression))),
                        childNode => RunReferenceTransformers(childNode, funcResult, funReferenceResult, namespaceMetadata)
                        );
                }
                return(node);
            }
            // If we have a method passed as an argument we need to check if we have to wrap it inside a function
            if (bodyFuncReferenceResult.AsyncDelegateArgument != null)
            {
                if (bodyFuncReferenceResult.WrapInsideFunction)
                {
                    // TODO: move to analyze step
                    var  argumentNode  = nameNode.Ancestors().OfType <ArgumentSyntax>().First();
                    var  delReturnType = (INamedTypeSymbol)bodyFuncReferenceResult.AsyncDelegateArgument.ReturnType;
                    var  returnType    = bodyFuncReferenceResult.AsyncCounterpartSymbol.ReturnType;
                    bool returnTypeMismatch;
                    if (bodyFuncReferenceResult.ReferenceFunction != null)
                    {
                        var refMethod = bodyFuncReferenceResult.ReferenceFunction as IMethodAnalyzationResult;
                        if (refMethod != null && refMethod.PreserveReturnType)
                        {
                            returnTypeMismatch = !delReturnType.Equals(returnType);   // TODO Generics
                        }
                        else if (delReturnType.IsGenericType)                         // Generic Task
                        {
                            returnTypeMismatch = delReturnType.TypeArguments.First().IsAwaitRequired(returnType);
                        }
                        else
                        {
                            returnTypeMismatch = delReturnType.IsAwaitRequired(returnType);
                        }
                    }
                    else
                    {
                        returnTypeMismatch = !delReturnType.Equals(returnType);                         // TODO Generics
                    }

                    var newArgumentExpression = argumentNode.Expression
                                                .ReplaceNestedNodes(
                        nameNode.Parent as MemberAccessExpressionSyntax,
                        nameNode,
                        newNameNode,
                        rootNode => UpdateTypeAndRunReferenceTransformers(rootNode, funcResult, funReferenceResult, namespaceMetadata,
                                                                          (type, fullName) => rootNode.WithExpression(type.CreateTypeSyntax(false, fullName))),
                        childNode => RunReferenceTransformers(childNode, funcResult, funReferenceResult, namespaceMetadata)
                        )
                                                .WrapInsideFunction(bodyFuncReferenceResult.AsyncDelegateArgument, returnTypeMismatch,
                                                                    namespaceMetadata.TaskConflict,
                                                                    invocation => invocation.AddCancellationTokenArgumentIf(cancellationTokenParamName, bodyFuncReferenceResult));
                    node = node
                           .ReplaceNode(argumentNode.Expression, newArgumentExpression);
                }
                else
                {
                    node = node.ReplaceNestedNodes(
                        nameNode.Parent as MemberAccessExpressionSyntax,
                        nameNode,
                        newNameNode,
                        rootNode => UpdateTypeAndRunReferenceTransformers(rootNode, funcResult, funReferenceResult, namespaceMetadata,
                                                                          (type, fullName) => rootNode.WithExpression(type.CreateTypeSyntax(false, fullName))),
                        childNode => RunReferenceTransformers(childNode, funcResult, funReferenceResult, namespaceMetadata)
                        );
                }
                return(node);
            }

            InvocationExpressionSyntax invokeNode = null;
            var isAccessor = bodyFuncReferenceResult.ReferenceSymbol.IsAccessor();

            if (!isAccessor && funReferenceResult.ReferenceNode.IsKind(SyntaxKind.InvocationExpression))
            {
                invokeNode = nameNode.Ancestors().OfType <InvocationExpressionSyntax>().First();
            }

            if (!bodyFuncReferenceResult.AwaitInvocation)
            {
                // An arrow method does not have a statement
                var statement = nameNode.Ancestors().OfType <StatementSyntax>().FirstOrDefault();
                var statementInParentFunction = nameNode.Ancestors().TakeWhile(o => !o.Equals(statement)).Any(o => o.IsFunction());
                var newNode = (SyntaxNode)statement ?? node;

                if (invokeNode != null)
                {
                    newNode = newNode.ReplaceNestedNodes(
                        invokeNode,
                        nameNode,
                        newNameNode,
                        rootNode => UpdateTypeAndRunReferenceTransformers(rootNode
                                                                          .AddCancellationTokenArgumentIf(cancellationTokenParamName, bodyFuncReferenceResult),
                                                                          funcResult, funReferenceResult, namespaceMetadata,
                                                                          (memberNode, type, fullName) => memberNode.WithExpression(type.CreateTypeSyntax(true, fullName).WithTriviaFrom(memberNode.Expression)))
                        );
                }
                else if (isAccessor)
                {
                    newNode = ConvertAccessor(newNode, nameNode, newNameNode, cancellationTokenParamName, bodyFuncReferenceResult,
                                              invNode => UpdateTypeAndRunReferenceTransformers(invNode, funcResult, funReferenceResult, namespaceMetadata,
                                                                                               (memberNode, type, fullName) => memberNode.WithExpression(type.CreateTypeSyntax(true, fullName).WithTriviaFrom(memberNode.Expression))));
                }
                else
                {
                    newNode = newNode.ReplaceNestedNodes(
                        nameNode.Parent as MemberAccessExpressionSyntax,
                        nameNode,
                        newNameNode,
                        rootNode => UpdateTypeAndRunReferenceTransformers(rootNode, funcResult, funReferenceResult, namespaceMetadata,
                                                                          (type, fullName) => rootNode.WithExpression(type.CreateTypeSyntax(false, fullName).WithTriviaFrom(rootNode.Expression))),
                        childNode => RunReferenceTransformers(childNode, funcResult, funReferenceResult, namespaceMetadata)
                        );
                }

                if (statement != null && !statement.IsKind(SyntaxKind.LocalFunctionStatement))
                {
                    // Skip adding return statement for arrow functions
                    if (bodyFuncReferenceResult.UseAsReturnValue && !statementInParentFunction)
                    {
                        newNode = ((StatementSyntax)newNode).ToReturnStatement();
                    }
                    node = node
                           .ReplaceNode(statement, newNode);
                }
                else
                {
                    node = (T)newNode;
                }
            }
            else
            {
                // We need to annotate the invocation node because of the AddAwait method as it needs the parent node
                var invokeAnnotation = Guid.NewGuid().ToString();
                if (isAccessor)
                {
                    node = ConvertAccessor(node, nameNode, newNameNode, cancellationTokenParamName, bodyFuncReferenceResult, invNode =>
                                           UpdateTypeAndRunReferenceTransformers(invNode, funcResult, funReferenceResult, namespaceMetadata,
                                                                                 (memberNode, type, fullName) => memberNode.WithExpression(type.CreateTypeSyntax(true, fullName).WithTriviaFrom(memberNode.Expression)))
                                           .WithAdditionalAnnotations(new SyntaxAnnotation(invokeAnnotation))
                                           );
                }
                else
                {
                    node = node.ReplaceNestedNodes(
                        invokeNode,
                        nameNode,
                        newNameNode,
                        rootNode => UpdateTypeAndRunReferenceTransformers(rootNode
                                                                          .AddCancellationTokenArgumentIf(cancellationTokenParamName, bodyFuncReferenceResult),
                                                                          funcResult, funReferenceResult, namespaceMetadata,
                                                                          (memberNode, type, fullName) => memberNode.WithExpression(type.CreateTypeSyntax(true, fullName).WithTriviaFrom(memberNode.Expression)))
                        .WithAdditionalAnnotations(new SyntaxAnnotation(invokeAnnotation))
                        );
                }

                invokeNode = node.GetAnnotatedNodes(invokeAnnotation).OfType <InvocationExpressionSyntax>().First();

                // Check if the invocation has a ?.
                var conditionalAccessNode = invokeNode.Ancestors()
                                            .TakeWhile(o => !(o is StatementSyntax))
                                            .OfType <ConditionalAccessExpressionSyntax>()
                                            .FirstOrDefault(o => o.WhenNotNull.Contains(invokeNode));
                if (conditionalAccessNode != null)                 // ?. syntax
                {
                    // We have to find out which strategy to use, if we have a non assignable expression, we are force to use if statements
                    // otherwise a ternary condition will be used
                    if (!conditionalAccessNode.Parent.IsKind(SyntaxKind.ExpressionStatement) || !invokeNode.Equals(conditionalAccessNode.WhenNotNull))
                    {
                        node = TransformConditionalAccessToConditionalExpressions(node, nameNode, funReferenceResult, typeMetadata,
                                                                                  conditionalAccessNode, invokeNode);
                    }
                    else
                    {
                        node = TransformConditionalAccessToIfStatements(node, nameNode, typeMetadata, conditionalAccessNode, invokeNode);
                    }
                }
                else
                {
                    node = node.ReplaceNode(invokeNode, invokeNode.AddAwait(_configuration.ConfigureAwaitArgument));
                }
            }
            return(node);
        }
コード例 #13
0
        internal FieldTransformationResult TransformField(
            BaseFieldDeclarationSyntax fieldNode,
            bool canCopy,
            FieldTransformationResult result,
            ITypeTransformationMetadata typeMetadata,
            INamespaceTransformationMetadata namespaceMetadata)
        {
            var analyzeResult = result.AnalyzationResult;
            var startRootSpan = analyzeResult.Node.SpanStart;

            // Calculate whitespace method trivias
            result.EndOfLineTrivia         = fieldNode.GetEndOfLine();
            result.LeadingWhitespaceTrivia = fieldNode.GetLeadingWhitespace();
            result.IndentTrivia            = fieldNode.GetIndent(result.LeadingWhitespaceTrivia, typeMetadata.LeadingWhitespaceTrivia);

            if (analyzeResult.Variables.All(o => o.Conversion == FieldVariableConversion.Ignore || o.Conversion == FieldVariableConversion.Copy && !canCopy))
            {
                return(result);
            }

            fieldNode      = fieldNode.WithAdditionalAnnotations(new SyntaxAnnotation(result.Annotation));
            startRootSpan -= fieldNode.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 analyzeResult.TypeReferences.Where(o => o.TypeAnalyzationResult.Conversion == TypeConversion.NewType))
            {
                var reference    = typeReference.ReferenceLocation;
                var refSpanStart = reference.Location.SourceSpan.Start - startRootSpan;
                var nameNode     = fieldNode.GetSimpleName(refSpanStart, reference.Location.SourceSpan.Length, typeReference.IsCref);
                var annotation   = Guid.NewGuid().ToString();
                fieldNode = fieldNode.ReplaceNode(nameNode, nameNode.WithAdditionalAnnotations(new SyntaxAnnotation(annotation)));
                typeReferencesAnnotations.Add(annotation);
            }

            foreach (var variableResult in analyzeResult.Variables)
            {
                var spanStart    = variableResult.Node.SpanStart - startRootSpan;
                var spanLength   = variableResult.Node.Span.Length;
                var accessorNode = fieldNode.DescendantNodes()
                                   .First(o => o.SpanStart == spanStart && o.Span.Length == spanLength);
                var transformedNode = new FieldVariableTransformationResult(variableResult);
                result.TransformedVariables.Add(transformedNode);
                fieldNode = fieldNode.ReplaceNode(accessorNode, accessorNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformedNode.Annotation)));
            }

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

            foreach (var fieldVariableResult in result.TransformedVariables.OrderByDescending(o => o.OriginalStartSpan))
            {
                var variableNode = (VariableDeclaratorSyntax)fieldNode.GetAnnotatedNodes(fieldVariableResult.Annotation)
                                   .First();
                var variableTransformResult = TransformFieldVariable(variableNode, fieldVariableResult, canCopy);
                fieldNode = variableTransformResult.Transformed == null
                                        ? fieldNode.RemoveNode(variableNode, SyntaxRemoveOptions.KeepUnbalancedDirectives)
                                        : fieldNode.ReplaceNode(variableNode, variableTransformResult.Transformed);
            }

            result.Transformed = fieldNode;
            return(result);
        }
コード例 #14
0
        private T TransformFunctionReference <T>(T node, IFunctionAnalyzationResult funcResult, FunctionReferenceTransformationResult transfromReference,
                                                 ITypeTransformationMetadata typeMetadata,
                                                 INamespaceTransformationMetadata namespaceMetadata)
            where T : SyntaxNode
        {
            var nameNode                = node.GetAnnotatedNodes(transfromReference.Annotation).OfType <SimpleNameSyntax>().First();
            var funReferenceResult      = transfromReference.AnalyzationResult;
            var bodyFuncReferenceResult = funReferenceResult as IBodyFunctionReferenceAnalyzationResult;
            var newNameNode             = nameNode
                                          .WithIdentifier(Identifier(funReferenceResult.AsyncCounterpartName))
                                          .WithTriviaFrom(nameNode);

            transfromReference.Transformed = newNameNode;

            var cancellationTokenParamName = funcResult.GetMethodOrAccessor().CancellationTokenRequired ? "cancellationToken" : null;             // TODO: remove

            // If we have a cref change the name to the async counterpart and add/update arguments
            if (bodyFuncReferenceResult == null)
            {
                if (funReferenceResult.IsCref)
                {
                    var crefNode  = (NameMemberCrefSyntax)nameNode.Parent;
                    var paramList = new List <CrefParameterSyntax>();
                    // If the cref has already the parameters set then use them
                    if (crefNode.Parameters != null)
                    {
                        paramList.AddRange(crefNode.Parameters.Parameters);
                        // If the external async counterpart has a cancellation token, add it
                        if (funReferenceResult.AsyncCounterpartFunction == null &&
                            funReferenceResult.ReferenceSymbol.Parameters.Length <
                            funReferenceResult.AsyncCounterpartSymbol.Parameters.Length)
                        {
                            paramList.Add(CrefParameter(IdentifierName(nameof(CancellationToken))));
                        }
                    }
                    else
                    {
                        // We have to add the parameters to avoid ambiguity
                        var asyncSymbol = funReferenceResult.AsyncCounterpartSymbol;
                        paramList.AddRange(asyncSymbol.Parameters
                                           .Select(o => CrefParameter(o.Type
                                                                      .CreateTypeSyntax(true, namespaceMetadata.AnalyzationResult.IsIncluded(o.Type.ContainingNamespace?.ToString())))));
                    }

                    // If the async counterpart is internal and a token is required add a token parameter
                    if (funReferenceResult.AsyncCounterpartFunction?.GetMethodOrAccessor()?.CancellationTokenRequired == true)
                    {
                        paramList.Add(CrefParameter(IdentifierName(nameof(CancellationToken))));
                    }

                    node = node.ReplaceNestedNodes(
                        crefNode.Parent as QualifiedCrefSyntax,
                        crefNode,
                        crefNode
                        .ReplaceNode(nameNode, newNameNode)
                        .WithParameters(CrefParameterList(SeparatedList(paramList))),
                        rootNode => UpdateTypeAndRunReferenceTransformers(rootNode, funcResult, funReferenceResult, namespaceMetadata,
                                                                          (type, fullName) => rootNode.WithContainer(type.CreateTypeSyntax(true, fullName).WithTriviaFrom(rootNode.Container))),
                        childNode => RunReferenceTransformers(childNode, funcResult, funReferenceResult, namespaceMetadata)
                        );
                }
                else if (funReferenceResult.IsNameOf)
                {
                    node = node.ReplaceNestedNodes(
                        nameNode.Parent as MemberAccessExpressionSyntax,
                        nameNode,
                        newNameNode,
                        rootNode => UpdateTypeAndRunReferenceTransformers(rootNode, funcResult, funReferenceResult, namespaceMetadata,
                                                                          (type, fullName) => rootNode.WithExpression(type.CreateTypeSyntax(false, fullName).WithTriviaFrom(rootNode.Expression))),
                        childNode => RunReferenceTransformers(childNode, funcResult, funReferenceResult, namespaceMetadata)
                        );
                }
                return(node);
            }
            // If we have a method passed as an argument we need to check if we have to wrap it inside a function
            if (bodyFuncReferenceResult.AsyncDelegateArgument != null)
            {
                if (bodyFuncReferenceResult.WrapInsideFunction)
                {
                    // TODO: move to analyze step
                    var  argumentNode  = nameNode.Ancestors().OfType <ArgumentSyntax>().First();
                    var  delReturnType = (INamedTypeSymbol)bodyFuncReferenceResult.AsyncDelegateArgument.ReturnType;
                    var  returnType    = bodyFuncReferenceResult.AsyncCounterpartSymbol.ReturnType;
                    bool returnTypeMismatch;
                    if (bodyFuncReferenceResult.ReferenceFunction != null)
                    {
                        var refMethod = bodyFuncReferenceResult.ReferenceFunction as IMethodAnalyzationResult;
                        if (refMethod != null && refMethod.PreserveReturnType)
                        {
                            returnTypeMismatch = !delReturnType.Equals(returnType);   // TODO Generics
                        }
                        else if (delReturnType.IsGenericType)                         // Generic Task
                        {
                            returnTypeMismatch = delReturnType.TypeArguments.First().IsAwaitRequired(returnType);
                        }
                        else
                        {
                            returnTypeMismatch = delReturnType.IsAwaitRequired(returnType);
                        }
                    }
                    else
                    {
                        returnTypeMismatch = !delReturnType.Equals(returnType);                         // TODO Generics
                    }

                    var newArgumentExpression = argumentNode.Expression
                                                .ReplaceNestedNodes(
                        nameNode.Parent as MemberAccessExpressionSyntax,
                        nameNode,
                        newNameNode,
                        rootNode => UpdateTypeAndRunReferenceTransformers(rootNode, funcResult, funReferenceResult, namespaceMetadata,
                                                                          (type, fullName) => rootNode.WithExpression(type.CreateTypeSyntax(false, fullName))),
                        childNode => RunReferenceTransformers(childNode, funcResult, funReferenceResult, namespaceMetadata)
                        )
                                                .WrapInsideFunction(bodyFuncReferenceResult.AsyncDelegateArgument, returnTypeMismatch,
                                                                    namespaceMetadata.TaskConflict,
                                                                    invocation => invocation.AddCancellationTokenArgumentIf(cancellationTokenParamName, bodyFuncReferenceResult));
                    node = node
                           .ReplaceNode(argumentNode.Expression, newArgumentExpression);
                }
                else
                {
                    node = node.ReplaceNestedNodes(
                        nameNode.Parent as MemberAccessExpressionSyntax,
                        nameNode,
                        newNameNode,
                        rootNode => UpdateTypeAndRunReferenceTransformers(rootNode, funcResult, funReferenceResult, namespaceMetadata,
                                                                          (type, fullName) => rootNode.WithExpression(type.CreateTypeSyntax(false, fullName))),
                        childNode => RunReferenceTransformers(childNode, funcResult, funReferenceResult, namespaceMetadata)
                        );
                }
                return(node);
            }

            InvocationExpressionSyntax invokeNode = null;
            var isAccessor = bodyFuncReferenceResult.ReferenceSymbol.IsAccessor();

            if (!isAccessor && funReferenceResult.ReferenceNode.IsKind(SyntaxKind.InvocationExpression))
            {
                invokeNode = nameNode.Ancestors().OfType <InvocationExpressionSyntax>().First();
            }

            if (!bodyFuncReferenceResult.AwaitInvocation)
            {
                // An arrow method does not have a statement
                var statement = nameNode.Ancestors().OfType <StatementSyntax>().FirstOrDefault();
                var newNode   = (SyntaxNode)statement ?? node;

                if (invokeNode != null)
                {
                    newNode = newNode.ReplaceNestedNodes(
                        invokeNode,
                        nameNode,
                        newNameNode,
                        rootNode => UpdateTypeAndRunReferenceTransformers(rootNode
                                                                          .AddCancellationTokenArgumentIf(cancellationTokenParamName, bodyFuncReferenceResult),
                                                                          funcResult, funReferenceResult, namespaceMetadata,
                                                                          (memberNode, type, fullName) => memberNode.WithExpression(type.CreateTypeSyntax(true, fullName).WithTriviaFrom(memberNode.Expression)))
                        );
                }
                else if (isAccessor)
                {
                    newNode = ConvertAccessor(newNode, nameNode, newNameNode, cancellationTokenParamName, bodyFuncReferenceResult,
                                              invNode => UpdateTypeAndRunReferenceTransformers(invNode, funcResult, funReferenceResult, namespaceMetadata,
                                                                                               (memberNode, type, fullName) => memberNode.WithExpression(type.CreateTypeSyntax(true, fullName).WithTriviaFrom(memberNode.Expression))));
                }
                else
                {
                    newNode = newNode.ReplaceNestedNodes(
                        nameNode.Parent as MemberAccessExpressionSyntax,
                        nameNode,
                        newNameNode,
                        rootNode => UpdateTypeAndRunReferenceTransformers(rootNode, funcResult, funReferenceResult, namespaceMetadata,
                                                                          (type, fullName) => rootNode.WithExpression(type.CreateTypeSyntax(false, fullName).WithTriviaFrom(rootNode.Expression))),
                        childNode => RunReferenceTransformers(childNode, funcResult, funReferenceResult, namespaceMetadata)
                        );
                }

                if (statement != null && !statement.IsKind(SyntaxKind.LocalFunctionStatement))
                {
                    if (bodyFuncReferenceResult.UseAsReturnValue)
                    {
                        newNode = ((StatementSyntax)newNode).ToReturnStatement();
                    }
                    node = node
                           .ReplaceNode(statement, newNode);
                }
                else
                {
                    node = (T)newNode;
                }
            }
            else
            {
                // We need to annotate the invocation node because of the AddAwait method as it needs the parent node
                var invokeAnnotation = Guid.NewGuid().ToString();
                if (isAccessor)
                {
                    node = ConvertAccessor(node, nameNode, newNameNode, cancellationTokenParamName, bodyFuncReferenceResult, invNode =>
                                           UpdateTypeAndRunReferenceTransformers(invNode, funcResult, funReferenceResult, namespaceMetadata,
                                                                                 (memberNode, type, fullName) => memberNode.WithExpression(type.CreateTypeSyntax(true, fullName).WithTriviaFrom(memberNode.Expression)))
                                           .WithAdditionalAnnotations(new SyntaxAnnotation(invokeAnnotation))
                                           );
                }
                else
                {
                    node = node.ReplaceNestedNodes(
                        invokeNode,
                        nameNode,
                        newNameNode,
                        rootNode => UpdateTypeAndRunReferenceTransformers(rootNode
                                                                          .AddCancellationTokenArgumentIf(cancellationTokenParamName, bodyFuncReferenceResult),
                                                                          funcResult, funReferenceResult, namespaceMetadata,
                                                                          (memberNode, type, fullName) => memberNode.WithExpression(type.CreateTypeSyntax(true, fullName).WithTriviaFrom(memberNode.Expression)))
                        .WithAdditionalAnnotations(new SyntaxAnnotation(invokeAnnotation))
                        );
                }

                invokeNode = node.GetAnnotatedNodes(invokeAnnotation).OfType <InvocationExpressionSyntax>().First();

                var conditionalAccessNode = invokeNode.Ancestors()
                                            .TakeWhile(o => !(o is StatementSyntax))
                                            .OfType <ConditionalAccessExpressionSyntax>()
                                            .FirstOrDefault();
                if (conditionalAccessNode != null)                 // ?. syntax
                {
                    var statement = (StatementSyntax)invokeNode.Ancestors().FirstOrDefault(o => o is StatementSyntax);
                    var block     = statement?.Parent as BlockSyntax;
                    if (statement == null || block == null)
                    {
                        // TODO: convert arrow method/property/function to a normal one
                        // TODO: convert to block if there is no block
                        node = node.ReplaceNode(conditionalAccessNode,
                                                conditionalAccessNode.AddAwait(_configuration.ConfigureAwaitArgument));
                    }
                    else
                    {
                        var fnName = nameNode.Identifier.ValueText;
                        // TODO: handle name collisions
                        var variableName             = $"{char.ToLowerInvariant(fnName[0])}{fnName.Substring(1)}Task";
                        var leadingTrivia            = statement.GetLeadingTrivia();
                        var newConditionalAccessNode = ConditionalAccessExpression(
                            conditionalAccessNode.Expression,
                            invokeNode)
                                                       .WithTriviaFrom(conditionalAccessNode);
                        var localVar = LocalDeclarationStatement(
                            VariableDeclaration(
                                IdentifierName(Identifier(leadingTrivia, "var", TriviaList(Space))),
                                SingletonSeparatedList(
                                    VariableDeclarator(
                                        Identifier(TriviaList(), variableName, TriviaList(Space)))
                                    .WithInitializer(
                                        EqualsValueClause(newConditionalAccessNode.WithoutTrivia())
                                        .WithEqualsToken(Token(TriviaList(), SyntaxKind.EqualsToken, TriviaList(Space)))
                                        )
                                    )))
                                       .WithSemicolonToken(Token(TriviaList(), SyntaxKind.SemicolonToken, TriviaList(typeMetadata.EndOfLineTrivia)));
                        var index = block.Statements.IndexOf(statement);

                        var lastReturnNode = block.DescendantNodes()
                                             .Where(o => o.SpanStart >= statement.SpanStart)
                                             .OfType <ReturnStatementSyntax>()
                                             .LastOrDefault();

                        var variableAnnotation = Guid.NewGuid().ToString();
                        var newBlock           = block.ReplaceNode(conditionalAccessNode,
                                                                   conditionalAccessNode.WhenNotNull.ReplaceNode(invokeNode,
                                                                                                                 IdentifierName(variableName)
                                                                                                                 .WithAdditionalAnnotations(new SyntaxAnnotation(variableAnnotation))
                                                                                                                 .WithLeadingTrivia(conditionalAccessNode.GetLeadingTrivia())
                                                                                                                 .WithTrailingTrivia(conditionalAccessNode.GetTrailingTrivia())
                                                                                                                 ));

                        var variable = newBlock.GetAnnotatedNodes(variableAnnotation).OfType <IdentifierNameSyntax>().First();
                        newBlock = newBlock.ReplaceNode(variable, variable.AddAwait(_configuration.ConfigureAwaitArgument));

                        var ifBlock = Block()
                                      .WithOpenBraceToken(
                            Token(TriviaList(leadingTrivia), SyntaxKind.OpenBraceToken, TriviaList(typeMetadata.EndOfLineTrivia)))
                                      .WithCloseBraceToken(
                            Token(TriviaList(leadingTrivia), SyntaxKind.CloseBraceToken, TriviaList(typeMetadata.EndOfLineTrivia)))
                                      .WithStatements(new SyntaxList <StatementSyntax>()
                                                      .AddRange(newBlock.AppendIndent(typeMetadata.IndentTrivia.ToFullString()).Statements.Skip(index)));

                        var ifStatement = IfStatement(
                            BinaryExpression(
                                SyntaxKind.NotEqualsExpression,
                                IdentifierName(Identifier(TriviaList(), variableName, TriviaList(Space))),
                                LiteralExpression(SyntaxKind.NullLiteralExpression))
                            .WithOperatorToken(
                                Token(TriviaList(), SyntaxKind.ExclamationEqualsToken, TriviaList(Space))),
                            ifBlock
                            )
                                          .WithIfKeyword(
                            Token(TriviaList(leadingTrivia), SyntaxKind.IfKeyword, TriviaList(Space)))
                                          .WithCloseParenToken(
                            Token(TriviaList(), SyntaxKind.CloseParenToken, TriviaList(typeMetadata.EndOfLineTrivia)));

                        var statements = new SyntaxList <StatementSyntax>()
                                         .AddRange(newBlock.Statements.Take(index))
                                         .Add(localVar)
                                         .Add(ifStatement);
                        if (lastReturnNode?.Expression != null)
                        {
                            // Check if the variable is defined otherwise return default return type value
                            if (lastReturnNode.Expression is IdentifierNameSyntax idNode &&
                                statements.OfType <VariableDeclaratorSyntax>().All(o => o.Identifier.ToString() != idNode.Identifier.ValueText))
                            {
                                lastReturnNode = lastReturnNode.WithExpression(DefaultExpression(funcResult.GetNode().GetReturnType().WithoutTrivia()));
                            }
                            statements = statements.Add(lastReturnNode);
                        }
                        node = node.ReplaceNode(block, newBlock.WithStatements(statements));
                    }
                }
                else
                {
                    node = node.ReplaceNode(invokeNode, invokeNode.AddAwait(_configuration.ConfigureAwaitArgument));
                }
            }
            return(node);
        }
コード例 #15
0
        // TODO: should we always add guards in anonymous methods?
        //public SyntaxNode Transform(IFunctionTransformationResult functionTransformResult, ITypeTransformationMetadata typeMetadata,
        //	INamespaceTransformationMetadata namespaceMetadata)
        //{
        //	var methodResult = functionTransformResult.AnalyzationResult.GetMethodOrAccessor();
        //	if (methodResult == null || !methodResult.CancellationTokenRequired)
        //	{
        //		return null;
        //	}

        //	var functionNode = functionTransformResult.Transformed;
        //	var functionBody = functionNode.GetFunctionBody() as BlockSyntax; // TODO: support expressions
        //	if (functionBody != null)
        //	{
        //		functionNode = functionNode.ReplaceNode(functionBody,
        //			AddGuards(functionTransformResult, functionBody, functionTransformResult.AnalyzationResult, CancellationTokenParamName));
        //	}

        //	return functionNode;
        //}

        public MethodTransformerResult Transform(IMethodOrAccessorTransformationResult transformResult,
                                                 ITypeTransformationMetadata typeMetadata, INamespaceTransformationMetadata namespaceMetadata)
        {
            var methodResult = transformResult.AnalyzationResult;

            if (!methodResult.CancellationTokenRequired)
            {
                return(MethodTransformerResult.Skip);
            }
            var originalNode      = methodResult.GetNode();
            var generationOptions = methodResult.MethodCancellationToken.GetValueOrDefault();
            var methodNode        = transformResult.Transformed;

            methodNode = methodNode
                         .AddCancellationTokenParameter(CancellationTokenParamName,
                                                        generationOptions.HasFlag(MethodCancellationToken.Optional),
                                                        transformResult.LeadingWhitespaceTrivia,
                                                        transformResult.EndOfLineTrivia);

            var methodBody = methodNode.Body;

            methodNode = methodNode.WithBody(AddGuards(transformResult, methodBody, methodResult, CancellationTokenParamName));

            var originalMethodNode = originalNode as MethodDeclarationSyntax;

            // Add an additional overload if specified
            if (originalMethodNode == null ||
                (
                    !generationOptions.HasFlag(MethodCancellationToken.ForwardNone) &&
                    !generationOptions.HasFlag(MethodCancellationToken.SealedForwardNone)
                ))
            {
                return(MethodTransformerResult.Update(methodNode));
            }
            var overloadNode = originalMethodNode
                               .ReturnAsTask(namespaceMetadata.TaskConflict)
                               .WithTriviaFrom(transformResult.Transformed)  // We want to have the sumamry of the transformed node but not the parameter list
                               .WithoutAnnotations(transformResult.Annotation)
                               .WithIdentifier(Identifier(methodNode.Identifier.ValueText));

            // We can have abstract methods that don't have a body
            if (methodResult.Symbol.IsAbstract)
            {
                // Add the trailing trivia from the semicolon to close paren
                overloadNode = overloadNode
                               .WithParameterList(
                    overloadNode.ParameterList
                    .WithCloseParenToken(
                        overloadNode.ParameterList.CloseParenToken.WithTrailingTrivia(overloadNode.SemicolonToken.TrailingTrivia))
                    )
                               .WithSemicolonToken(default(SyntaxToken));
                methodBody = Block()
                             .WithOpenBraceToken(
                    Token(TriviaList(transformResult.LeadingWhitespaceTrivia), SyntaxKind.OpenBraceToken,
                          TriviaList(transformResult.EndOfLineTrivia)))
                             .WithCloseBraceToken(
                    Token(TriviaList(transformResult.LeadingWhitespaceTrivia), SyntaxKind.CloseBraceToken,
                          TriviaList(transformResult.EndOfLineTrivia)));
            }

            var tokenArg = Argument(
                MemberAccessExpression(
                    SyntaxKind.SimpleMemberAccessExpression,
                    IdentifierName("CancellationToken"),
                    IdentifierName("None")));

            overloadNode = overloadNode
                           .WithBody(methodBody
                                     .WithStatements(
                                         SingletonList <StatementSyntax>(
                                             ReturnStatement(originalMethodNode.ForwardCall(methodResult.Symbol, methodNode.Identifier.ValueText, tokenArg))
                                             .WithReturnKeyword(
                                                 Token(TriviaList(transformResult.BodyLeadingWhitespaceTrivia), SyntaxKind.ReturnKeyword, TriviaList(Space))
                                                 )
                                             .WithSemicolonToken(Token(TriviaList(), SyntaxKind.SemicolonToken, TriviaList(transformResult.EndOfLineTrivia)))
                                             )
                                         ));
            if (generationOptions.HasFlag(MethodCancellationToken.SealedForwardNone))
            {
                if (methodResult.Symbol.IsVirtual)
                {
                    // For virtual methods we need to remove the virtual keyword
                    overloadNode = overloadNode
                                   .WithModifiers(TokenList(originalMethodNode.Modifiers.Where(o => !o.IsKind(SyntaxKind.VirtualKeyword))));
                }
                else if (methodResult.Symbol.OverriddenMethod != null)
                {
                    // For overrides we need to add the sealed keyword
                    overloadNode = overloadNode
                                   .WithModifiers(originalMethodNode.Modifiers.Add(Token(TriviaList(), SyntaxKind.SealedKeyword, TriviaList(Space))));
                }
                else if (methodResult.Symbol.IsAbstract)
                {
                    // For abstract we need to remove the abstract keyword
                    overloadNode = overloadNode
                                   .WithModifiers(TokenList(originalMethodNode.Modifiers.Where(o => !o.IsKind(SyntaxKind.AbstractKeyword))));
                }
            }
            // We need to remove all directives
            while (overloadNode.ContainsDirectives)
            {
                overloadNode = overloadNode.RemoveNode(overloadNode.GetFirstDirective(), SyntaxRemoveOptions.KeepNoTrivia);
            }

            return(MethodTransformerResult.Update(methodNode)
                   .AddMethod(overloadNode));
        }
コード例 #16
0
        public MethodTransformerResult Transform(IMethodOrAccessorTransformationResult transformResult,
                                                 ITypeTransformationMetadata typeMetadata, INamespaceTransformationMetadata namespaceMetadata)
        {
            var methodResult = transformResult.AnalyzationResult;

            if (!methodResult.Missing || !methodResult.Conversion.HasFlag(MethodConversion.ToAsync) || methodResult.Symbol.IsObsolete())
            {
                return(MethodTransformerResult.Skip);
            }
            var methodNode = transformResult.Transformed;

            var baseMethod = methodResult.RelatedMethods
                             .Where(o =>
                                    (methodResult.BaseOverriddenMethod != null && o.Symbol.Equals(methodResult.BaseOverriddenMethod)) ||
                                    methodResult.ImplementedInterfaces.Any(i => o.Symbol.Equals(i)))
                             .FirstOrDefault(o => o.AsyncCounterpartSymbol?.IsObsolete() == true);

            if (baseMethod == null)
            {
                return(MethodTransformerResult.Skip);
            }

            namespaceMetadata.AddUsing("System");
            AttributeListSyntax obsoleteAttribute = null;
            var          syntaxReference          = baseMethod.AsyncCounterpartSymbol.DeclaringSyntaxReferences.SingleOrDefault();
            SyntaxTrivia?documentationTrivia      = null;

            if (syntaxReference != null)
            {
                var baseMethodNode = syntaxReference.GetSyntax() as MethodDeclarationSyntax;
                obsoleteAttribute   = baseMethodNode?.AttributeLists.FirstOrDefault(o => o.Attributes.Count == 1 && o.Attributes.First().Name.ToString() == "Obsolete");
                obsoleteAttribute   = (AttributeListSyntax)_directiveRemover.VisitAttributeList(obsoleteAttribute);
                documentationTrivia = obsoleteAttribute.GetLeadingTrivia()
                                      .Select(o => o.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia) ? o : (SyntaxTrivia?)null)
                                      .FirstOrDefault(o => o.HasValue);
            }

            if (obsoleteAttribute == null)
            {
                obsoleteAttribute = AttributeList(SingletonSeparatedList(Attribute(IdentifierName("Obsolete"))))
                                    .WithOpenBracketToken(Token(TriviaList(transformResult.LeadingWhitespaceTrivia), SyntaxKind.OpenBracketToken, TriviaList()))
                                    .WithCloseBracketToken(Token(TriviaList(), SyntaxKind.CloseBracketToken, TriviaList(transformResult.EndOfLineTrivia)));
            }

            var inheritDocTrivia = Trivia(GetInheritdoc(transformResult.EndOfLineTrivia.ToFullString()));

            if (documentationTrivia.HasValue)
            {
                obsoleteAttribute = obsoleteAttribute.WithLeadingTrivia(obsoleteAttribute.GetLeadingTrivia()
                                                                        .Replace(documentationTrivia.Value, inheritDocTrivia));
            }
            else
            {
                // Append <inheritdoc />
                var leadingTrivia = obsoleteAttribute.GetLeadingTrivia();
                var trivias       = new List <SyntaxTrivia>();
                if (leadingTrivia.Count == 0 || !leadingTrivia.Last().IsKind(SyntaxKind.WhitespaceTrivia))
                {
                    trivias.Add(transformResult.LeadingWhitespaceTrivia);
                }

                trivias.Add(inheritDocTrivia);
                trivias.Add(transformResult.LeadingWhitespaceTrivia);
                obsoleteAttribute = obsoleteAttribute.WithLeadingTrivia(leadingTrivia.AddRange(trivias));
            }

            methodNode = methodNode
                         .WithLeadingTrivia(TriviaList(transformResult.LeadingWhitespaceTrivia))
                         .WithAttributeLists(methodNode.AttributeLists.Add(obsoleteAttribute));

            return(MethodTransformerResult.Update(methodNode));
        }
コード例 #17
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;
        }
コード例 #18
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);
        }
コード例 #19
0
        public MethodTransformerResult Transform(IMethodOrAccessorTransformationResult transformResult,
                                                 ITypeTransformationMetadata typeMetadata, INamespaceTransformationMetadata namespaceMetadata)
        {
            var methodResult = transformResult.AnalyzationResult;

            if (!methodResult.CancellationTokenRequired)
            {
                return(MethodTransformerResult.Skip);
            }
            var originalNode = methodResult.GetNode();
            var cancellationTokenParamName = "cancellationToken";             // TODO: handle variable collision for token
            var generationOptions          = methodResult.MethodCancellationToken.GetValueOrDefault();
            var methodNode = transformResult.Transformed;

            methodNode = methodNode
                         .AddCancellationTokenParameter(cancellationTokenParamName,
                                                        generationOptions.HasFlag(MethodCancellationToken.Optional),
                                                        transformResult.LeadingWhitespaceTrivia,
                                                        transformResult.EndOfLineTrivia);

            var methodBody = methodNode.Body;

            if (_configuration.Guards && methodBody != null && !methodResult.Faulted)
            {
                var startGuard = methodResult.OmitAsync
                                        ? GetSyncGuard(methodResult, cancellationTokenParamName, transformResult.BodyLeadingWhitespaceTrivia,
                                                       transformResult.EndOfLineTrivia, transformResult.IndentTrivia)
                                        : GetAsyncGuard(cancellationTokenParamName, transformResult.BodyLeadingWhitespaceTrivia,
                                                        transformResult.EndOfLineTrivia);

                methodNode = methodNode.WithBody(
                    methodBody.WithStatements(
                        methodBody.Statements.Insert(methodResult.Preconditions.Count, startGuard))
                    );
                // We need to get all statements that have at least one async invocation without a cancellation token argument, to prepend an extra guard
                var statements = new Dictionary <int, string>();
                foreach (var functionReference in transformResult.TransformedFunctionReferences)
                {
                    if (!(functionReference.AnalyzationResult is IBodyFunctionReferenceAnalyzationResult bodyFunctionReference))
                    {
                        continue;
                    }
                    if (bodyFunctionReference.GetConversion() != ReferenceConversion.ToAsync || bodyFunctionReference.PassCancellationToken)
                    {
                        continue;
                    }
                    var statement = methodNode
                                    .GetAnnotatedNodes(functionReference.Annotation)
                                    .First().Ancestors().OfType <StatementSyntax>().First();
                    if (statements.ContainsKey(statement.SpanStart))
                    {
                        continue;
                    }
                    var annotation = Guid.NewGuid().ToString();
                    methodNode = methodNode
                                 .ReplaceNode(statement, statement.WithAdditionalAnnotations(new SyntaxAnnotation(annotation)));
                    statements.Add(statement.SpanStart, annotation);
                }
                // For each statement we need to find the index where is located in the block.
                // TODO: Add support when the parent is not a block syntax
                foreach (var pair in statements)
                {
                    var statement   = methodNode.GetAnnotatedNodes(pair.Value).OfType <StatementSyntax>().First();
                    var parentBlock = statement.Parent as BlockSyntax;
                    if (parentBlock == null)
                    {
                        continue;                         // Currently not supported
                    }
                    var index          = parentBlock.Statements.IndexOf(statement);
                    var newParentBlock = parentBlock
                                         .WithStatements(parentBlock.Statements
                                                         .Insert(index, GetAsyncGuard(cancellationTokenParamName, statement.GetLeadingWhitespace(), transformResult.EndOfLineTrivia)));
                    methodNode = methodNode
                                 .ReplaceNode(parentBlock, newParentBlock);
                }
            }

            var originalMethodNode = originalNode as MethodDeclarationSyntax;

            // Add an additional overload if specified
            if (originalMethodNode == null ||
                (
                    !generationOptions.HasFlag(MethodCancellationToken.ForwardNone) &&
                    !generationOptions.HasFlag(MethodCancellationToken.SealedForwardNone)
                ))
            {
                return(MethodTransformerResult.Update(methodNode));
            }
            var overloadNode = originalMethodNode
                               .ReturnAsTask(namespaceMetadata.TaskConflict)
                               .WithTriviaFrom(transformResult.Transformed)  // We want to have the sumamry of the transformed node but not the parameter list
                               .WithoutAnnotations(transformResult.Annotation)
                               .WithIdentifier(Identifier(methodNode.Identifier.ValueText));

            // We can have abstract methods that don't have a body
            if (methodResult.Symbol.IsAbstract)
            {
                // Add the trailing trivia from the semicolon to close paren
                overloadNode = overloadNode
                               .WithParameterList(
                    overloadNode.ParameterList
                    .WithCloseParenToken(
                        overloadNode.ParameterList.CloseParenToken.WithTrailingTrivia(overloadNode.SemicolonToken.TrailingTrivia))
                    )
                               .WithSemicolonToken(default(SyntaxToken));
                methodBody = Block()
                             .WithOpenBraceToken(
                    Token(TriviaList(transformResult.LeadingWhitespaceTrivia), SyntaxKind.OpenBraceToken,
                          TriviaList(transformResult.EndOfLineTrivia)))
                             .WithCloseBraceToken(
                    Token(TriviaList(transformResult.LeadingWhitespaceTrivia), SyntaxKind.CloseBraceToken,
                          TriviaList(transformResult.EndOfLineTrivia)));
            }

            var tokenArg = Argument(
                MemberAccessExpression(
                    SyntaxKind.SimpleMemberAccessExpression,
                    IdentifierName("CancellationToken"),
                    IdentifierName("None")));

            overloadNode = overloadNode
                           .WithBody(methodBody
                                     .WithStatements(
                                         SingletonList <StatementSyntax>(
                                             ReturnStatement(originalMethodNode.ForwardCall(methodResult.Symbol, methodNode.Identifier.ValueText, tokenArg))
                                             .WithReturnKeyword(
                                                 Token(TriviaList(transformResult.BodyLeadingWhitespaceTrivia), SyntaxKind.ReturnKeyword, TriviaList(Space))
                                                 )
                                             .WithSemicolonToken(Token(TriviaList(), SyntaxKind.SemicolonToken, TriviaList(transformResult.EndOfLineTrivia)))
                                             )
                                         ));
            if (generationOptions.HasFlag(MethodCancellationToken.SealedForwardNone))
            {
                if (methodResult.Symbol.IsVirtual)
                {
                    // For virtual methods we need to remove the virtual keyword
                    overloadNode = overloadNode
                                   .WithModifiers(TokenList(originalMethodNode.Modifiers.Where(o => !o.IsKind(SyntaxKind.VirtualKeyword))));
                }
                else if (methodResult.Symbol.OverriddenMethod != null)
                {
                    // For overrides we need to add the sealed keyword
                    overloadNode = overloadNode
                                   .WithModifiers(originalMethodNode.Modifiers.Add(Token(TriviaList(), SyntaxKind.SealedKeyword, TriviaList(Space))));
                }
                else if (methodResult.Symbol.IsAbstract)
                {
                    // For abstract we need to remove the abstract keyword
                    overloadNode = overloadNode
                                   .WithModifiers(TokenList(originalMethodNode.Modifiers.Where(o => !o.IsKind(SyntaxKind.AbstractKeyword))));
                }
            }
            // We need to remove all directives
            while (overloadNode.ContainsDirectives)
            {
                overloadNode = overloadNode.RemoveNode(overloadNode.GetFirstDirective(), SyntaxRemoveOptions.KeepNoTrivia);
            }

            return(MethodTransformerResult.Update(methodNode)
                   .AddMethod(overloadNode));
        }
コード例 #20
0
 public SyntaxNode Transform(IFunctionTransformationResult transformResult,
                             ITypeTransformationMetadata typeMetadata,
                             INamespaceTransformationMetadata namespaceMetadata)
 {
     return(transformResult.AnalyzationResult.OmitAsync ? null : _rewriter.VisitFunction(transformResult.Transformed));
 }
コード例 #21
0
        private RootFunctionTransformationResult TransformFunction(IFunctionAnalyzationResult rootFuncResult,
                                                                   ITransformationTrivia parentTransformTrivia, ITypeTransformationMetadata typeMetadata, INamespaceTransformationMetadata namespaceMetadata)
        {
            var rootFuncNode        = rootFuncResult.GetNode();
            var startRootFuncSpan   = rootFuncNode.SpanStart;
            var rootTransformResult = new RootFunctionTransformationResult(rootFuncResult)
            {
            };

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

            // Before any modification we need to annotate nodes that will be transformed in order to find them later on.
            foreach (var funcResult in rootFuncResult.GetSelfAndDescendantsFunctions())
            {
                var origFuncNode   = funcResult.GetNode();
                var funcSpanStart  = origFuncNode.SpanStart - startRootFuncSpan;
                var funcSpanLength = origFuncNode.Span.Length;
                var funcNode       = rootFuncNode.DescendantNodesAndSelf()
                                     .Where(o => !o.IsKind(SyntaxKind.Argument))    // An argument can have the same span as the function
                                     .First(o => o.SpanStart == funcSpanStart && o.Span.Length == funcSpanLength);
                FunctionTransformationResult transformResult;
                if (funcNode == rootFuncNode)
                {
                    transformResult = rootTransformResult;
                    transformResult.IndentTrivia            = parentTransformTrivia.IndentTrivia;
                    transformResult.EndOfLineTrivia         = parentTransformTrivia.EndOfLineTrivia;
                    transformResult.LeadingWhitespaceTrivia = Whitespace(parentTransformTrivia.LeadingWhitespaceTrivia.ToFullString() +
                                                                         parentTransformTrivia.IndentTrivia.ToFullString());
                    transformResult.BodyLeadingWhitespaceTrivia = Whitespace(transformResult.LeadingWhitespaceTrivia.ToFullString() +
                                                                             parentTransformTrivia.IndentTrivia.ToFullString());
                }
                else
                {
                    transformResult = new FunctionTransformationResult(funcResult);
                    rootFuncNode    = rootFuncNode.ReplaceNode(funcNode, funcNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformResult.Annotation)));
                    rootTransformResult.DescendantTransformedFunctions.Add(transformResult);
                    // TODO: calculate trivias
                }
                if (funcResult.Conversion == MethodConversion.Ignore)
                {
                    continue;                     // Ignored functions shall be only annotated
                }

                foreach (var typeReference in funcResult.TypeReferences.Where(o => o.TypeAnalyzationResult.Conversion == TypeConversion.NewType))
                {
                    var reference       = typeReference.ReferenceLocation;
                    var refSpanStart    = reference.Location.SourceSpan.Start - startRootFuncSpan;
                    var refSpanLength   = reference.Location.SourceSpan.Length;
                    var nameNode        = rootFuncNode.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);
                    rootFuncNode = rootFuncNode.ReplaceNode(nameNode, nameNode.WithAdditionalAnnotations(new SyntaxAnnotation(transformedNode.Annotation)));
                }

                // TODO: unify with method in order to avoid duplicate code
                foreach (var referenceResult in funcResult.FunctionReferences.Where(o => o.GetConversion() == ReferenceConversion.ToAsync))
                {
                    var transfromReference = new FunctionReferenceTransformationResult(referenceResult);
                    var reference          = referenceResult.ReferenceLocation;
                    var startSpan          = reference.Location.SourceSpan.Start - startRootFuncSpan;
                    var nameNode           = rootFuncNode.GetSimpleName(startSpan, reference.Location.SourceSpan.Length);
                    rootFuncNode = rootFuncNode.ReplaceNode(nameNode, nameNode.WithAdditionalAnnotations(new SyntaxAnnotation(transfromReference.Annotation)));
                    transformResult.TransformedFunctionReferences.Add(transfromReference);

                    var bodyRef = referenceResult as IBodyFunctionReferenceAnalyzationResult;
                    if (!funcResult.OmitAsync || bodyRef == null)
                    {
                        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;
                    if (bodyRef.UseAsReturnValue || refNode.IsReturned())
                    {
                        startSpan = refNode.SpanStart - startRootFuncSpan;
                        var referenceNode = rootFuncNode.DescendantNodes().First(o => o.SpanStart == startSpan && o.Span.Length == refNode.Span.Length);
                        rootFuncNode = rootFuncNode.ReplaceNode(referenceNode, referenceNode.WithAdditionalAnnotations(new SyntaxAnnotation(Annotations.TaskReturned)));
                    }
                }
            }

            foreach (var transformResult in rootTransformResult.GetSelfAndDescendantTransformedFunctions().OrderByDescending(o => o.OriginalStartSpan))
            {
                // We have to order by OriginalStartSpan in order to have consistent formatting when adding awaits
                foreach (var transfromReference in transformResult.TransformedFunctionReferences.OrderByDescending(o => o.OriginalStartSpan))
                {
                    rootFuncNode = TransformFunctionReference(rootFuncNode, rootFuncResult, transfromReference, typeMetadata, namespaceMetadata);
                }

                // Replace all rewritten nodes
                foreach (var rewNode in transformResult.TransformedNodes)
                {
                    var node = rootFuncNode.GetAnnotatedNodes(rewNode.Annotation).First();
                    if (rewNode.Transformed == null)
                    {
                        rootFuncNode = rootFuncNode.RemoveNode(node, SyntaxRemoveOptions.KeepUnbalancedDirectives);
                    }
                    else
                    {
                        rootFuncNode = rootFuncNode.ReplaceNode(node, rewNode.Transformed);
                    }
                }

                var funcNode    = rootFuncNode.GetAnnotatedNodes(transformResult.Annotation).First();
                var newFuncNode = funcNode;
                transformResult.Transformed = newFuncNode;
                newFuncNode  = RunFunctionTransformers(transformResult, typeMetadata, namespaceMetadata);
                rootFuncNode = rootFuncNode.ReplaceNode(funcNode, newFuncNode);
            }

            rootTransformResult.Transformed = rootFuncNode;
            return(rootTransformResult);
        }
コード例 #22
0
        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);
        }
コード例 #23
0
        public MethodTransformerResult Transform(IMethodOrAccessorTransformationResult result,
                                                 ITypeTransformationMetadata typeMetadata, INamespaceTransformationMetadata namespaceMetadata)
        {
            if (!result.TransformedLocks.Any() && !result.AnalyzationResult.MustRunSynchronized)
            {
                return(MethodTransformerResult.Skip);
            }
            var newFields = new Dictionary <string, FieldDeclarationSyntax>();
            var node      = result.Transformed;

            // Transform all lock statements that contains at least one async invocation.
            foreach (var lockResult in result.TransformedLocks)
            {
                var lockNode = node.GetAnnotatedNodes(lockResult.Annotation).OfType <LockStatementSyntax>().First();
                if (result.AnalyzationResult.FunctionReferences
                    .Where(r => lockResult.AnalyzationResult.Node.Span.Contains(r.ReferenceNameNode.Span))
                    .All(r => r.GetConversion() != ReferenceConversion.ToAsync))
                {
                    continue;
                }
                var lockSymbol    = lockResult.AnalyzationResult.Symbol;
                var typeLock      = lockSymbol is INamedTypeSymbol;
                var isStatic      = lockSymbol.IsStatic || typeLock;
                var lockFieldName = GetLockFieldName(lockResult.AnalyzationResult.Symbol, isStatic, typeLock ? "Lock" : "", "Async");
                // TODO: handle name collisions
                if (!typeMetadata.MemberNames.Contains(lockFieldName) && !newFields.ContainsKey(lockFieldName))
                {
                    newFields.Add(lockFieldName, GetAsyncLockField(lockFieldName, isStatic, result));
                }

                var usingNode = GetUsingAsyncLock(lockFieldName, lockNode.GetLeadingTrivia(),
                                                  lockNode.CloseParenToken.TrailingTrivia, lockNode.Statement);
                node = node.ReplaceNode(lockNode, usingNode);
            }

            if (result.AnalyzationResult.MustRunSynchronized)
            {
                var methodSymbol = result.AnalyzationResult.Symbol;
                var fieldName    = GetLockFieldName(methodSymbol, methodSymbol.IsStatic, typeMetadata);
                var newBody      = GetUsingAsyncLock(fieldName,
                                                     TriviaList(result.LeadingWhitespaceTrivia), TriviaList(result.EndOfLineTrivia), node.Body)
                                   .AppendIndent(result.IndentTrivia.ToFullString());
                node = node.WithBody(node.Body
                                     .WithStatements(SingletonList <StatementSyntax>(newBody)));

                // Remove the Synchronized option from the MethodImpl attribute
                var methodImplAttr    = node.AttributeLists.SelectMany(o => o.Attributes).First(o => o.Name.ToString() == "MethodImpl");
                var newMethodImplAttr = (AttributeSyntax)VisitAttribute(methodImplAttr);

                node = node.ReplaceNode(methodImplAttr, newMethodImplAttr);
                newFields.Add(fieldName, GetAsyncLockField(fieldName, methodSymbol.IsStatic, result));
            }

            var transformResult = MethodTransformerResult.Update(node);

            foreach (var newField in newFields.Values)
            {
                transformResult.AddField(newField);
            }
            return(transformResult);
        }
コード例 #24
0
 public MethodTransformerResult Transform(IMethodOrAccessorTransformationResult methodTransformResult,
                                          ITypeTransformationMetadata typeMetadata, INamespaceTransformationMetadata namespaceMetadata)
 {
     return(MethodTransformerResult.Update((MethodDeclarationSyntax)VisitMethodDeclaration(methodTransformResult.Transformed)));
 }
コード例 #25
0
        private T TransformConditionalAccessToConditionalExpressions <T>(
            T node,
            SimpleNameSyntax nameNode,
            IFunctionReferenceAnalyzationResult funReferenceResult,
            ITypeTransformationMetadata typeMetadata,
            ConditionalAccessExpressionSyntax conditionalAccessNode,
            InvocationExpressionSyntax invokeNode) where T : SyntaxNode
        {
            // TODO: we should check the async symbol instead
            var returnType  = funReferenceResult.ReferenceSymbol.ReturnType;
            var type        = returnType.CreateTypeSyntax();
            var canSkipCast = !returnType.IsValueType && !returnType.IsNullable();

            if (returnType.IsValueType && !returnType.IsNullable())
            {
                type = NullableType(type);
            }

            ExpressionSyntax whenNotNullNode = null;

            if (invokeNode.Parent is MemberAccessExpressionSyntax memberAccessParent)
            {
                whenNotNullNode = conditionalAccessNode.WhenNotNull
                                  .ReplaceNode(memberAccessParent,
                                               MemberBindingExpression(Token(SyntaxKind.DotToken), memberAccessParent.Name));
            }
            else if (invokeNode.Parent is ElementAccessExpressionSyntax elementAccessParent)
            {
                whenNotNullNode = conditionalAccessNode.WhenNotNull
                                  .ReplaceNode(elementAccessParent,
                                               ElementBindingExpression(elementAccessParent.ArgumentList));
            }

            var             valueNode         = conditionalAccessNode.Expression.WithoutTrivia();
            StatementSyntax variableStatement = null;
            BlockSyntax     statementBlock    = null;
            var             statementIndex    = 0;

            // We have to save the value in a variable when the expression is an invocation, index accessor or property in
            // order to prevent double calls
            // TODO: find a more robust solution
            if (!(conditionalAccessNode.Expression is SimpleNameSyntax simpleName) || char.IsUpper(simpleName.ToString()[0]))
            {
                var statement = (StatementSyntax)conditionalAccessNode.Ancestors().FirstOrDefault(o => o is StatementSyntax);
                if (statement == null || !(statement.Parent is BlockSyntax block))
                {
                    // TODO: convert arrow method/property/function to a normal one
                    // TODO: convert to block if there is no block
                    throw new NotSupportedException(
                              $"Arrow method with null-conditional is not supported. Node: {conditionalAccessNode}");
                }

                var leadingTrivia = statement.GetLeadingTrivia();
                var fnName        = nameNode.Identifier.ValueText;
                statementIndex = block.Statements.IndexOf(statement);
                statementBlock = block;
                // TODO: handle name collisions
                var variableName = $"{char.ToLowerInvariant(fnName[0])}{fnName.Substring(1)}{statementIndex}";
                variableStatement = LocalDeclarationStatement(
                    VariableDeclaration(
                        IdentifierName(Identifier(leadingTrivia, "var", TriviaList(Space))),
                        SingletonSeparatedList(
                            VariableDeclarator(
                                Identifier(TriviaList(), variableName, TriviaList(Space)))
                            .WithInitializer(
                                EqualsValueClause(valueNode)
                                .WithEqualsToken(Token(TriviaList(), SyntaxKind.EqualsToken, TriviaList(Space)))
                                )
                            )))
                                    .WithSemicolonToken(Token(TriviaList(), SyntaxKind.SemicolonToken, TriviaList(typeMetadata.EndOfLineTrivia)));

                valueNode = IdentifierName(variableName);
            }

            var invocationAnnotation = Guid.NewGuid().ToString();
            var nullNode             = LiteralExpression(
                SyntaxKind.NullLiteralExpression,
                Token(TriviaList(), SyntaxKind.NullKeyword, TriviaList(Space)));
            var ifNullCondition = BinaryExpression(
                SyntaxKind.EqualsExpression,
                valueNode.WithTrailingTrivia(TriviaList(Space)),
                nullNode)
                                  .WithOperatorToken(
                Token(TriviaList(), SyntaxKind.EqualsEqualsToken, TriviaList(Space)));

            ExpressionSyntax wrappedNode = ParenthesizedExpression(
                ConditionalExpression(
                    ifNullCondition,
                    canSkipCast
                                                        ? (ExpressionSyntax)nullNode
                                                        : CastExpression(
                        Token(SyntaxKind.OpenParenToken),
                        type,
                        Token(TriviaList(), SyntaxKind.CloseParenToken, TriviaList(Space)),
                        nullNode),
                    InvocationExpression(
                        MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                               valueNode,
                                               ((MemberBindingExpressionSyntax)invokeNode.Expression).Name))
                    .WithAdditionalAnnotations(new SyntaxAnnotation(invocationAnnotation))
                    .WithArgumentList(invokeNode.ArgumentList.WithoutTrailingTrivia())
                    )
                .WithColonToken(Token(TriviaList(), SyntaxKind.ColonToken, TriviaList(Space)))
                .WithQuestionToken(Token(TriviaList(), SyntaxKind.QuestionToken, TriviaList(Space)))
                );

            if (whenNotNullNode != null)
            {
                wrappedNode = conditionalAccessNode
                              .WithExpression(wrappedNode)
                              .WithWhenNotNull(whenNotNullNode);
            }

            wrappedNode = wrappedNode.WithTriviaFrom(conditionalAccessNode);
            invokeNode  = (InvocationExpressionSyntax)wrappedNode.GetAnnotatedNodes(invocationAnnotation).First();
            wrappedNode = wrappedNode.ReplaceNode(invokeNode, invokeNode.AddAwait(_configuration.ConfigureAwaitArgument));
            if (statementBlock != null)
            {
                var newBlock = statementBlock.ReplaceNode(conditionalAccessNode, wrappedNode);
                newBlock = newBlock.WithStatements(newBlock.Statements.Insert(statementIndex, variableStatement));

                return(node.ReplaceNode(statementBlock, newBlock));
            }

            return(node.ReplaceNode(conditionalAccessNode, wrappedNode));
        }