2013-11-22 5 views
6

Roslynを探索しながら、私はVisual Studio Solutionにあるすべてのメソッドの最初のステートメントとしてtraceステートメントを含めるべき小さなアプリケーションをまとめました。私のコードはバグで、最初のメソッドを更新するだけです。Roslynを使用したメソッドノードの置換

期待どおりに機能していない行には、「TODO」というコメントが付けられています。お知らせ下さい。

また、より合理的な/読解可能なソリューションを作成するスタイルの推奨事項を歓迎します。

ありがとうございます。

...

private void TraceBtn_Click(object sender, RoutedEventArgs e) { 
     var myWorkSpace = new MyWorkspace("...Visual Studio 2012\Projects\Tests.sln"); 
     myWorkSpace.InjectTrace(); 
     myWorkSpace.ApplyChanges(); 
    } 

...

using System; 
using System.Linq; 
using Roslyn.Compilers; 
using Roslyn.Compilers.CSharp; 
using Roslyn.Services; 

namespace InjectTrace 
{ 
    public class MyWorkspace 
    { 
    private string solutionFile; 
    public string SolutionFile { 
     get { return solutionFile; } 
     set { 
      if (string.IsNullOrEmpty(value)) throw new Exception("Invalid Solution File"); 
      solutionFile = value; 
     } 
    } 

    private IWorkspace loadedWorkSpace; 
    public IWorkspace LoadedWorkSpace { get { return loadedWorkSpace; } } 

    public ISolution CurrentSolution { get; private set; } 
    public IProject CurrentProject { get; private set; } 
    public IDocument CurrentDocument { get; private set; } 
    public ISolution NewSolution { get; private set; } 


    public MyWorkspace(string solutionFile) { 
     this.SolutionFile = solutionFile; 
     this.loadedWorkSpace = Workspace.LoadSolution(SolutionFile); 
    } 

    public void InjectTrace() 
    { 

     int projectCtr = 0; 
     int documentsCtr = 0; 
     int transformedMembers = 0; 
     int transformedClasses = 0; 
     this.CurrentSolution = this.LoadedWorkSpace.CurrentSolution; 
     this.NewSolution = this.CurrentSolution; 

     //For Each Project... 
     foreach (var projectId in LoadedWorkSpace.CurrentSolution.ProjectIds) 
     { 
      CurrentProject = NewSolution.GetProject(projectId); 

      //..for each Document in the Project.. 
      foreach (var docId in CurrentProject.DocumentIds) 
      { 
       CurrentDocument = NewSolution.GetDocument(docId); 
       var docRoot = CurrentDocument.GetSyntaxRoot(); 
       var newDocRoot = docRoot; 
       var classes = docRoot.DescendantNodes().OfType<ClassDeclarationSyntax>(); 
       IDocument newDocument = null; 

       //..for each Class in the Document.. 
       foreach (var @class in classes) { 
        var methods = @class.Members.OfType<MethodDeclarationSyntax>(); 

        //..for each Member in the Class.. 
        foreach (var currMethod in methods) { 
         //..insert a Trace Statement 
         var newMethod = InsertTrace(currMethod); 
         transformedMembers++; 
         //TODO: PROBLEM IS HERE 
         newDocRoot = newDocRoot.ReplaceNode(currMethod, newMethod);        
        } 
        if (transformedMembers != 0) { 
         newDocument = CurrentDocument.UpdateSyntaxRoot(newDocRoot); 
         transformedMembers = 0; 
         transformedClasses++; 
        } 
       } 

       if (transformedClasses != 0) { 
        NewSolution = NewSolution.UpdateDocument(newDocument); 
        transformedClasses = 0; 
       } 

       documentsCtr++; 

      } 
      projectCtr++; 
      if (projectCtr > 2) return; 
     } 
    } 

    public MethodDeclarationSyntax InsertTrace(MethodDeclarationSyntax currMethod) { 
     var traceText = 
     @"System.Diagnostics.Trace.WriteLine(""Tracing: '" + currMethod.Ancestors().OfType<NamespaceDeclarationSyntax>().Single().Name + "." + currMethod.Identifier.ValueText + "'\");"; 
     var traceStatement = Syntax.ParseStatement(traceText); 
     var bodyStatementsWithTrace = currMethod.Body.Statements.Insert(0, traceStatement); 
     var newBody = currMethod.Body.Update(Syntax.Token(SyntaxKind.OpenBraceToken), bodyStatementsWithTrace, 
              Syntax.Token(SyntaxKind.CloseBraceToken)); 
     var newMethod = currMethod.ReplaceNode(currMethod.Body, newBody); 
     return newMethod; 

    } 

    public void ApplyChanges() { 
     LoadedWorkSpace.ApplyChanges(CurrentSolution, NewSolution); 
    } 


} 

}

答えて

6

あなたのコードの根本的な問題はnewDocRoot = newDocRoot.ReplaceNode(currMethod, newMethod);は何とか勝ったコードのnewDocRoot内部表現ので、次のcurrMethod要素を再構築することですそれが見つかると、次にReplaceNodeコールは何もしません。 foreachループ内のコレクションを変更するのと同様の状況です。

解決策は、すべての必要な変更を収集し、ReplaceNodesメソッドで一度に適用することです。そして、実際には、これらのカウンターをすべてトレースする必要がないため、コードの簡素化につながります。必要なすべての変換を保存して、ドキュメント全体に対して一度に適用します。変更後の

の作業コード:

public void InjectTrace() 
{ 
    this.CurrentSolution = this.LoadedWorkSpace.CurrentSolution; 
    this.NewSolution = this.CurrentSolution; 

    //For Each Project... 
    foreach (var projectId in LoadedWorkSpace.CurrentSolution.ProjectIds) 
    { 
     CurrentProject = NewSolution.GetProject(projectId); 
     //..for each Document in the Project.. 
     foreach (var docId in CurrentProject.DocumentIds) 
     { 
      var dict = new Dictionary<CommonSyntaxNode, CommonSyntaxNode>(); 
      CurrentDocument = NewSolution.GetDocument(docId); 
      var docRoot = CurrentDocument.GetSyntaxRoot(); 
      var classes = docRoot.DescendantNodes().OfType<ClassDeclarationSyntax>(); 

      //..for each Class in the Document.. 
      foreach (var @class in classes) 
      { 
       var methods = @class.Members.OfType<MethodDeclarationSyntax>(); 

       //..for each Member in the Class.. 
       foreach (var currMethod in methods) 
       { 
        //..insert a Trace Statement 
        dict.Add(currMethod, InsertTrace(currMethod)); 
       } 
      } 

      if (dict.Any()) 
      { 
       var newDocRoot = docRoot.ReplaceNodes(dict.Keys, (n1, n2) => dict[n1]); 
       var newDocument = CurrentDocument.UpdateSyntaxRoot(newDocRoot); 
       NewSolution = NewSolution.UpdateDocument(newDocument); 
      } 
     } 
    } 
} 
関連する問題