I am using Roslyn and I want to split the statement as below,
string stringVariable = "string";
int intVariable = 10;
Console.Write(stringVariable + string.Concat("string1","string2") + intVariable.ToString())
Console.Write()
stringVariable
string.Concat("string1","string2")
intVariable.ToString()
I have asked a question and got answer for splitting the expressions Splitting the Expression statements with Roslyn but this suggestion splits the string.Concat("string1", "string2")
as below,
string.Concat()
string1
string2
But i dont want to split the inner expressions, I need to keep the inner expressions as it is. How can I do this with Roslyn?
The expression Console.Write(stringVariable + string.Concat("string1","string2") + intVariable.ToString())
is a InvocationExpressionSyntax
. The InvocationExpressionSyntax can be further splitted into expression and arguments.
Here the expression part will have Console.Write
and
the argument part will have stringVariable + string.Concat("string1","string2") + intVariable.ToString()
.
Now the argument will be the BinaryExpressionSyntax
.
We can split the BinaryExpressionSyntax by visiting the SyntaxNodes
. So when Visiting we can just avoid traversing the "inner expressions" by identifyning its
syntax( like InvocationExpressionSyntax
, MemberAccessExpressionSyntax
..etc) .
The code for visiting the Binary expression as above will be.
public class BinaryExpressionVisitor : CSharpSyntaxRewriter
{
List<string> restrictedTokens = new List<string>();
internal List<object> binaryExpressionNodes = new List<object>();
public BinaryExpressionVisitor()
{
restrictedTokens.Add("IdentifierToken");
restrictedTokens.Add("NumericLiteralToken");
restrictedTokens.Add("StringLiteralToken");
}
public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node)
{
return base.VisitBinaryExpression(node);
}
public override SyntaxNode Visit(SyntaxNode node)
{
if (node.GetType().Name != "BinaryExpressionSyntax" && node.GetType().Name != "ParenthesizedExpressionSyntax")
binaryExpressionNodes.Add(node);
return base.Visit(node);
}
public override SyntaxToken VisitToken(SyntaxToken token)
{
if (!restrictedTokens.Contains(token.CSharpKind().ToString().Trim()))
binaryExpressionNodes.Add(token);
SyntaxToken baseToken = base.VisitToken(token);
return baseToken;
}
public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax node)
{
return node;//Bypassing the expression instead of base.Visit(node)
}
public override SyntaxToken VisitListSeparator(SyntaxToken separator)
{
SyntaxToken baseToken = base.VisitListSeparator(separator);
return baseToken;
}
}
The class can be invoked by,
BinaryExpressionVisitor expressionVisitor = new BinaryExpressionVisitor();
expressionVisitor.VisitBinaryExpression(binaryExpressions);
List<object> nodeList = expressionVisitor.binaryExpressionNodes;
The nodeList will have the below result.
- [0] = "IdentifierNameSyntax IdentifierName stringVariable"
- [1] = "SyntaxToken PlusToken +"
- [2] = "InvocationExpressionSyntax InvocationExpression
string.Concat(\"string1\", \"string2\")"
- [3] = "SyntaxToken PlusToken +"
- [4] = "InvocationExpressionSyntax InvocationExpression
intVariable.ToString()"