Roslyn 语法树差异

6
假设我有两个SyntaxTree,A和B,其中B是通过对A进行更改而生成的。
我想获取以下信息: - 从A到B删除的SyntaxNodes和Tokens - 添加到A以生成B的SyntaxNodes和Tokens
是否有API可用于此?如果没有,如何高效地计算?
这些信息必须对Roslyn可用,因为未更改的GreenNode在树之间共享。
我能想到的一个解决方案是使用SyntaxTree.GetChangedSpans(),然后查找相交的tokens。但是,这感觉像是一个hack,并且我不确定它是否总是准确的。一个小的文本更改可能会对SyntaxTree产生很大的影响: (例如,在表达式中用+替换*可能会改变其顺序/优先级)

如果你真的有两个AST并且可以访问它们,这似乎很简单。列出A的节点和B的节点。nodes(A)-Green是已删除的节点。nodes(B)-Green是已添加的节点。你所需要做的就是进行树遍历,构建一些集合并进行集合减法。我不是Rosyln用户,但这难吗? - Ira Baxter
我认为由于技术原因,这种操作无法高效地完成(不能使用HashSets,因为节点的“不稳定”GetHashCode()实现)。相等性可以通过SyntaxNode.IsEquivalentTo()来判断。然而,我想避免将A中的每个节点与B中的每个节点进行比较,因为时间复杂度为O(n^2)。 - 3dGrabber
所以Roslyn让人失望。我构建了一个类似于Rosyln的系统,我的建议方法完全可行;事实上,我们有一个“智能差异器”,通过更加出色的树比较方式,在更加智能的方式下工作。请查看我的个人简介。 - Ira Baxter
1
你的语法树是否有共享历史?还是在更改之间重新解析它们? - JoshVarty
1
@IraBaxter:感谢您的建议,但由于各种原因,我现在必须坚持使用Roslyn。 我之前已经检查过您的个人资料和网站。 当在SO上浏览与AST相关的内容时,很难避免看到您的名字;) - 3dGrabber
显示剩余2条评论
1个回答

2
我们内部有一个位于编译器层的差异,因此使用绿色节点,但我们尚未将其公开为API。实际上,这就是我们用来驱动GetChangedSpans的工具。我们故意没有直接公开绿色节点,因为那是一个实现细节。
这个API没有特定的原因不能是公共的。我认为当这个API出现时,我们担心如何规定行为,或者什么是可以从差异中期望的最小“好处”。除此之外,我们没有一个激励场景来确保我们的工作是有用的。

这是第一个问题的答案:没有公共API。SyntaxDiffer有机会变成公共的吗?(pull request?)或者我们可以使用SyntaxTree.GetChangedSpansSyntaxTree.GetChanges来解决它吗? - 3dGrabber
附言:我应该在哪里询问有关Roslyn API的问题?是在SO、GitHub还是MSDN上?(例如,“SyntaxTree.GetChangedSpans”和“SyntaxTree.GetChanges”的区别是什么?”) - 3dGrabber
你完全可以提交一个拉取请求。我建议你先在GitHub上开一个bug,这样人们就知道有问题了,也有一些代表你正在做这项工作的东西。这也会让人们参与进来,提出他们知道的任何问题,你需要在公开之前修复它们。也许这段代码实际上存在缺陷,这就是为什么我们没有将其公开的原因。如果只是改变访问修饰符为public的“驱动式”拉取请求将被拒绝,因为我们必须维护一个受支持的、经过深思熟虑的、形式良好的API。 :-) - Jason Malinowski
就问题而言,StackOverflow或GitHub都是很好的论坛。我们也有一个Gitter频道。 - Jason Malinowski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接