罗斯林-查找所有符号

TWT*_*TWT 2 c# roslyn roslyn-code-analysis

我正在使用以下代码来检索代码块中使用的所有符号。这包括声明和对符号的引用。不幸的是,GetSymbolInfo调用非常慢,因此,此方法花费的总时间可能很长。有没有办法加快速度?

    public static IEnumerable<ISymbol> GetAllSymbols(CSharpCompilation compilation, SyntaxNode root)
    {
        var noDuplicates = new HashSet<ISymbol>();

        var model = compilation.GetSemanticModel(root.SyntaxTree);

        foreach (var node in root.DescendantNodesAndSelf())
        {
            ISymbol symbol = model.GetDeclaredSymbol(node) ??
                model.GetSymbolInfo(node).Symbol;

            if (symbol != null)
            {
                if (noDuplicates.Add(symbol))
                    yield return symbol; 
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

Kri*_*ten 5

我发现您的代码有几个问题。

第一个是一个细节,但是您说您正在寻找“使用”的符号。您是否认为将符号声明使用符号的一种?如果没有,您可以摆脱model.GetDeclaredSymbol(node)

第二个问题更为重要:您过于频繁地获得相同的符号。

以下面的语句为例:

SomeMethod();
Run Code Online (Sandbox Code Playgroud)

那是一个ExpressionStatement节点,有一个节点,InvocationExpression并且有一个IdentifierName。您正在调用model.GetSymbolInfo(node)所有这三个节点。您应该寻找一种避免这种情况的方法。

如果仅调用model.GetSymbolInfo(node)类型的节点SimpleNameSyntax(或其后代IdentifierNameSyntaxGenericNameSyntax),则会得到很多符号。

就像是:

public static IEnumerable<ISymbol> GetAllSymbols(CSharpCompilation compilation, SyntaxNode root)
{
    var noDuplicates = new HashSet<ISymbol>();

    var model = compilation.GetSemanticModel(root.SyntaxTree);

    foreach (var node in root.DescendantNodesAndSelf())
    {
        switch (node.Kind())
        {
            case SyntaxKind.IdentifierName:
            case SyntaxKind.GenericName:
                ISymbol symbol = model.GetSymbolInfo(node).Symbol;

                if (symbol != null && noDuplicates.Add(symbol))
                {
                    yield return symbol;
                }
                break;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它不会获得所有符号。例如,找不到用于运算符的符号。

这就是我要讲的第三点:您确实应该考虑要使用的符号。您真的需要所有符号吗?

即使答案是“是”,您也可以通过扭转上述逻辑来避免许多冗余查找。

例如:

public static IEnumerable<ISymbol> GetAllSymbols(CSharpCompilation compilation, SyntaxNode root)
{
    var noDuplicates = new HashSet<ISymbol>();

    var model = compilation.GetSemanticModel(root.SyntaxTree);

    foreach (var node in root.DescendantNodesAndSelf())
    {
        switch (node.Kind())
        {
            case SyntaxKind.ExpressionStatement:
            case SyntaxKind.InvocationExpression:
                break;
            default:
                ISymbol symbol = model.GetSymbolInfo(node).Symbol;

                if (symbol != null)
                {
                    if (noDuplicates.Add(symbol))
                        yield return symbol;
                }
                break;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我仅从上面的示例中过滤了ExpressionStatementInvocationExpression。您可以安全地过滤掉更多的内容,但是我将其留给您练习。