如何在诊断中不依赖SymbolFinder判断Dispose方法是否访问可释放字段
判断Dispose方法是否访问可释放字段(不依赖Solution/SymbolFinder)
核心思路
不用SymbolFinder的话,我们完全可以借助Roslyn的语义分析能力,仅用SyntaxNodeAnalysisContext提供的SemanticModel和Compilation完成需求。核心步骤是:先定位字段所属类型的IDisposable.Dispose方法,再分析该方法的语法节点,检查其中是否包含对目标字段的引用。
实现代码
下面是修改后的IsMentionedInDisposeCallAsync方法,全程不依赖外部Solution:
private async Task<bool> IsMentionedInDisposeCallAsync(SyntaxNodeAnalysisContext context, FieldDeclarationSyntax fieldDeclarationSyntax) { foreach (var variableDeclaratorSyntax in fieldDeclarationSyntax.Declaration.Variables) { var declaredSymbol = context.SemanticModel.GetDeclaredSymbol(variableDeclaratorSyntax); if (declaredSymbol is not IFieldSymbol fieldSymbol) continue; // 获取字段所属的类型符号 if (fieldSymbol.ContainingType is not INamedTypeSymbol containingType) continue; // 筛选出该类型实现的IDisposable.Dispose方法 var disposeMethod = containingType.GetMembers("Dispose") .OfType<IMethodSymbol>() .FirstOrDefault(m => m.ReturnType.SpecialType == SpecialType.System_Void && m.Parameters.Length == 0 && m.ContainingType.AllInterfaces.Any(i => i.Name == "IDisposable" && i.ContainingNamespace.Name == "System")); if (disposeMethod == null) continue; // 获取Dispose方法的语法节点 var disposeSyntax = await disposeMethod.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntaxAsync(context.CancellationToken); if (disposeSyntax is not MethodDeclarationSyntax disposeMethodSyntax) continue; // 遍历Dispose方法内所有节点,查找对目标字段的引用 var hasFieldReference = disposeMethodSyntax.DescendantNodes() .OfType<IdentifierNameSyntax>() .Select(id => context.SemanticModel.GetSymbolInfo(id).Symbol) .Any(symbol => symbol?.Equals(fieldSymbol) == true); if (hasFieldReference) return true; } return false; }
测试场景验证
你的测试代码可以直接用来验证这个逻辑:
private static readonly string TestSourceImplementsDisposableAndDoesMentionDisposableField = @" using System; using System.IO; namespace ConsoleApplication1 { public class SampleDisposable : IDisposable { public void Dispose() { } } public class SampleConsumer : IDisposable { private SampleDisposable _disposable = new SampleDisposable(); private IDisposable _ms = new MemoryStream(); public void Dispose() { _disposable?.Dispose(); _ms?.Dispose(); } } }";
对于_disposable和_ms这两个可释放字段,上述方法会正确识别到它们在Dispose方法中被访问,返回true。
关键细节说明
- 精准定位Dispose方法:通过筛选无参数、返回
void,且所属类型实现System.IDisposable的方法,确保我们找到的是符合规范的Dispose方法。 - 语法与语义联动:先通过符号获取方法的语法节点,再遍历节点中的标识符,最后用语义模型验证标识符是否指向目标字段,避免语法层面的误判。
- 异步兼容:代码中使用
await处理语法节点的异步获取,同时传递CancellationToken保证可取消性。
内容的提问来源于stack exchange,提问作者Dbl
相关产品推荐
相关产品推荐

