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)))); } }
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))); }