【发布时间】:2023-04-04 10:43:01
【问题描述】:
我正在使用 Roslyn 实现不同的源代码转换。 (代码上下文将是一个独立的命令行实用程序,不是一个 VS CodeAction)
实现 CSharpSyntaxRewriter 并在访问特定节点时应用更改 on fly 的最简单方法。然而,这种方法可能有也可能没有副作用,导致结果不稳定。在更改树时,我们也在更改语义模型,因此之前获得的语义模型可能会失效。不详细介绍它有点类似于更改列表,同时枚举该而不通知枚举器。
(是的,我知道树是不可变的,但这就是重点:当重载方法返回替换节点而不是原始节点时,访问者将更改它。)
所以我有了这个想法:我们必须分两遍进行转换:首先收集更改,第二次实际应用更改。
- 第一遍显然是一个CSharpSyntaxRewriter(访问者),实际上并没有重写任何东西,只是产生了一个更改列表。 (也许一些较低的基本访问者类会比重写器做得更好,因为实际上不会在此过程中重写任何东西)
- 第二遍是更改列表应用程序,用于应用在第一遍中收集的更改。
下一个有趣的想法,第二遍不必操作树本身:它可以直接操作原始源文本(第一遍可以构建具有确切源代码位置的更改列表,因为 Span 信息可用于每个节点和令牌。)
抱歉这么长的解释,现在是问题:
我不想重新发明轮子:是否已经在 Roslyn 中实现了任何源代码操作基础架构(有一个更改列表,(例如基于 Spans)和 Apply(...) 它在源代码上?
提前谢谢
【问题讨论】:
-
我认为(但我可能错了)如果 "tree is immutable" 那么访问者 不会 更改它。这是一个处理阶段,而不是就地修改。
-
@Adriano,当然访问者不会更改不可变的东西,而是继续处理创建和更改的新对象,特别是当访问方法返回替换并且子节点尚未访问时。这样整个处理就完成了,而且数据结构不一致,前半部分处理在原来的,后半部分改了其他的。