2017-04-18 2 views
0

Ich verwende den folgenden Code, um alle Symbole, die in einem Codeblock verwendet werden, abzurufen. Dies schließt Deklarationen und Verweise auf Symbole ein. Leider ist der GetSymbolInfo-Aufruf ziemlich langsam und daher kann die Gesamtzeit, die diese Methode benötigt, lang sein. Gibt es eine Möglichkeit, dies zu beschleunigen?Roslyn - Finden Sie alle Symbole

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

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. –

Antwort

0

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.

Verwandte Themen