我已经搜索了一整天并阅读了很多帖子,但我无法对此得出结论。我正在尝试创建一个 Roslyn 分析器,以便在私有(private)字段未读时报告诊断。注册语法操作并确定其私有(private)是否真的很容易。但现在我一直在尝试找出该字段是否在类中被读取。
假设我们有以下示例代码:
public class C {
private int foo; //private field is declared but never read. Should report diagnostic here
public void DoNothing() {
//irrelevant
}
}
有几个例子说明我希望在哪里标记此标记(是否初始化、是否注入(inject)、单行上的多个声明等),但我认为也许它们对于说明问题不是必需的。
到目前为止我所拥有的是:
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()
方法发挥作用。这确实感觉像是一件应该很容易做到的事情,但我就是无法完全理解它。我认为获取方法并分析我的领域的方法,看看它是否被读取将是一个不错的主意,但这并不包括该领域是否被另一个私有(private)领域读取,而且我无论如何也无法让它工作。 :)
最佳答案
感谢this other SO answer,我成功地解决了这个问题。由真正在微软从事 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;
}
请注意,这仅涵盖方法内的用法。还有其他几个地方,例如其他字段、属性和构造函数,也需要检查。
关于c# - 确定是否使用 Roslyn 读取私有(private)字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69636558/