2017-05-29 28 views
1

我想製作一個分析器,該代碼將爲每個出現在代碼中的某個特定成員發出一條消息(嚴重性=信息)。這模仿[Obsolete(...)]的行爲,但只是拋出一條消息。查找引用某個特定屬性的符號的所有引用

屬性定義會是這樣的

public class ThrowsMessageAttribute : Attribute 
{ 
    // ... 
} 

我想拋出一個消息,然後將它歸因員:

public class Foo 
{ 
    [ThrowsMessage] 
    public void Bar() { } 
} 

對於每個Bar()我在代碼中使用,我現在會在錯誤列表的消息選項卡中獲得一個條目。

我的出發點是一個空DiagnosticAnalyzer類:

[DiagnosticAnalyzer(LanguageNames.CSharp)] 
internal class MyDiagnosticAnalyzer : DiagnosticAnalyzer 
{ 
    private static readonly DiagnosticDescriptor Descriptor = 
    new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Info, true, Description, HelpLink); 

    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(Descriptor); 

    public override void Initialize(AnalysisContext context) 
    { 
    // how to go on from here? 
    } 
} 

具有AnalysisContext我怎麼前進?我需要在ordner中實現哪些邏輯以找到所有以特殊方式歸因的符號參考?

也許我完全在錯誤的軌道上,解決這個問題不應該通過分析儀來完成。還有哪些其他選項可用?

編輯

基於@陶的建議,我得到了它與下面的代碼幾乎工作:

public override void Initialize(AnalysisContext context) 
{ 
    context.RegisterSemanticModelAction(Analyze); 
} 

private static void Analyze(SemanticModelAnalysisContext context) 
{ 
    var semanticModel = context.SemanticModel; 
    var step2 = GetSymbolsOfAttributedMethods(semanticModel, "ThrowsMessage"); 
    Step3(context, list2, semanticModel); 
} 

private static List<ISymbol> GetSymbolsOfAttributedMethods(SemanticModel semanticModel, string attributeName) 
{ 
    var methodDeclarations = semanticModel.SyntaxTree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>(); 
    var symbolList = new List<ISymbol>(); 

    foreach (var declaration in methodDeclarations) 
    { 
    foreach (var attributeList in declaration.AttributeLists) 
    { 
     if (attributeList.Attributes.Any(a => (a.Name as IdentifierNameSyntax)?.Identifier.Text == attributeName)) 
     { 
     symbolList.Add(semanticModel.GetDeclaredSymbol(declaration)); 
     break; 
     } 
    } 
    } 
    return symbolList; 
} 

private static void Step3(SemanticModelAnalysisContext context, List<ISymbol> attributedSymbols, SemanticModel semanticModel) 
{ 
    var invocationExpressions = semanticModel.SyntaxTree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>(); 

    foreach (var invocation in invocationExpressions) 
    { 
    var symbol = semanticModel.GetSymbolInfo(invocation).Symbol; 

    if (attributedSymbols.Contains(symbol)) 
    { 
     var l = Location.Create(context.SemanticModel.SyntaxTree, invocation.FullSpan); 
     context.ReportDiagnostic(Diagnostic.Create(Rule, l)); 
    } 
    } 
} 

可正常工作,但對此我報告的診斷是位置還不完全正確,因爲它不僅是調用,而且還是尾隨的空白。這是爲什麼?

+0

你有警告錯誤嗎? –

回答

1

這是我會走的路線:

  1. 註冊一個SemanticModelActioncontext.RegisterSemanticModelAction

  2. 查找的方法MethodDeclaration與您的特殊屬性和獲得方法的符號。這看起來像這樣:

    private List<ISymbol> GetSymbolsOfAttributedMethods(string attributeName) 
    { 
        var methodDeclarations = semanticModel.SyntaxTree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>(); 
        var symbolList = new List<ISymbol>(); 
    
        foreach (var declaration in methodDeclarations) 
        { 
         foreach (var attributeList in declaration.AttributeLists) 
         { 
          if (attributeList.Attributes.Any(a => (a.Name as IdentifierNameSyntax)?.Identifier.Text == attributeName)) 
          { 
           symbolList.Add(semanticModel.GetDeclaredSymbol(declaration)); 
           break; 
          } 
         } 
        } 
        return symbolList; 
    } 
    

    semanticModel可以從您註冊的操作的上下文中獲得。

  3. 通過所有InvocationExpression S(讓他們以類似的方式,因爲我們與methodDeclarations一樣,加載其符號(請確保您使用GetSymbolInfo(invocation).Symbol這裏,而不是GetDeclaredSymbol正如我們先前做的)。

  4. 比較如果調用符號在具有特殊屬性的符號之中,則從步驟3到步驟2的符號以及ReportDiagnostic

編輯

關於你的編輯,那是因爲你正在使用FullSpan

該節點在字符中的絕對跨度,包括其前導和結尾瑣事。

要麼使用Span或使用invocation.GetLocation()和忘記共創建Location對象。

Roslyn reference是非常徹底的,所以它通常是一個很好的看看。另外別忘了Syntax Visualizer,這個工具可以讓你的生活變得容易100倍。

+0

你讓我走上了正軌。你的頭頂建議是一塵不染。看到我的編輯有點後續問題。 – David

+0

@大衛我已經更新了關於你的編輯的答案 –

相關問題