protected override IEnumerable <StatementSyntax> GetInitialStatementsForMethodDefinitions()
                {
                    Contract.ThrowIfFalse(IsExtractMethodOnExpression(CSharpSelectionResult));

                    ExpressionSyntax expression = null;

                    // special case for array initializer
                    var returnType      = AnalyzerResult.ReturnType;
                    var containingScope = CSharpSelectionResult.GetContainingScope();

                    if (returnType.TypeKind == TypeKind.Array && containingScope is InitializerExpressionSyntax)
                    {
                        var typeSyntax = returnType.GenerateTypeSyntax();

                        expression = SyntaxFactory.ArrayCreationExpression(typeSyntax as ArrayTypeSyntax, containingScope as InitializerExpressionSyntax);
                    }
                    else
                    {
                        expression = containingScope as ExpressionSyntax;
                    }

                    if (AnalyzerResult.HasReturnType)
                    {
                        return(SpecializedCollections.SingletonEnumerable <StatementSyntax>(
                                   SyntaxFactory.ReturnStatement(
                                       WrapInCheckedExpressionIfNeeded(expression))));
                    }
                    else
                    {
                        return(SpecializedCollections.SingletonEnumerable <StatementSyntax>(
                                   SyntaxFactory.ExpressionStatement(
                                       WrapInCheckedExpressionIfNeeded(expression))));
                    }
                }
Beispiel #2
0
                protected override async Task <SyntaxNode> GetStatementOrInitializerContainingInvocationToExtractedMethodAsync(CancellationToken cancellationToken)
                {
                    var enclosingStatement = GetFirstStatementOrInitializerSelectedAtCallSite();

                    var callSignature = CreateCallSignature().WithAdditionalAnnotations(CallSiteAnnotation);

                    var sourceNode = CSharpSelectionResult.GetContainingScope();

                    Contract.ThrowIfTrue(
                        sourceNode.Parent is MemberAccessExpressionSyntax && ((MemberAccessExpressionSyntax)sourceNode.Parent).Name == sourceNode,
                        "invalid scope. given scope is not an expression");

                    // To lower the chances that replacing sourceNode with callSignature will break the user's
                    // code, we make the enclosing statement semantically explicit. This ends up being a little
                    // bit more work because we need to annotate the sourceNode so that we can get back to it
                    // after rewriting the enclosing statement.
                    var updatedDocument              = SemanticDocument.Document;
                    var sourceNodeAnnotation         = new SyntaxAnnotation();
                    var enclosingStatementAnnotation = new SyntaxAnnotation();
                    var newEnclosingStatement        = enclosingStatement
                                                       .ReplaceNode(sourceNode, sourceNode.WithAdditionalAnnotations(sourceNodeAnnotation))
                                                       .WithAdditionalAnnotations(enclosingStatementAnnotation);

                    updatedDocument = await updatedDocument.ReplaceNodeAsync(enclosingStatement, newEnclosingStatement, cancellationToken).ConfigureAwait(false);

                    var updatedRoot = await updatedDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                    newEnclosingStatement = updatedRoot.GetAnnotatedNodesAndTokens(enclosingStatementAnnotation).Single().AsNode();

                    // because of the complexification we cannot guarantee that there is only one annotation.
                    // however complexification of names is prepended, so the last annotation should be the original one.
                    sourceNode = updatedRoot.GetAnnotatedNodesAndTokens(sourceNodeAnnotation).Last().AsNode();

                    return(newEnclosingStatement.ReplaceNode(sourceNode, callSignature));
                }
                protected override async Task <SyntaxNode> GetStatementOrInitializerContainingInvocationToExtractedMethodAsync(
                    SyntaxAnnotation callSiteAnnotation, CancellationToken cancellationToken)
                {
                    var enclosingStatement = GetFirstStatementOrInitializerSelectedAtCallSite();
                    var callSignature      = CreateCallSignature().WithAdditionalAnnotations(callSiteAnnotation);
                    var invocation         = callSignature.IsKind(SyntaxKind.AwaitExpression, out AwaitExpressionSyntax awaitExpr) ? awaitExpr.Expression : callSignature;

                    var sourceNode = CSharpSelectionResult.GetContainingScope();

                    Contract.ThrowIfTrue(
                        sourceNode.Parent is MemberAccessExpressionSyntax && ((MemberAccessExpressionSyntax)sourceNode.Parent).Name == sourceNode,
                        "invalid scope. given scope is not an expression");

                    // To lower the chances that replacing sourceNode with callSignature will break the user's
                    // code, we make the enclosing statement semantically explicit. This ends up being a little
                    // bit more work because we need to annotate the sourceNode so that we can get back to it
                    // after rewriting the enclosing statement.
                    var updatedDocument              = SemanticDocument.Document;
                    var sourceNodeAnnotation         = new SyntaxAnnotation();
                    var enclosingStatementAnnotation = new SyntaxAnnotation();
                    var newEnclosingStatement        = enclosingStatement
                                                       .ReplaceNode(sourceNode, sourceNode.WithAdditionalAnnotations(sourceNodeAnnotation))
                                                       .WithAdditionalAnnotations(enclosingStatementAnnotation);

                    updatedDocument = await updatedDocument.ReplaceNodeAsync(enclosingStatement, newEnclosingStatement, cancellationToken).ConfigureAwait(false);

                    var updatedRoot = await updatedDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                    newEnclosingStatement = updatedRoot.GetAnnotatedNodesAndTokens(enclosingStatementAnnotation).Single().AsNode();

                    // because of the complexification we cannot guarantee that there is only one annotation.
                    // however complexification of names is prepended, so the last annotation should be the original one.
                    sourceNode = updatedRoot.GetAnnotatedNodesAndTokens(sourceNodeAnnotation).Last().AsNode();

                    // we want to replace the old identifier with a invocation expression, but because of MakeExplicit we might have
                    // a member access now instead of the identifier. So more syntax fiddling is needed.
                    if (sourceNode.Parent.Kind() == SyntaxKind.SimpleMemberAccessExpression &&
                        ((ExpressionSyntax)sourceNode).IsRightSideOfDot())
                    {
                        var explicitMemberAccess    = (MemberAccessExpressionSyntax)sourceNode.Parent;
                        var replacementMemberAccess = explicitMemberAccess.CopyAnnotationsTo(
                            SyntaxFactory.MemberAccessExpression(
                                sourceNode.Parent.Kind(),
                                explicitMemberAccess.Expression,
                                (SimpleNameSyntax)((InvocationExpressionSyntax)invocation).Expression));
                        var newInvocation = SyntaxFactory.InvocationExpression(
                            replacementMemberAccess,
                            ((InvocationExpressionSyntax)invocation).ArgumentList);

                        var newCallSignature = callSignature != invocation?
                                               callSignature.ReplaceNode(invocation, newInvocation) : invocation.CopyAnnotationsTo(newInvocation);

                        sourceNode    = sourceNode.Parent;
                        callSignature = newCallSignature;
                    }

                    return(newEnclosingStatement.ReplaceNode(sourceNode, callSignature));
                }
                protected override SyntaxToken CreateMethodName()
                {
                    var methodName = GenerateMethodNameFromUserPreference();

                    var containingScope = CSharpSelectionResult.GetContainingScope();

                    methodName = GetMethodNameBasedOnExpression(methodName, containingScope);

                    var semanticModel = SemanticDocument.SemanticModel;
                    var nameGenerator = new UniqueNameGenerator(semanticModel);

                    return(SyntaxFactory.Identifier(nameGenerator.CreateUniqueMethodName(containingScope, methodName)));
                }