确定是不是使用 Roslyn 读取私有字段
Posted
技术标签:
【中文标题】确定是不是使用 Roslyn 读取私有字段【英文标题】:Determining if a private field is read using Roslyn确定是否使用 Roslyn 读取私有字段 【发布时间】:2021-12-06 17:14:14 【问题描述】:我整天都在搜索并阅读了很多帖子,但我无法就此得出结论。我正在尝试创建一个 Roslyn 分析器以在未读取私有字段时报告诊断。注册语法动作并找出它是否是私有的真的很容易。但是现在我一直在尝试找出该字段是否在课堂上被读取。
假设我们有以下示例代码:
public class C
private int foo; //private field is declared but never read. Should report diagnostic here
public void DoNothing()
//irrelevant
有几个我希望在哪里标记的示例(初始化与否、注入与否、单行上的多个声明等),但我认为它们可能不是说明问题所必需的。
到目前为止,我所拥有的是:
public override void Initialize(AnalysisContext context)
context.EnableConcurrentExecution();
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.RegisterSyntaxNodeAction(AnalyzeField, SyntaxKind.FieldDeclaration);
private void AnalyzeField(SyntaxNodeAnalysisContext context)
if (!(context.Node is FieldDeclarationSyntax fieldDeclarationSyntax))
return;
foreach (var variableDeclaration in fieldDeclarationSyntax.Declaration.Variables)
if (context.SemanticModel.GetDeclaredSymbol(variableDeclaration) is IFieldSymbol variableDeclarationSymbol &&
IsFieldPrivate(variableDeclarationSymbol) &&
!IsFieldRead(context, variableDeclarationSymbol))
//report diagnostic here
private bool IsFieldPrivate(IFieldSymbol fieldSymbol)
return fieldSymbol.DeclaredAccessibility == Accessibility.Private || // the field itself is explicitly private
fieldSymbol.ContainingType?.DeclaredAccessibility == Accessibility.Private; //the field is not private, but is contained within a private class
private bool IsFieldRead(SyntaxNodeAnalysisContext context, IFieldSymbol fieldSymbol)
//context.Node.Parent will be the class declaration here since we're analyzing a field declaration
//but let's be safe about that just in case and make sure we traverse up until we find the class declaration
var classDeclarationSyntax = context.Node.Parent;
while (!(classDeclarationSyntax is ClassDeclarationSyntax))
classDeclarationSyntax = classDeclarationSyntax.Parent;
var methodsInClassContainingPrivateField = classDeclarationSyntax.DescendantNodes().OfType<MethodDeclarationSyntax>().ToImmutableArray();
foreach (var method in methodsInClassContainingPrivateField)
var dataFlowAnalysis = context.SemanticModel.AnalyzeDataFlow(method); //does not work because this is not a StatementSyntax or ExpressionSyntax
if (dataFlowAnalysis.ReadInside.Contains(fieldSymbol) || dataFlowAnalysis.ReadOutside.Contains(fieldSymbol))
return true;
return false;
我只是不知道如何让IsFieldRead()
方法工作。这真的感觉像是应该很容易做到的事情,但我就是不能完全理解它。我认为获取方法并为我的领域分析这些方法以查看它是否被读取将是一个不错的主意,但这并不包括该字段是否被另一个私有字段读取,而且我无论如何都无法让它工作。 :)
【问题讨论】:
【参考方案1】:感谢this other SO answer 的一位在 Microsoft 为 Roslyn 工作的人,我设法弄清楚了这一点。这是我现在的IsFieldRead()
方法。密钥显然位于Microsoft.CodeAnalysis.Operations
命名空间中。
private bool IsFieldRead(SyntaxNodeAnalysisContext context, IFieldSymbol fieldSymbol)
var classDeclarationSyntax = context.Node.Parent;
while (!(classDeclarationSyntax is ClassDeclarationSyntax))
classDeclarationSyntax = classDeclarationSyntax.Parent;
if (classDeclarationSyntax == null)
throw new InvalidOperationException("You have somehow traversed up and out of the syntax tree when determining if a private member field is being read.");
//get all methods in the class
var methodsInClass = classDeclarationSyntax.DescendantNodes().OfType<MethodDeclarationSyntax>().ToImmutableArray();
foreach (var method in methodsInClass)
//get all member references in those methods
if (context.SemanticModel.GetOperation(method).Descendants().OfType<IMemberReferenceOperation>().ToImmutableArray().Any(x => x.Member.Equals(fieldSymbol)))
return true;
return false;
请注意,这仅涵盖方法内的用法。还有其他几个地方也需要检查,例如其他字段、属性和构造函数。
【讨论】:
以上是关于确定是不是使用 Roslyn 读取私有字段的主要内容,如果未能解决你的问题,请参考以下文章
如何确定是不是有数据可从 boost::asio 中的套接字读取?