C# 代码修复:显示代码修复的最低要求
C# CodeFixes: Minimum Requirement that codefix is displayed
我最近开始使用 CodeAnalyzers 和 CodeFixes。
sdk()自带的模板当然可以。但是当我继续时,codefix 不再出现在调试中。
当遍历时,诊断会按预期创建。
但是:代码修复 (Strg+.) 不再显示。我处理了 Diagnostic-Id、equivalence-key,...但无法弄清楚,为什么我不再显示我的代码修复。那么要为诊断显示的代码修复的最小 "requirements" 是多少?
分析器代码如下:
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class VirtualMemberAnalyzer : DiagnosticAnalyzer
{
public const string PublicVirtualMethod_DiagnosticId = "PublicVirtualMethod";
private const string Category = "Naming";
private static readonly DiagnosticDescriptor PublicMethodVirtualRule = new DiagnosticDescriptor(
PublicVirtualMethod_DiagnosticId,
"public methode not virtual",
"every public methode must be virtual",
Category,
DiagnosticSeverity.Error,
true);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
ImmutableArray.Create(PublicMethodVirtualRule);
public override void Initialize(AnalysisContext context)
{
context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType);
}
private static void AnalyzeSymbol(SymbolAnalysisContext context)
{
var namedTypeSymbol = (INamedTypeSymbol)context.Symbol;
foreach (var methodSymbol in namedTypeSymbol.GetMembers().OfType<IMethodSymbol>())
{
if (methodSymbol.MethodKind == MethodKind.Ordinary && !methodSymbol.IsStatic && !methodSymbol.IsVirtual && methodSymbol.DeclaredAccessibility == Accessibility.Public)
{
var diagnostic = Diagnostic.Create(
PublicMethodVirtualRule,
methodSymbol.Locations[0],
methodSymbol.Name);
context.ReportDiagnostic(diagnostic);
}
}
}
}
以及 Codefix-Provider 的:
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(VirtualMemberAnalyzersCodeFixProvider)), Shared]
public class VirtualMemberAnalyzersCodeFixProvider : CodeFixProvider {
private const string title_property = "Make property virtual";
private const string title_method = "Make method virtual";
public sealed override ImmutableArray<string> FixableDiagnosticIds {
get {
return ImmutableArray.Create(VirtualMemberAnalyzer.PublicVirtualMethod_DiagnosticId);
}
}
public sealed override FixAllProvider GetFixAllProvider() {
return WellKnownFixAllProviders.BatchFixer;
}
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) {
var root = await context.Document.GetSyntaxRootAsync();
var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
var methodDeclarations = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<MethodDeclarationSyntax>().FirstOrDefault();
if (methodDeclarations != null) {
CodeAction codeAction = CodeAction.Create(title_method, c => MakeVirtual(context.Document, methodDeclarations, c), equivalenceKey: title_method);
context.RegisterCodeFix(codeAction, diagnostic);
}
}
private async Task<Document> MakeVirtual(Document document, MethodDeclarationSyntax memberDeclaration, CancellationToken cancellationToken)
{
SyntaxTokenList memberDeclarationModifiers = memberDeclaration.Modifiers;
memberDeclarationModifiers.Add(SyntaxFactory.Token(SyntaxKind.VirtualKeyword));
MethodDeclarationSyntax methodDeclarationSyntax = memberDeclaration.WithModifiers(memberDeclarationModifiers);
var oldRoot = await document.GetSyntaxRootAsync(cancellationToken);
var newRoot = oldRoot.ReplaceNode(memberDeclaration, methodDeclarationSyntax);
return document.WithSyntaxRoot(newRoot);
}
}
memberDeclarationModifiers.Add(SyntaxFactory.Token(SyntaxKind.VirtualKeyword));
returns一个新的SyntaxTokenList
。您没有使用新创建的列表。请记住,语法树在 Roslyn 中是不可变的。树中的每个更改都会创建一棵新树。这是您的 roslyn 代码修复的代码修复:)
private async Task<Document> MakeVirtual(Document document, MethodDeclarationSyntax memberDeclaration, CancellationToken cancellationToken)
{
var methodDeclarationSyntax =
memberDeclaration.WithModifiers(
memberDeclaration.Modifiers.Add( SyntaxFactory.Token( SyntaxKind.VirtualKeyword ) ) );
var oldRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait( false );
var newRoot = oldRoot.ReplaceNode(memberDeclaration, methodDeclarationSyntax);
return document.WithSyntaxRoot(newRoot);
}
我最近开始使用 CodeAnalyzers 和 CodeFixes。
sdk()自带的模板当然可以。但是当我继续时,codefix 不再出现在调试中。
当遍历时,诊断会按预期创建。 但是:代码修复 (Strg+.) 不再显示。我处理了 Diagnostic-Id、equivalence-key,...但无法弄清楚,为什么我不再显示我的代码修复。那么要为诊断显示的代码修复的最小 "requirements" 是多少?
分析器代码如下:
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class VirtualMemberAnalyzer : DiagnosticAnalyzer
{
public const string PublicVirtualMethod_DiagnosticId = "PublicVirtualMethod";
private const string Category = "Naming";
private static readonly DiagnosticDescriptor PublicMethodVirtualRule = new DiagnosticDescriptor(
PublicVirtualMethod_DiagnosticId,
"public methode not virtual",
"every public methode must be virtual",
Category,
DiagnosticSeverity.Error,
true);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
ImmutableArray.Create(PublicMethodVirtualRule);
public override void Initialize(AnalysisContext context)
{
context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType);
}
private static void AnalyzeSymbol(SymbolAnalysisContext context)
{
var namedTypeSymbol = (INamedTypeSymbol)context.Symbol;
foreach (var methodSymbol in namedTypeSymbol.GetMembers().OfType<IMethodSymbol>())
{
if (methodSymbol.MethodKind == MethodKind.Ordinary && !methodSymbol.IsStatic && !methodSymbol.IsVirtual && methodSymbol.DeclaredAccessibility == Accessibility.Public)
{
var diagnostic = Diagnostic.Create(
PublicMethodVirtualRule,
methodSymbol.Locations[0],
methodSymbol.Name);
context.ReportDiagnostic(diagnostic);
}
}
}
}
以及 Codefix-Provider 的:
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(VirtualMemberAnalyzersCodeFixProvider)), Shared]
public class VirtualMemberAnalyzersCodeFixProvider : CodeFixProvider {
private const string title_property = "Make property virtual";
private const string title_method = "Make method virtual";
public sealed override ImmutableArray<string> FixableDiagnosticIds {
get {
return ImmutableArray.Create(VirtualMemberAnalyzer.PublicVirtualMethod_DiagnosticId);
}
}
public sealed override FixAllProvider GetFixAllProvider() {
return WellKnownFixAllProviders.BatchFixer;
}
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) {
var root = await context.Document.GetSyntaxRootAsync();
var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
var methodDeclarations = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<MethodDeclarationSyntax>().FirstOrDefault();
if (methodDeclarations != null) {
CodeAction codeAction = CodeAction.Create(title_method, c => MakeVirtual(context.Document, methodDeclarations, c), equivalenceKey: title_method);
context.RegisterCodeFix(codeAction, diagnostic);
}
}
private async Task<Document> MakeVirtual(Document document, MethodDeclarationSyntax memberDeclaration, CancellationToken cancellationToken)
{
SyntaxTokenList memberDeclarationModifiers = memberDeclaration.Modifiers;
memberDeclarationModifiers.Add(SyntaxFactory.Token(SyntaxKind.VirtualKeyword));
MethodDeclarationSyntax methodDeclarationSyntax = memberDeclaration.WithModifiers(memberDeclarationModifiers);
var oldRoot = await document.GetSyntaxRootAsync(cancellationToken);
var newRoot = oldRoot.ReplaceNode(memberDeclaration, methodDeclarationSyntax);
return document.WithSyntaxRoot(newRoot);
}
}
memberDeclarationModifiers.Add(SyntaxFactory.Token(SyntaxKind.VirtualKeyword));
returns一个新的SyntaxTokenList
。您没有使用新创建的列表。请记住,语法树在 Roslyn 中是不可变的。树中的每个更改都会创建一棵新树。这是您的 roslyn 代码修复的代码修复:)
private async Task<Document> MakeVirtual(Document document, MethodDeclarationSyntax memberDeclaration, CancellationToken cancellationToken)
{
var methodDeclarationSyntax =
memberDeclaration.WithModifiers(
memberDeclaration.Modifiers.Add( SyntaxFactory.Token( SyntaxKind.VirtualKeyword ) ) );
var oldRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait( false );
var newRoot = oldRoot.ReplaceNode(memberDeclaration, methodDeclarationSyntax);
return document.WithSyntaxRoot(newRoot);
}