Splitting expressions with Roslyn
I am using Roslyn and I want to split the statement like 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 asked a question and got an answer to Split Expressions Split Expressions with Roslyn , but this sentence splits string.Concat("string1", "string2")
as below,
-
string.Concat()
-
string1
-
string2
But I don't want to break up the inner expressions, I need to keep the inner expressions as they are. How can I do this with Roslin?
source to share
The expression Console.Write(stringVariable + string.Concat("string1","string2") + intVariable.ToString())
is equal InvocationExpressionSyntax
. InvocationExpressionSyntax can be divided into expression and arguments .
Here, part of the expression will have Console.Write
and part of the argument will have a value stringVariable + string.Concat("string1","string2") + intVariable.ToString()
.
Now the argument will be BinaryExpressionSyntax
.
We can share BinaryExpressionSyntax by visiting SyntaxNodes
. Therefore, when you visit, we can just avoid passing "internal expression" by defining the syntax (eg InvocationExpressionSyntax
, MemberAccessExpressionSyntax
etc.).
The code to visit the binary expression as above would 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 called,
BinaryExpressionVisitor expressionVisitor = new BinaryExpressionVisitor();
expressionVisitor.VisitBinaryExpression(binaryExpressions);
List<object> nodeList = expressionVisitor.binaryExpressionNodes;
nodeList will have the following result.
- [0] = "IdentifierNameSyntax IdentifierName stringVariable"
- [1] = "SyntaxToken PlusToken +"
- [2] = "InvocationExpressionSyntax InvocationExpression string.Concat (\" string1 \ ", \" string2 \ ")"
- [3] = "SyntaxToken PlusToken +"
- [4] = "InvocationExpressionSyntax InvocationExpression intVariable.ToString ()"
source to share