Created
February 5, 2015 20:11
-
-
Save camilojd/64e834ca94fc18ffdbc3 to your computer and use it in GitHub Desktop.
SSA-like transformation of C# code AST using Roslyn
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.CodeAnalysis; | |
using Microsoft.CodeAnalysis.CSharp; | |
using Microsoft.CodeAnalysis.CSharp.Syntax; | |
using System; | |
using System.IO; | |
using System.Linq; | |
using System.Linq.Expressions; | |
namespace AppTransforms | |
{ | |
class App | |
{ | |
public static void Main(string[] args) | |
{ | |
string source = File.ReadAllText(@"..\..\Misc\ToyApp.cs"); | |
var compilation = SyntaxFactory.ParseCompilationUnit(source); | |
var instrumenter = new MyInvocRewriter(); | |
compilation = (CompilationUnitSyntax) instrumenter.Visit(compilation).NormalizeWhitespace(); | |
Console.WriteLine("===== sources below ====="); | |
Console.WriteLine(compilation); | |
Console.ReadLine(); | |
} | |
} | |
class MyInvocRewriter : CSharpSyntaxRewriter | |
{ | |
public override SyntaxNode VisitBlock(BlockSyntax node) | |
{ | |
BlockSyntax block = (BlockSyntax) base.VisitBlock(node); | |
SyntaxList<StatementSyntax> curList = new SyntaxList<StatementSyntax>(); | |
int numbering = 1; | |
foreach (var stmt in block.Statements) { | |
SyntaxList<StatementSyntax> preList = new SyntaxList<StatementSyntax>(); | |
var stm = stmt.ReplaceNodes(nodes: stmt.DescendantNodes().Reverse(), computeReplacementNode: (original, origWithReplaced) => | |
{ | |
if (origWithReplaced.IsKind(SyntaxKind.InvocationExpression) | |
|| origWithReplaced.IsKind(SyntaxKind.ObjectCreationExpression)) | |
{ | |
SeparatedSyntaxList<ArgumentSyntax> slst = new SeparatedSyntaxList<ArgumentSyntax>(); | |
SeparatedSyntaxList<ArgumentSyntax> exprArgs; | |
InvocationExpressionSyntax ies = null; | |
ObjectCreationExpressionSyntax oces = null; | |
// es necesario manejarlos por separado, porque pese a que ambos tienen como propiedad Arguments | |
// de tipo SeparatedSyntaxList<ArgumentSyntax>, no estan en la misma linea de jerarquia | |
// de clases... entonces: | |
if (origWithReplaced.IsKind(SyntaxKind.InvocationExpression)) { | |
ies = (InvocationExpressionSyntax) origWithReplaced; | |
exprArgs = ies.ArgumentList.Arguments; | |
} else { | |
oces = (ObjectCreationExpressionSyntax) origWithReplaced; | |
exprArgs = oces.ArgumentList.Arguments; | |
} | |
foreach (var arg in exprArgs) { | |
if (!(arg.Expression is LiteralExpressionSyntax || arg.Expression is IdentifierNameSyntax)) { | |
numbering++; | |
preList = preList.Add(SyntaxFactory.ParseStatement("var __a" + numbering + " = " + arg + ";")); | |
slst = slst.Add((SyntaxFactory.Argument(SyntaxFactory.ParseExpression("__a" + numbering)))); | |
} | |
else | |
slst = slst.Add(arg); | |
} | |
var argumentList = SyntaxFactory.ArgumentList(slst); | |
if (origWithReplaced.IsKind(SyntaxKind.InvocationExpression)) { | |
return ies.WithArgumentList(argumentList); | |
} else { | |
return oces.WithArgumentList(argumentList); | |
} | |
} | |
return origWithReplaced; | |
}); | |
curList = curList.AddRange(preList); | |
curList = curList.Add(stm); | |
} | |
return block.WithStatements(curList); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment