2017-11-20 17 views
0

최근에 CodeAnalyzers 및 CodeFixes로 시작했습니다.C# CodeFixes : codefix가 표시되는 최소 요구 사항

물론 sdk()와 함께 제공되는 템플릿이 작동합니다. 그러나 내가 나아갈 때, codefix는 더 이상 디버깅에 나타나지 않습니다.

진단을 통해 걸을 때 예상대로 진행됩니다. 하지만 : codefix (Strg +.)는 더 이상 표시되지 않습니다. Diagnostic-Id, equivalence-key를 돌 보았습니다 ...하지만 더 이상 내 코드가 표시되지 않는 이유를 알아낼 수 없습니다. 그렇다면 진단을 위해 코드 픽스를 표시하기위한 최소한의 "요구 사항"은 무엇입니까?

[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-제공자의 :

[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

memberDeclarationModifiers.Add(SyntaxFactory.Token(SyntaxKind.VirtualKeyword)); 반환 새로운 SyntaxTokenList 여기


는 분석기의 코드입니다. 새로 생성 된 목록을 사용하고 있지 않습니다. SyntaxTrees는 Roslyn에서 변경할 수 없음을 기억하십시오. 나무가 바뀔 때마다 새로운 나무가 생깁니다. roslyn 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); 
}