2017-04-18 66 views
0

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

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

是的。你为每个节点调用GetSymbolInfo,但我怀疑你需要这个。例如,当你有一个使用声明,比如'using System.Collections.Generic;',你真的需要System和System.Collections命名空间的符号吗?所以开始考虑你需要什么符号。 –

回答

0

我看到你的代码的几个问题。

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

第二个问题更为重要:您经常使用相同的符号。

采取例如以下语句:

SomeMethod(); 

这是一个ExpressionStatement节点,withing它有一个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; 
     } 
    } 
} 

它不会得到所有符号虽然。例如,运营商的符号不会被发现。

这使我想到了第三点:你真的应该考虑你以后的哪些符号。你真的需要所有符号?

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

例如:

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。还有更多的你可以安全地过滤出来,但是我把它作为你的锻炼。