您可能知道,我们可以根据Roslyn和Visual Studio Integration提供的工具为我们的CSharp项目开发一些分析器和代码修复程序。
当我开发代码修补程序以更改代码语法树时,它适用于WellKnownFixAllProviders.BatchFixer
。例如,将所有TypeDeclaration名称更改为大写。
public class MyClassCodeFixProvider : CodeFixProvider
{
private const string title = "MyClassCodeFix";
public sealed override ImmutableArray<string> FixableDiagnosticIds
{
get { return ImmutableArray.Create("MyClassCodeFix"); }
}
public sealed override FixAllProvider GetFixAllProvider()
{
return WellKnownFixAllProviders.BatchFixer;
}
public async sealed override Task RegisterCodeFixesAsync(CodeFixContext context)
{
var document = context.Document;
var span = context.Span;
var cancellationToken = context.CancellationToken;
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var token = root.FindToken(span.Start);
if (!token.Span.IntersectsWith(span))
{
return;
}
Diagnostic diagnostic = context.Diagnostics.First();
TextSpan diagnosticSpan = diagnostic.Location.SourceSpan;
TypeDeclarationSyntax declaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<TypeDeclarationSyntax>().First();
var codeChangeForDocument = CodeAction.Create(
title: title,
//this code works fine
createChangedSolution: c => MakeUppercaseAsync(context, declaration, c),
equivalenceKey: title);
context.RegisterCodeFix(codeChangeForDocument, context.Diagnostics);
}
private async Task<Solution> MakeUppercaseAsync(CodeFixContext context, TypeDeclarationSyntax typeDecl, CancellationToken cancellationToken)
{
var identifierToken = typeDecl.Identifier;
var newName = identifierToken.Text.ToUpperInvariant();
var semanticModel = await context.Document.GetSemanticModelAsync(cancellationToken);
var typeSymbol = semanticModel.GetDeclaredSymbol(typeDecl, cancellationToken);
var originalSolution = context.Document.Project.Solution;
var optionSet = originalSolution.Workspace.Options;
var newSolution = await Renamer.RenameSymbolAsync(context.Document.Project.Solution, typeSymbol, newName, optionSet, cancellationToken).ConfigureAwait(false);
return newSolution;
}
}
但是,当我们在代码修复中添加一些新文档,然后我们在文档或项目或解决方案中使用代码修复时,它根本不起作用(WellKnownFixAllProviders.BatchFixer
窗口无法打开)。但是当我们在一个诊断上调用我们的代码修复时,它就完美了。
public sealed override FixAllProvider GetFixAllProvider()
{
return WellKnownFixAllProviders.BatchFixer;
}
public async sealed override Task RegisterCodeFixesAsync(CodeFixContext context)
{
var document = context.Document;
var span = context.Span;
var cancellationToken = context.CancellationToken;
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var token = root.FindToken(span.Start);
if (!token.Span.IntersectsWith(span))
{
return;
}
Diagnostic diagnostic = context.Diagnostics.First();
TextSpan diagnosticSpan = diagnostic.Location.SourceSpan;
TypeDeclarationSyntax declaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<TypeDeclarationSyntax>().First();
var codeChangeForDocument = CodeAction.Create(
title: title,
//createChangedSolution: c => MakeUppercaseAsync(context.Document, declaration, c),
//this code does not work
createChangedSolution : c => GenerateDocForSolution(context, declaration, c),
equivalenceKey: title);
context.RegisterCodeFix(codeChangeForDocument, context.Diagnostics);
}
private async Task<Solution> GenerateDocForSolution(CodeFixContext context, TypeDeclarationSyntax declaration, CancellationToken cancellationToken)
{
var model = await context.Document.GetSemanticModelAsync(cancellationToken);
ExtractPropFromEntitySyntaxWalker extractor = new ExtractPropFromEntitySyntaxWalker(model);
extractor.Visit(declaration);
var currentDoc = context.Document.Project.Documents.SingleOrDefault(doc => doc.Name == string.Format("{0}Auto", declaration.Identifier.Text));
Document newDoc = null;
if (currentDoc != null)
{
newDoc = currentDoc.WithSyntaxRoot(extractor.NewSyntax);
}
else
{
newDoc = context.Document.Project.AddDocument(string.Format("{0}Auto", declaration.Identifier.Text),
extractor.NewSyntax.GetText()
);
}
return newDoc.Project.Solution;
}
据我所知,WellKnownFixAllProviders.BatchFixer
合并了解决方案,项目或文档中所有诊断的所有代码修复所做的所有更改。
WellKnownFixAllProviders.BatchFixer
是否支持此类方案?