2017-09-18 3 views
1

Je travaille sur un petit projet Roslyn qui inclut le changement de l'arbre d'analyse et l'écriture des modifications dans le fichier. J'ai commencé avec l'analyseur de code autonome et je veux le construire comme une application de ligne de commande. J'ai rencontré un défi, cependant. Travailler avec: Find classes which derive from a specific base class with Roslyn partiellement, et la plupart du temps avec: https://github.com/dotnet/roslyn/wiki/Getting-Started-C%23-Syntax-Analysis J'ai créé ce petit projet:Je trouve tout ce qui ne hérite pas des classes C# avec Roslyn et je hérite de l'objet de base (java-like)

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); 
     } 
    } 
} 

Comme commentaires dans les états de code, je dois vérifier si la classe hérite de quelque chose ou non (et choisissez deuxième option) puis modifiez l'arbre d'analyse et enfin l'écrire dans le fichier, pour l'instant je serais heureux de savoir comment vérifier "non l'héritage", bien que toutes les directions pour les étapes deux et trois soient les bienvenues aussi. Fichier pour analyser et le changement est fourni par le chemin en tant que paramètre de programme ici:

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


SOLUTION
Avec le soutien de réponses recus Je suis venu avec l'application de travail. Voici mon code, peut-être pas parfait, mais travailler

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); 
     } 
    } 
} 

Répondre

0

ClassDeclarationSyntax a BaseList qui contient Types. Ainsi, vous pouvez récupérer des informations sur les classes de base utilisent ces champs:

 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*/ 
      } 
     } 

Malheureusement, vous avez besoin d'une logique supplémentaire pour distinguer que votre classe a la classe de base ou il implémente simplement des interfaces. Si vous voulez résoudre cela, vous devez analyser objet de base (classe/interface) en utilisant semantical model pour obtenir des informations sur correspondant ISymbol ou essayer de trouver la déclaration de ces noeuds dans le syntax tree, si cette déclaration est définie dans vos projets/solutions.

Aussi, si vous souhaitez ajouter à la classe inheritation vous devez définir en BaseList un nouveau nœud créé à l'aide SyntaxFactory.SimpleBaseType(...) et SyntaxFactory.BaseList(...)

+0

est-il pas juste de comparer 'simplier BaseList' à' null'? De ce que j'ai expérimenté cela fonctionne aussi. –

+0

@RobertGrzesiak Eh bien, je ne sais pas exemple quand la comparaison entre 'BaseList' et' null' ne fonctionnerait pas, mais je n'ai pas trouvé une documentation qui explique que BaseList ne peut pas être nul quand la classe a la classe de base ou implémente des interfaces. Donc, je ne suis pas sûr que cette comparaison sera un travail dans tous les cas ou non. –

+0

Vous avez totalement raison 'BaseList' n'existe que si la classe hérite ou implémente quelque chose. Donc 'BaseList! = Null' devrait fonctionner correctement d'après ce que je comprends. –