Skip to content

Instantly share code, notes, and snippets.

@camilojd
Created February 5, 2015 20:11
Show Gist options
  • Save camilojd/64e834ca94fc18ffdbc3 to your computer and use it in GitHub Desktop.
Save camilojd/64e834ca94fc18ffdbc3 to your computer and use it in GitHub Desktop.
SSA-like transformation of C# code AST using Roslyn
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