I faced a difficult situation using SyntaxRewriter in Roslyn. I would like to rewrite certain types of statements, including local variable declarations. The solution requires me to convert the statements in question into several operators, as in the following trivial example:
void method() { int i; }
becomes
void method() { int i; Console.WriteLine("I declared a variable."); }
I saw other examples where blocks are used to do something similar, but, of course, in the case of a variable declaration, the scope of the declaration will be affected. I came up with the following solution, but I do not agree with this. This seems overly complex and requires a break in the visitor's template:
class Rewriter: SyntaxRewriter { public override SyntaxList<TNode> VisitList<TNode>(SyntaxList<TNode> list) { if (typeof(TNode) == typeof(StatementSyntax)) return Syntax.List<TNode>(list.SelectMany(st => RewriteStatementInList(st as StatementSyntax).Cast<TNode>())); else return base.VisitList<TNode>(list); } private IEnumerable<SyntaxNode> RewriteStatementInList(StatementSyntax node) { if (node is LocalDeclarationStatementSyntax) return PerformRewrite((LocalDeclarationStatementSyntax)node);
What am I missing? Editing statements and deleting them (via an empty operator) seems more straightforward than rewriting for brevity.
I answer the answer:
class Rewriter : SyntaxRewriter { readonly ListVisitor _visitor = new ListVisitor(); public override SyntaxList<TNode> VisitList<TNode>(SyntaxList<TNode> list) { var result = Syntax.List(list.SelectMany(_visitor.Visit).Cast<TNode>()); return base.VisitList(result); } private class ListVisitor : SyntaxVisitor<IEnumerable<SyntaxNode>> { protected override IEnumerable<SyntaxNode> DefaultVisit(SyntaxNode node) { yield return node; } protected override IEnumerable<SyntaxNode> VisitLocalDeclarationStatement( LocalDeclarationStatementSyntax node) { yield return node; yield return Syntax.ParseStatement("Console.WriteLine(\"I declared a variable.\");"); } } }
source share