C#-Visual Studio-查找只有一个引用的所有接口方法



我正在寻找一种方法来找到每个只有一个引用的接口方法

换句话说:已实现但从未调用的方法。

我的目标是清理死代码。

谢谢,

您可以使用Roslyn编写一个命令行工具来轻松完成这项工作。将项目加载到MSBuildWorkspace中,浏览语义树以获取所有方法,然后使用SymbolFinder.FindReferencesAsync查找对每个方法的所有引用,并为每个没有引用的方法打印警告。

您也可以将其写成Roslyn Analyzer。但是,在此上下文中不能使用SymbolFinder(您没有可用的工作区,而且它对分析器来说太慢了(。但是,您可以使用RegisterOperationAction来查找调用或引用方法的位置,同时使用RegisterSymbolAction来查找所有方法,然后将其放在一起以查找所有未引用的方法。

像这样的事情可能是一个起点。它关心一个方法是在接口上定义的还是从接口实现的(一旦你澄清了这里的规则,添加起来会很容易(,而且它只是经过了表面测试,但它似乎是有效的。

(您需要使用Analyzer模板创建一个新项目:如果您以前从未编写过分析器,请参阅教程(。

[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class UnusedMethodAnalyzer : DiagnosticAnalyzer
{
public const string DiagnosticId = "UNUSED";
private const string Category = "Unused Methods";
private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, "Method is not referenced", "Method '{0}' is not referenced", Category, DiagnosticSeverity.Warning, isEnabledByDefault: true);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterCompilationStartAction(Analyze);
}
private void Analyze(CompilationStartAnalysisContext context)
{
// Key: IMethodSymbol. Value: true if we've seen a reference to this method, false if we've just seen its definition
var methods = new ConcurrentDictionary<IMethodSymbol, bool>(SymbolEqualityComparer.Default);
context.RegisterOperationAction(ctx =>
{
methods.AddOrUpdate(((IInvocationOperation)ctx.Operation).TargetMethod, true, (_, _) => true);
}, OperationKind.Invocation);
context.RegisterOperationAction(ctx =>
{
methods.AddOrUpdate(((IMethodReferenceOperation)ctx.Operation).Method, true, (_, _) => true);
}, OperationKind.MethodReference);
context.RegisterSymbolAction(ctx =>
{
methods.TryAdd((IMethodSymbol)ctx.Symbol, false);
}, SymbolKind.Method);
context.RegisterCompilationEndAction(ctx =>
{
foreach (var kvp in methods)
{
if (!kvp.Value)
{
var methodSymbol = kvp.Key;
var diagnostic = Diagnostic.Create(Rule, methodSymbol.Locations[0], methodSymbol.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat));
ctx.ReportDiagnostic(diagnostic);
}
}
});
}
}

最新更新