2017-09-18 2 views
1

Ich arbeite an einem kleinen Roslyn-Projekt, das das Ändern des Syntaxbaums und das Schreiben von Änderungen in die Datei enthält. Ich habe mit dem Standalone-Code-Analyzer begonnen und möchte es als Befehlszeilen-App erstellen. Ich bin jedoch auf eine Herausforderung gestoßen. Arbeiten mit: Find classes which derive from a specific base class with Roslyn teilweise, und vor allem mit: https://github.com/dotnet/roslyn/wiki/Getting-Started-C%23-Syntax-Analysis ich dieses kleine Projekt erstellt haben:Suche nach allen nicht vererbenden C# -Klassen mit Roslyn und Änderung der Vererbung vom Basisobjekt (javaähnlich)

class Program 
{ 
    static void Main(string[] args) 
    { 
     try 
     { 
      if (args.Length < 1) 
       throw new ArgumentException(); 
      SyntaxTree tree = CSharpSyntaxTree.ParseText(File.ReadAllText(args[0])); 
      var root = (CompilationUnitSyntax) tree.GetRoot(); 
      var classes = from ClassDeclarationSyntax in root.DescendantNodesAndSelf() select ClassDeclarationSyntax; 
      foreach (var c in classes) 
      { 
       if (/*Not inheriting*/) 
       { 
        /*Add inherition*/ 
       } 
      } 
      /*Write changes to file*/ 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Fatal error ocured."); 
      Console.WriteLine(e.Message); 
      Console.WriteLine(e.StackTrace); 
     } 
    } 
} 

Als Kommentare in Code Staaten, muss ich prüfen, ob Klasse von etwas erbt oder nicht (und wählen zweite Option) dann ändern Parse-Baum und zuletzt schreibe es in Datei, für jetzt wäre ich froh zu wissen, wie man "nicht Vererbung" nur überprüfen, obwohl alle Richtungen für Schritt zwei und drei sind auch willkommen. Datei zu analysieren und Änderung wird durch Pfad als Programmparameter hier geliefert:

if (args.Length < 1) 
    throw new ArgumentException(); 
SyntaxTree tree = CSharpSyntaxTree.ParseText(File.ReadAllText(args[0])); 


SOLUTION
Mit Unterstützung erhielt Antworten, die ich gekommen bin oben mit App arbeiten. Hier ist mein Code, vielleicht nicht perfekt, aber arbeiten

class Program 
{ 
    static void Main(string[] args) 
    { 
     try 
     { 
      if (args.Length < 1) 
       throw new ArgumentException(); 
      SyntaxTree tree = CSharpSyntaxTree.ParseText(File.ReadAllText(args[0])); 
      var root = (CompilationUnitSyntax) tree.GetRoot(); 
      IdentifierNameSyntax iname = SyntaxFactory.IdentifierName("Object"); 
      BaseTypeSyntax bts = SyntaxFactory.SimpleBaseType(iname); 
      SeparatedSyntaxList<BaseTypeSyntax> ssl = new SeparatedSyntaxList<BaseTypeSyntax>(); 
      ssl = ssl.Add(bts); 
      BaseListSyntax bls = SyntaxFactory.BaseList(ssl); 
      bool x = true; 
      while(x) //Way to handle all nodes due to impossibility to handle more than one in foreach 
      { 
       foreach (var c in root.DescendantNodesAndSelf()) 
       { 
        x = false; 
        var classDeclaration = c as ClassDeclarationSyntax; 
        if (classDeclaration == null) 
         continue; 
        if (classDeclaration.BaseList != null) //Inherits 
         continue; 
        else //Not inherits 
        { 
         root = root.ReplaceNode(classDeclaration, classDeclaration.WithBaseList(bls)); 
         x = true; 
         break; 
        } 
       } 
      } 
      if (args.Length > 1) //Write to given file 
       using (var sw = new StreamWriter(File.Open(args[1], FileMode.Open))) 
       { 
        root.WriteTo(sw); 
       } 
      else //Overwrite source 
       using (var sw = new StreamWriter(File.Open(args[0], FileMode.Open))) 
       { 
        root.WriteTo(sw); 
       } 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Fatal error ocured."); 
      Console.WriteLine(e.Message); 
      Console.WriteLine(e.StackTrace); 
     } 
    } 
} 

Antwort

0

ClassDeclarationSyntax hat BaseList die Types enthält. So können Sie Informationen abrufen über Basisklassen diese Felder verwenden:

 foreach (var c in correctRoot.DescendantNodesAndSelf()) 
     { 
      var classDeclaration = c as ClassDeclarationSyntax; 
      if (classDeclaration == null) 
      { 
       continue; 
      } 
      if (classDeclaration.BaseList?.Types.Count > 0) 
      { 
       Console.WriteLine("This class has base class or it implements interfaces"); 
      } 
      else 
      { 
       /*Add inherition*/ 
      } 
     } 

Leider müssen Sie zusätzliche Logik zu unterscheiden, dass Ihre Klasse Basisklasse hat oder es implementiert nur Schnittstellen. Wenn Sie dies lösen wollen, müssen Sie Basisobjekt (Klasse/Interface) mit semantical model analysieren Informationen erhalten über ISymbol entsprechende oder versuchen Erklärung dieser Knoten in der syntax tree zu finden, wenn diese Erklärung in Ihren Projekten definiert/Lösungen.

Auch wenn Sie Sie inheritation Klasse hinzufügen möchten festlegen müssen in BaseList ein neuer erstellt Knoten mit SyntaxFactory.SimpleBaseType(...) und SyntaxFactory.BaseList(...)

+0

Ist es nicht nur simplier 'BaseList' zu' null' zu vergleichen? Von dem, was ich experimentiert habe, funktioniert es auch. –

+0

@RobertGrzesiak Nun, ich weiß nicht, Beispiel, wenn der Vergleich zwischen 'BaseList' und' null' nicht funktionieren würde, aber ich habe keine Dokumentation gefunden, die erklärt, dass 'BaseList' nicht null sein kann, wenn Klasse Basisklasse oder hat implementiert Schnittstellen. Ich bin also nicht sicher, ob dieser Vergleich in allen Fällen funktionieren wird oder nicht. –

+0

Sie haben völlig Recht 'BaseList' existiert nur, wenn die Klasse etwas erbt oder implementiert. Also 'BaseList! = Null' sollte gut funktionieren von dem, was ich verstehe. –

Verwandte Themen