提交 f10ee727 编写于 作者: C Cyrus Najmabadi

Make shared impl

上级 fba2e439
......@@ -8,6 +8,7 @@
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.IntroduceVariable;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
......@@ -15,59 +16,30 @@
namespace Microsoft.CodeAnalysis.CSharp.IntroduceVariable
{
[ExportCodeRefactoringProvider(LanguageNames.CSharp), Shared]
internal class CSharpIntroduceLocalForExpressionCodeRefactoringProvider : CodeRefactoringProvider
internal class CSharpIntroduceLocalForExpressionCodeRefactoringProvider :
AbstractIntroduceLocalForExpressionCodeRefactoringProvider<
StatementSyntax,
ExpressionStatementSyntax,
LocalDeclarationStatementSyntax>
{
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
protected override bool IsValid(ExpressionStatementSyntax expressionStatement, TextSpan span)
{
var document = context.Document;
var span = context.Span;
var cancellationToken = context.CancellationToken;
var expressionStatement = await GetExpressionStatementAsync(document, span, cancellationToken).ConfigureAwait(false);
if (expressionStatement == null)
{
return;
}
var expression = expressionStatement.Expression;
// Expression is likely too simple to want to offer to generate a local for.
// This leads to too many false cases where this is offered.
if (span.IsEmpty &&
expressionStatement.SemicolonToken.IsMissing &&
expression.IsKind(SyntaxKind.IdentifierName))
{
return;
}
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var type = semanticModel.GetTypeInfo(expression).Type;
if (type == null ||
type.SpecialType == SpecialType.System_Void)
expressionStatement.Expression.IsKind(SyntaxKind.IdentifierName))
{
return;
return false;
}
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
var singleLineExpression = syntaxFacts.ConvertToSingleLine(expression);
var nodeString = singleLineExpression.ToString();
context.RegisterRefactoring(new MyCodeAction(
string.Format(FeaturesResources.Introduce_local_for_0, nodeString),
c => IntroduceLocalAsync(document, span, c)));
return true;
}
private static async Task<ExpressionStatementSyntax> GetExpressionStatementAsync(Document document, TextSpan span, CancellationToken cancellationToken)
{
var helpers = document.GetLanguageService<IRefactoringHelpersService>();
var expressionStatement = await helpers.TryGetSelectedNodeAsync<ExpressionStatementSyntax>(document, span, cancellationToken).ConfigureAwait(false);
return expressionStatement;
}
private async Task<Document> IntroduceLocalAsync(Document document, TextSpan span, CancellationToken cancellationToken)
protected override async Task<LocalDeclarationStatementSyntax> CreateLocalDeclarationAsync(
Document document, ExpressionStatementSyntax expressionStatement, CancellationToken cancellationToken)
{
var expressionStatement = await GetExpressionStatementAsync(document, span, cancellationToken).ConfigureAwait(false);
var expression = expressionStatement.Expression;
var semicolon = expressionStatement.SemicolonToken;
......@@ -99,10 +71,7 @@ private async Task<Document> IntroduceLocalAsync(Document document, TextSpan spa
.WithSemicolonToken(semicolon)
.WithLeadingTrivia(expression.GetLeadingTrivia());
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var newRoot = root.ReplaceNode(expressionStatement, localDeclaration);
return document.WithSyntaxRoot(newRoot);
return localDeclaration;
}
private class MyCodeAction : CodeAction.DocumentChangeAction
......
......@@ -2,17 +2,86 @@
using System;
using System.Collections.Generic;
using System.Composition;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.IntroduceVariable
{
internal class IntroduceLocalForExpressionCodeRefactoringProvider : CodeRefactoringProvider
internal abstract class AbstractIntroduceLocalForExpressionCodeRefactoringProvider<
TStatementSyntax,
TExpressionStatementSyntax,
TLocalDeclarationStatementSyntax> : CodeRefactoringProvider
where TStatementSyntax : SyntaxNode
where TExpressionStatementSyntax : TStatementSyntax
where TLocalDeclarationStatementSyntax : TStatementSyntax
{
public override Task ComputeRefactoringsAsync(CodeRefactoringContext context)
protected abstract bool IsValid(TExpressionStatementSyntax expressionStatement, TextSpan span);
protected abstract Task<TLocalDeclarationStatementSyntax> CreateLocalDeclarationAsync(Document document, TExpressionStatementSyntax expressionStatement, CancellationToken cancellationToken);
public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
{
var document = context.Document;
var span = context.Span;
var cancellationToken = context.CancellationToken;
var expressionStatement = await GetExpressionStatementAsync(document, span, cancellationToken).ConfigureAwait(false);
if (expressionStatement == null)
{
return;
}
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
var expression = syntaxFacts.GetExpressionOfExpressionStatement(expressionStatement);
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var type = semanticModel.GetTypeInfo(expression).Type;
if (type == null ||
type.SpecialType == SpecialType.System_Void)
{
return;
}
var singleLineExpression = syntaxFacts.ConvertToSingleLine(expression);
var nodeString = singleLineExpression.ToString();
context.RegisterRefactoring(new MyCodeAction(
string.Format(FeaturesResources.Introduce_local_for_0, nodeString),
c => IntroduceLocalAsync(document, span, c)));
}
protected async Task<TExpressionStatementSyntax> GetExpressionStatementAsync(Document document, TextSpan span, CancellationToken cancellationToken)
{
var helpers = document.GetLanguageService<IRefactoringHelpersService>();
var expressionStatement = await helpers.TryGetSelectedNodeAsync<TExpressionStatementSyntax>(document, span, cancellationToken).ConfigureAwait(false);
return expressionStatement != null && IsValid(expressionStatement, span)
? expressionStatement
: null;
}
private async Task<Document> IntroduceLocalAsync(Document document, TextSpan span, CancellationToken cancellationToken)
{
var expressionStatement = await GetExpressionStatementAsync(document, span, cancellationToken).ConfigureAwait(false);
var localDeclaration = await CreateLocalDeclarationAsync(document, expressionStatement, cancellationToken).ConfigureAwait(false);
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var newRoot = root.ReplaceNode(expressionStatement, localDeclaration);
return document.WithSyntaxRoot(newRoot);
}
private class MyCodeAction : CodeAction.DocumentChangeAction
{
throw new NotImplementedException();
public MyCodeAction(string title, Func<CancellationToken, Task<Document>> createChangedDocument)
: base(title, createChangedDocument)
{
}
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册