コード例 #1
0
        private MethodTransformerResult Update(MethodDeclarationSyntax methodNode,
                                               IMethodOrAccessorAnalyzationResult methodResult, INamespaceTransformationMetadata namespaceMetadata)
        {
            methodNode = methodNode.WithIdentifier(Identifier(methodResult.AsyncCounterpartName));

            // Remove the new modifier
            if (methodNode.Modifiers.Any(o => o.IsKind(SyntaxKind.NewKeyword)))
            {
                var newMofidier = methodNode.Modifiers.First(o => o.IsKind(SyntaxKind.NewKeyword));
                if (methodNode.GetFirstToken(true).IsKind(SyntaxKind.NewKeyword))
                {
                    methodNode = methodNode
                                 .WithModifiers(TokenList(methodNode.Modifiers.Where(o => !o.IsKind(SyntaxKind.NewKeyword))))
                                 .WithLeadingTrivia(newMofidier.LeadingTrivia);
                }
                else
                {
                    var nextToken = newMofidier.GetNextToken(true);
                    methodNode = methodNode
                                 .ReplaceToken(nextToken, nextToken.WithLeadingTrivia(newMofidier.LeadingTrivia))
                                 .WithModifiers(TokenList(methodNode.Modifiers.Where(o => !o.IsKind(SyntaxKind.NewKeyword))));
                }
            }

            if (!methodResult.PreserveReturnType && methodResult.Symbol.MethodKind != MethodKind.PropertySet)
            {
                methodNode = methodNode.ReturnAsTask(namespaceMetadata.TaskConflict);
            }
            return(MethodTransformerResult.Update(methodNode));
        }
コード例 #2
0
 private MethodTransformerResult Update(MethodDeclarationSyntax methodNode,
                                        IMethodOrAccessorAnalyzationResult methodResult, INamespaceTransformationMetadata namespaceMetadata)
 {
     methodNode = methodNode.WithIdentifier(Identifier(methodResult.AsyncCounterpartName));
     if (!methodResult.PreserveReturnType && methodResult.Symbol.MethodKind != MethodKind.PropertySet)
     {
         methodNode = methodNode.ReturnAsTask(namespaceMetadata.TaskConflict);
     }
     return(MethodTransformerResult.Update(methodNode));
 }
コード例 #3
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));
        }
コード例 #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 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));
        }
        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));
        }
コード例 #7
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));
        }
コード例 #8
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);
        }
コード例 #9
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);
        }
コード例 #10
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));
        }
コード例 #11
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));
        }