查找具有某些特殊属性的符号的所有引用
Find all references of a symbol that is attributed with some special attribute
我想制作一个分析器,它会针对代码中某个属性成员的每次出现抛出一条消息(严重性 = 信息)。这模仿了 [Obsolete(...)]
的行为,但只抛出一条消息。
属性定义类似于
public class ThrowsMessageAttribute : Attribute
{
// ...
}
我要为其发送消息的成员将被归因于它:
public class Foo
{
[ThrowsMessage]
public void Bar() { }
}
对于我在代码中使用的每个 Bar()
,我现在都会在错误列表的消息选项卡中获得一个条目。
我的起点是一个空的 DiagnosticAnalyzer class:
[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
我该如何继续前进?我需要实现什么逻辑才能找到所有以不同方式归因的符号引用?
也许我完全走错了路,解决这个问题不应该通过分析器来完成。还有哪些其他选项可用?
编辑
根据@Tamás 的建议,我使用以下代码几乎可以正常工作:
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));
}
}
}
这按预期工作,但我报告诊断的位置还不太正确,因为它不仅是调用而且是尾随空格。这是为什么?
这是我要走的路线:
用context.RegisterSemanticModelAction
注册一个SemanticModelAction
找到 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
可以从您注册的操作的上下文中获取。
遍历所有 InvocationExpression
(以与 methodDeclarations
类似的方式获取它们),加载它们的符号(确保使用 GetSymbolInfo(invocation).Symbol
这里而不是我们之前做的GetDeclaredSymbol
。
将步骤 3 中的符号与步骤 2 中的符号进行比较,如果调用的符号属于具有特殊属性的符号,则 ReportDiagnostic
。
编辑
关于您的编辑,是因为您使用的是FullSpan
。
The absolute span of this node in characters, including its leading and trailing trivia.
要么使用 Span
or use invocation.GetLocation()
而完全忘记创建 Location
对象。
Roslyn reference is pretty thorough so it's usually a good place to look. And don't forget the Syntax Visualizer,另一个可以让您的生活轻松 100 倍的工具。
我想制作一个分析器,它会针对代码中某个属性成员的每次出现抛出一条消息(严重性 = 信息)。这模仿了 [Obsolete(...)]
的行为,但只抛出一条消息。
属性定义类似于
public class ThrowsMessageAttribute : Attribute
{
// ...
}
我要为其发送消息的成员将被归因于它:
public class Foo
{
[ThrowsMessage]
public void Bar() { }
}
对于我在代码中使用的每个 Bar()
,我现在都会在错误列表的消息选项卡中获得一个条目。
我的起点是一个空的 DiagnosticAnalyzer class:
[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
我该如何继续前进?我需要实现什么逻辑才能找到所有以不同方式归因的符号引用?
也许我完全走错了路,解决这个问题不应该通过分析器来完成。还有哪些其他选项可用?
编辑
根据@Tamás 的建议,我使用以下代码几乎可以正常工作:
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));
}
}
}
这按预期工作,但我报告诊断的位置还不太正确,因为它不仅是调用而且是尾随空格。这是为什么?
这是我要走的路线:
用
context.RegisterSemanticModelAction
注册一个找到
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
可以从您注册的操作的上下文中获取。遍历所有
InvocationExpression
(以与methodDeclarations
类似的方式获取它们),加载它们的符号(确保使用GetSymbolInfo(invocation).Symbol
这里而不是我们之前做的GetDeclaredSymbol
。将步骤 3 中的符号与步骤 2 中的符号进行比较,如果调用的符号属于具有特殊属性的符号,则
ReportDiagnostic
。
SemanticModelAction
编辑
关于您的编辑,是因为您使用的是FullSpan
。
The absolute span of this node in characters, including its leading and trailing trivia.
要么使用 Span
or use invocation.GetLocation()
而完全忘记创建 Location
对象。
Roslyn reference is pretty thorough so it's usually a good place to look. And don't forget the Syntax Visualizer,另一个可以让您的生活轻松 100 倍的工具。