2017-09-18 10 views
1

파스 트리 변경 및 변경 사항을 다시 파일에 기록하는 작은 Roslyn 프로젝트에서 작업하고 있습니다. 필자는 독립형 코드 분석기로 시작하여 명령 줄 응용 프로그램으로 빌드하려고합니다. 그래도 난 어려움을 겪었습니다. 작업 : Find classes which derive from a specific base class with Roslyn 부분적으로, 주로로 : https://github.com/dotnet/roslyn/wiki/Getting-Started-C%23-Syntax-Analysis 내가이 작은 프로젝트를 만든 : 코드 상태에서 주석으로Roslyn에서 C# 클래스를 상속하지 않고 기본 객체에서 상속하는 것으로 변경 (java와 비슷한)

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

을, 나는 수업 뭔가에서 상속 여부 확인 (선택 필요 두 번째 옵션) 다음 구문 분석 트리를 변경하고 마지막으로 파일에 쓰기, 지금은 2 단계와 3 단계에 대한 모든 지침도 환영하지만 "상속을"확인하는 방법을 알고 기쁠 것입니다. 구문 분석 및 변경이 여기에 프로그램의 매개 변수로 경로가 제공하는 파일 : 나는 응용 프로그램을 작동 함께 왔어요 받았다 답변의 지원을

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


솔루션
합니다. 다음은 어쩌면 완벽한하지만

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

답변

0

ClassDeclarationSyntaxTypes을 포함 BaseList을 가지고 작동하지, 내 코드입니다.

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

불행하게도, 당신이 당신의 클래스는 기본 클래스가 있거나 그냥 인터페이스를 구현하는 것을 구분하기 위해 별도의 로직을 필요 기본 클래스는이 필드를 사용에 대한 그래서 당신은 정보를 검색 할 수 있습니다. 당신이이 문제를 해결하려면 당신은 분석 할 필요가 기본 오브젝트 (클래스/인터페이스)이 선언이 프로젝트에 정의되어있는 경우, ISymbol 대응에 대한 정보를 가져 오거나 syntax tree에서이 노드의 선언을 찾으려고 semantical model를 사용하여/솔루션.

당신이 BaseList로 설정해야합니다 클래스에 inheritation을 추가 할 경우에도 새로 생성 된 노드는 그냥 더 간단`null`에`BaseList` 비교하지 않는 것입니다 SyntaxFactory.SimpleBaseType(...)SyntaxFactory.BaseList(...)

+0

을 사용하고 계십니까? 실험 한 것에서도 효과가 있습니다. –

+0

@RobertGrzesiak 글쎄,'BaseList'와'null'의 비교가 안되면 예제를 모른다. 클래스가 기본 클래스를 가질 때'BaseList'가 null이 될 수 없다고 설명하는 문서를 찾지 못했다. 인터페이스를 구현합니다. 그래서 나는이 비교가 모든 경우에 효과가 있는지 없는지 확신하지 못합니다. –

+0

클래스가 상속하거나 구현하는 경우에만'BaseList'가 존재합니다. 그래서'BaseList! = null'은 내가 이해하는 것으로부터 잘 작동 할 것입니다. –