2015-05-08 16 views
5

Ich habe einige Probleme mit dem Hinzufügen eines Ausdrucks zum SyntaxTree mit Roslyn. Was ich erreichen muss, ist folgendes: Immer wenn ich eine spezielle Anweisung finde, möchte ich einen oder mehrere Ausdrücke nach diese Aussage einfügen.Einfügen neuer Ausdruck nach Anweisung über Roslyn

Sagen wir, ich möchte die Anweisung "myVar = myVar + 1" nach jeder Anweisung einfügen, die die Variable "testVar" schreibt.

So folgender Ausschnitt:

a = 10; 
testVar = 50; 
a = testVar/a; 
testVar = a; 

Sollte in dieses Stück Code umgewandelt werden:

a = 10; 
testVar = 50; 
myVar = myVar + 1; 
a = testVar/a; 
testVar = a; 
myVar = myVar + 1; 

Mein aktueller Ansatz nutzt den SyntaxVisitor mit der Methode 'SyntaxNode VisitExpressionStatement (ExpressionStatement Knoten)'. Diese Methode ruft alle Ausdrücke im SyntaxTree auf und ermöglicht es, den besuchten Ausdruck durch den zurückgegebenen SyntaxNode zu ersetzen. Allerdings möchte ich nicht ersetzen Anweisungen, aber fügen Sie neue Ausdrücke nach ihnen, die grundsätzlich erfordert zwei Ausdrücke zurückgegeben werden. Die einzige Lösung, die ich gefunden habe, ist die Verwendung von "BlockSyntax", die als Container für die beiden Ausdrücke dient (siehe Codeausschnitt [0]). Leider führt „BlockSyntax“ geschweifte Klammern um sich selbst, die zu folgendem Ergebnis führen:

a = 10; 
{ 
    testVar = 50; 
    myVar = myVar + 1; 
} 
a = testVar/a; 
{ 
    testVar = a; 
    myVar = myVar + 1; 
} 

Dieser Ansatz für mich nicht akzeptabel ist, wie ich will nicht über die Bereiche manipulieren. Gibt es eine Möglichkeit, beliebige Ausdrücke an einem Ort meiner Wahl mit Roslyn einzufügen?

[0]

public SyntaxNode VisitExpressionStatement(ExpressionStatement node){ 
    if(node has special characteristics){ 
     var newExpression = ... 

     var newStatmentList = new Roslyn.Compilers.CSharp.SyntaxList<StatementSyntax>(); 
     newStatmentList = newStatmentList.Insert(newStatmentList.Count, node); 
     newStatmentList = newStatmentList.Insert(newStatmentList.Count, newExpression); 

     BlockSyntax newBlock = Syntax.Block(newStatmentList); 
     return newBlock; 

    } 
    else { 
     return node; 
    } 
} 

Antwort

1

Meine Strategie mit BlockSyntax zu betrügen sind. Siehe meine similar question.

Also füge ich BlockSyntax hinzu, wie du es getan hast, aber dann "entferne" ich sie, indem ich die { und } Token als fehlend markiere. Ich habe noch keine Probleme mit diesem Ansatz, aber es scheint eher ein Workaround als eine Lösung.

var statements = new SyntaxList<StatementSyntax>(); 
//Tried bundling newNode and invocation together 
statements.Add(SyntaxFactory.ExpressionStatement(newNode)); 
statements.Add(SyntaxFactory.ExpressionStatement(invocation)); 
var wrapper = SyntaxFactory.Block(statements); 

//Now we can remove the { and } braces 
wrapper = wrapper.WithOpenBraceToken(SyntaxFactory.MissingToken(SyntaxKind.OpenBraceToken)) 
.WithCloseBraceToken(SyntaxFactory.MissingToken(SyntaxKind.CloseBraceToken)); 

Beachten Sie, dass ich sage, dass ich sie "entferne". Das Problem hier ist, dass die SyntaxTree, die Sie generieren, dem C# -Compiler immer noch so angezeigt wird, als hätte er an dem Punkt, an dem Sie ihn platziert haben, eine BlockSyntax. Dies kann oder kann nicht wichtig sein.

Zum Beispiel:

  • Wenn Sie diesen Baum als Zeichenkette in einer Datei sind ausgibt, werden Sie in Ordnung sein.

  • Wenn Sie sofort diesen Baum kompilieren, glaube ich, wird der Compiler die BlockSyntax als bestehende interpretieren, wo Sie es und alle Scoping Semantik noch erzwungen werden neu geschrieben haben, als ob es da war.

Weitere auf die Generierung von "weird" Bäume in meinem Blogbeitrag check out: Don't Trust SyntaxNode.ToFullString()