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));
        }
        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));
        }
Exemplo n.º 3
0
 public ReturnTaskFunctionRewriter(IFunctionTransformationResult transformResult, INamespaceTransformationMetadata namespaceMetadata)
 {
     _transformResult   = transformResult;
     _methodResult      = transformResult.AnalyzationResult;
     _namespaceMetadata = namespaceMetadata;
 }
Exemplo n.º 4
0
 public SyntaxNode Transform(IFunctionTransformationResult transformResult,
                             ITypeTransformationMetadata typeMetadata,
                             INamespaceTransformationMetadata namespaceMetadata)
 {
     return(transformResult.AnalyzationResult.OmitAsync ? null : _rewriter.VisitFunction(transformResult.Transformed));
 }
        private BlockSyntax AddGuards(IFunctionTransformationResult transformResult, BlockSyntax methodBody,
                                      IFunctionAnalyzationResult methodResult, string cancellationTokenParamName)
        {
            if (!_configuration.Guards || methodBody == null || methodResult.Faulted)
            {
                return(methodBody);
            }

            // Avoid duplicate guards if the first statement also needs a guard
            var afterGuardIndex = methodBody.Statements.Count > methodResult.Preconditions.Count
                                ? (int?)methodResult.Preconditions.Count
                                : null;
            int?afterGuardStatementSpan = null;

            if (afterGuardIndex.HasValue)
            {
                // We have to update the methodBody node in order to have correct spans
                var afterGuardStatement = methodBody.Statements[afterGuardIndex.Value];
                methodBody = methodBody.ReplaceNode(afterGuardStatement,
                                                    afterGuardStatement.WithAdditionalAnnotations(new SyntaxAnnotation("AfterGuardStatement")));
                afterGuardStatementSpan = methodBody.Statements[afterGuardIndex.Value].SpanStart;
            }

            // 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 = methodBody
                                .GetAnnotatedNodes(functionReference.Annotation)
                                .First().Ancestors().OfType <StatementSyntax>().First();
                if (statements.ContainsKey(statement.SpanStart) ||
                    (afterGuardStatementSpan.HasValue && afterGuardStatementSpan.Value == statement.SpanStart))
                {
                    continue;
                }

                var annotation = Guid.NewGuid().ToString();
                methodBody = methodBody
                             .ReplaceNode(statement, statement.WithAdditionalAnnotations(new SyntaxAnnotation(annotation)));
                statements.Add(statement.SpanStart, annotation);
            }

            var startGuard = methodResult.OmitAsync
                                ? GetSyncGuard(methodResult, cancellationTokenParamName, transformResult.BodyLeadingWhitespaceTrivia,
                                               transformResult.EndOfLineTrivia, transformResult.IndentTrivia)
                                : GetAsyncGuard(cancellationTokenParamName, transformResult.BodyLeadingWhitespaceTrivia,
                                                transformResult.EndOfLineTrivia);

            methodBody = methodBody.WithStatements(methodBody.Statements.Insert(methodResult.Preconditions.Count, startGuard));

            // 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   = methodBody.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)));
                methodBody = methodBody
                             .ReplaceNode(parentBlock, newParentBlock);
            }

            return(methodBody);
        }