我看到你的代码的几个问题。
第一个是一个细节,但你说你正在寻找你“使用”的符号。您是否认为宣称符号是一种使用的符号?如果没有,你可以摆脱model.GetDeclaredSymbol(node)
。
第二个问题更为重要:您经常使用相同的符号。
采取例如以下语句:
SomeMethod();
这是一个ExpressionStatement
节点,withing它有一个InvocationExpression
,并在那里有一个IdentifierName
。您在这三个节点上都打电话model.GetSymbolInfo(node)
。你应该寻找一种方法来避免这种情况。
如果您只在类型SimpleNameSyntax
(或其后代IdentifierNameSyntax
和GenericNameSyntax
)的节点上调用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;
}
}
}
在该套色我滤出只从上面的例子中的ExpressionStatement
和InvocationExpression
。还有更多的你可以安全地过滤出来,但是我把它作为你的锻炼。
是的。你为每个节点调用GetSymbolInfo,但我怀疑你需要这个。例如,当你有一个使用声明,比如'using System.Collections.Generic;',你真的需要System和System.Collections命名空间的符号吗?所以开始考虑你需要什么符号。 –