如何使用Roslyn传递收集所有MethodDeclarationSyntax?

xoo*_*ofx 7 c# roslyn

给出一个列表,MethodDeclarationSyntax我想收集解决方案中的所有方法,这些方法可以传递地调用此方法.

我一直在使用以下代码:

        var methods = new Stack<MethodDeclarationSyntax>();
        ... // fill methods with original method to start from
        var visited = new HashSet<MethodDeclarationSyntax>();
        while (methods.Count > 0)
        {
            var method = methods.Pop();
            if (!visited.Add(method))
            {
                continue;
            }

            var methodSymbol = (await solution.GetDocument(method.SyntaxTree).GetSemanticModelAsync()).GetDeclaredSymbol(method);
            foreach (var referencer in await SymbolFinder.FindCallersAsync(methodSymbol, solution))
            {
                var callingMethod = (MethodDeclarationSyntax) referencer.CallingSymbol.DeclaringSyntaxReferences[0].GetSyntax();
                methods.Push(callingMethod);
            }
        }
Run Code Online (Sandbox Code Playgroud)

问题是MethodDeclarationSyntax看起来不是单身,所以这个循环永远在运行,一次又一次地访问相同的方法.

MethodDeclarationSyntax在Dictionary/Hashset中唯一标识a的正确方法是什么?

编辑1)

作为一种解决方法,我使用以下内容MethodDeclarationSyntaxComparer初始化我的HashSet,但它看起来非常脆弱:

    private class MethodDeclarationSyntaxComparer: IEqualityComparer<MethodDeclarationSyntax>
    {
        public bool Equals(MethodDeclarationSyntax x, MethodDeclarationSyntax y)
        {
            var xloc = x.GetLocation();
            var yloc = y.GetLocation();
            return xloc.SourceTree.FilePath == yloc.SourceTree.FilePath &&
                   xloc.SourceSpan == yloc.SourceSpan;
        }

        public int GetHashCode(MethodDeclarationSyntax obj)
        {
            var loc = obj.GetLocation();
            return (loc.SourceTree.FilePath.GetHashCode() * 307) ^ loc.SourceSpan.GetHashCode();
        }
    }
Run Code Online (Sandbox Code Playgroud)

Mar*_*anu 4

我想知道使用SyntaxNode这里是否是正确的方法。

既然您已经在使用SymbolFinder并且正在使用语义模型,也许正确的方法是实际使用ISymbols,而不是SyntaxNodes。

ISymbol已经包含SyntaxReference您正在使用的 s,因此:

   var methods = new Stack<IMethodSymbol>();
    ... // fill methods with original method to start from
    ... // convert methods to symbols via semanticModel.GetDeclaredSymbol (node);
    var visited = new HashSet<IMethodSymbol>();
    while (methods.Count > 0)
    {
        var method = methods.Pop();
        if (!visited.Add(method))
        {
            continue;
        }

        foreach (var referencer in await SymbolFinder.FindCallersAsync(method, solution))
        {
            var callingMethod = (MethodDeclarationSyntax) referencer.CallingSymbol.DeclaringSyntaxReferences[0].GetSyntax();
            methods.Push(callingMethod);
        }
    }
Run Code Online (Sandbox Code Playgroud)

您可以将访问的哈希集放入Dictionary<IMethodSymbol, IEnumerable<Location>>,并连接所有位置,从而根据该结果重建语法。