【问题标题】:Roslyn - Find all symbolsRoslyn - 查找所有符号
【发布时间】:2017-04-18 10:25:16
【问题描述】:

我正在使用以下代码来检索代码块中使用的所有符号。这包括声明和对符号的引用。 不幸的是,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; 
            }
        }
    }

【问题讨论】:

  • 是的。您正在为每个节点调用 GetSymbolInfo,但我怀疑您是否需要它。例如,当您有 using System.Collections.Generic; 之类的 using 声明时,您真的需要 System 和 System.Collections 命名空间的符号吗?所以开始考虑你需要什么符号。

标签: c# roslyn roslyn-code-analysis


【解决方案1】:

我发现您的代码存在一些问题。

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

第二个问题更重要:你经常得到相同的符号。

以下面的语句为例:

SomeMethod();

这是一个ExpressionStatement 节点,其中有一个InvocationExpression,其中有一个IdentifierName。您正在这三个节点上调用model.GetSymbolInfo(node)。你应该想办法避免这种情况。

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

类似:

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;
        }
    }
}

它不会得到 all 符号。例如,将找不到运算符的符号。

这让我想到了第三点:你真的应该考虑你所追求的符号。你真的需要所有个符号吗?

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

例如:

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;
        }
    }
}

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

【讨论】:

  • 谢谢,这很有帮助。我有类似的查询所有符号的需求,但我只需要查询所有“外部”符号(即当前编译单元使用但未在当前单元中定义的符号,例如框架类,或来自 3rd 方程序集的类/命名空间),您能否简要说明我应该如何实现这一目标?
  • @WeipengL 使用类似!symbol.ContainingAssembly.Equals(context.Compilation.Assembly)的东西
  • 再次感谢克里斯
猜你喜欢
  • 2015-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-14
相关资源
最近更新 更多