我最近开始使用CodeAnalyzers和CodeFixes。
当然,sdk()附带的模板有效。但是当我继续前进时,codefix不会再出现在调试中。
在完成诊断时,按照预期创建诊断。 但是:codefix(Strg +。)不再显示了。我负责Diagnostic-Id,等价键,但是无法搞清楚,为什么我不再显示我的codefix。那么为诊断显示代码的最低“要求”是什么?
以下是分析仪的代码:
[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);
}
}
答案 0 :(得分:0)
memberDeclarationModifiers.Add(SyntaxFactory.Token(SyntaxKind.VirtualKeyword));
会返回新的SyntaxTokenList
。您没有使用新创建的列表。请记住,SyntaxTrees在Roslyn中是不可变的。树中的每个更改都将创建一个新树。这是你的roslyn codefix的codefix:)
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);
}