Splitting expressions with Roslyn
I am working on developing an application that rephrases code CSharp
. I do this with Roslyn
. I ran into a problem with splitting expressions
.
Example class
class Program
{
static void Main(string[] args)
{
float floatVariable = 20;
Int16 intVariable = 10;
string str = "School";
Console.Write(str + floatVariable.ToString() + intVariable.ToString()); // Facing problem with this statement
}
}
Sample code I am using
string code = new StreamReader(classPath).ReadToEnd();
var syntaxTree = CSharpSyntaxTree.ParseText(code);
var syntaxRoot = syntaxTree.GetRoot();
//This will get the method and local variables declared inside the method
var MyMethods = syntaxRoot.DescendantNodes().OfType<MethodDeclarationSyntax>();
foreach (MethodDeclarationSyntax mds in MyMethods)
{
syntaxTree = CSharpSyntaxTree.ParseText(mds.ToFullString());
IEnumerable<SyntaxNode> nodes = syntaxTree.GetRoot().DescendantNodes();
IEnumerable<VariableDeclarationSyntax> variableDeclarations = nodes.OfType<VariableDeclarationSyntax>();
foreach (VariableDeclarationSyntax variable in variableDeclarations)
{
// I will collect the variable details like Datatype, variable names and initialized values here
}
foreach (StatementSyntax statement in mds.Body.Statements)
{
if (statement.CSharpKind() == SyntaxKind.ExpressionStatement)
{
//I want to split the expressions "Console.Write(str + floatVariable.ToString() + intVariable.ToString());" as below
//1. intVariable.ToString()
//2. floatVariable.ToString()
//3. str
//Then I have to find the whole data type from the resolved result of above 3 => string here
}
}
}
Any help would be appreciated.
Edit: I'm having problems splitting parameterized expression statements. I'm trying to do this,
if (statement.CSharpKind() == SyntaxKind.ExpressionStatement)
{
ExpressionStatementSyntax expression = statement as ExpressionStatementSyntax;
var expressions = expression.Expression.DescendantNodes();
}
But this breaks each token as a separate item. I just want to split into Console.Write(str + floatVariable.ToString() + intVariable.ToString())
- Console.Write ()
- st
- intVariable.ToString ()
- floatVariable.ToString ()
source to share
It's hard to say what exactly you want to do, because you indicated that the code should only do one specific case, not in general.
The way I interpret it:
- For a call expression, return the expression that is being called, and also exit into its arguments, if any.
- For binary operators, omit in both children.
- For all other expressions, return the expression directly.
With this specification and usage, the CSharpSyntaxVisitor
code could look like this:
public static IEnumerable<ExpressionSyntax> Split(ExpressionSyntax expression)
{
return new SplitVisitor().Visit(expression);
}
class SplitVisitor : CSharpSyntaxVisitor<IEnumerable<ExpressionSyntax>>
{
public override IEnumerable<ExpressionSyntax> VisitInvocationExpression(
InvocationExpressionSyntax node)
{
yield return node.Expression;
var argumentExpressions = node.ArgumentList.Arguments
.SelectMany(a => Visit(a.Expression));
foreach (var expression in argumentExpressions)
yield return expression;
}
public override IEnumerable<ExpressionSyntax> VisitBinaryExpression(
BinaryExpressionSyntax node)
{
foreach (var expression in Visit(node.Left))
yield return expression;
foreach (var expression in Visit(node.Right))
yield return expression;
}
public override IEnumerable<ExpressionSyntax> DefaultVisit(SyntaxNode node)
{
var expression = node as ExpressionSyntax;
if (expression != null)
yield return expression;
}
}
source to share