Ich sehe mehrere Probleme mit Ihrem Code.
Die erste ist ein bisschen ein Detail, aber Sie sagen, dass Sie nach Symbolen suchen, die Sie "verwenden". Denkst du deklarieren ein Symbol eine Art mit ein Symbol? Wenn nicht, können Sie model.GetDeclaredSymbol(node)
loswerden.
Die zweite Frage ist viel wichtiger: Sie erhalten die gleichen Symbole zu oft.
Nehmen Sie zum Beispiel die folgende Anweisung:
SomeMethod();
Das ist ein ExpressionStatement
Knoten, es gibt withing ist ein InvocationExpression
und dort in gibt es eine IdentifierName
. Sie rufen model.GetSymbolInfo(node)
auf allen drei dieser Knoten auf. Sie sollten nach einem Weg suchen, dies zu vermeiden.
Sie würden eine Menge Symbole, wenn man nur model.GetSymbolInfo(node)
auf Knoten vom Typ SimpleNameSyntax
(oder dessen Abkömmlinge, IdentifierNameSyntax
und GenericNameSyntax
) genannt.
Etwas wie: obwohl
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;
}
}
}
Es würde sich nicht alle Symbole. Zum Beispiel würden Symbole für Operatoren nicht gefunden.
Und das bringt mich zu meinem dritten Punkt: Sie sollten wirklich überlegen, welche Symbole Sie suchen. Benötigen Sie wirklich alle Symbole?
Auch wenn die Antwort darauf "Ja" ist, könnten Sie viele Fälle redundanter Suchvorgänge vermeiden, indem Sie die obige Logik umdrehen.
Zum Beispiel:
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;
}
}
}
In diesem verrohrten gefiltert ich die ExpressionStatement
nur aus und InvocationExpression
aus dem obigen Beispiel. Es gibt viele mehr, die Sie sicher herausfiltern können, aber ich überlasse das als Übung für Sie.
Ja. Sie rufen GetSymbolInfo für jeden Knoten auf, aber ich bezweifle, dass Sie das brauchen. Wenn Sie beispielsweise eine using-Deklaration verwenden, zum Beispiel 'using System.Collections.Generic;', benötigen Sie wirklich das Symbol für die Namespaces System und System.Collections? Überlege dir also, welche Symbole du brauchst. –