Roslyn SyntaxTree Diff

Допустим, у меня есть два SyntaxTrees A и B,
где B был создан путем применения изменений к A.

Я хотел бы получить следующую информацию:

  • SyntaxNodes & Tokens, которые были удалены из A для создания B
  • SyntaxNodes & Tokens, которые были добавлены к A для создания B

Есть ли для этого API?
Если нет, то как это можно эффективно вычислить?

Эта информация должна быть доступна для Roslyn,
так как неизменные GreenNode являются общими для деревьев.

Я могу придумать одно решение: использовать SyntaxTree.GetChangedSpans()
, а затем искать пересекающиеся токены.
Однако это похоже на взлом, и я не уверен, всегда ли он точен.
Небольшое изменение текста может иметь значение. большое влияние на SyntaxTree:
(например, замена * на + в выражении может изменить его порядок/приоритет)


person 3dGrabber    schedule 22.01.2016    source источник
comment
Если у вас действительно есть два AST и доступ к ним, это кажется простым. Составьте список узлов A и узлов B. Узлы (A)-Green — это те, которые были удалены. узлы (B)-зеленые — это те, которые были добавлены. Все, что вам нужно сделать, это пройтись по дереву, построить несколько наборов и выполнить вычитание наборов. Я не пользователь Rosyln, но это сложно?   -  person Ira Baxter    schedule 22.01.2016
comment
Я думаю, что это невозможно сделать эффективно по техническим причинам. (невозможно использовать HashSets из-за нестабильной GetHashCode() реализации узлов). Равенство работает: SyntaxNode.IsEquivalentTo(). Однако я хотел бы избежать сравнения каждого узла в A с каждым узлом в B bcs O(n^2).   -  person 3dGrabber    schedule 22.01.2016
comment
Так что Рослин разочаровывает. (Я создаю систему, которая делает что-то вроде Rosyln, и мой предложенный метод будет работать очень хорошо; на самом деле у нас есть умный дифференциатор, который работает путем гораздо более впечатляющего сравнения деревьев, гораздо более умным способом. См. мою биографию) .   -  person Ira Baxter    schedule 22.01.2016
comment
Есть ли у ваших синтаксических деревьев общая история? Или вы повторно анализируете их с нуля между изменениями?   -  person JoshVarty    schedule 22.01.2016
comment
Smart Differencer анализирует два отдельных файла, а затем создает правдоподобный набор действий редактирования для создания одного из другого, используя совпадающие изоморфные под-переименования поддеревья. См. semdesigns.com/Products/SmartDifferencer/. Если вы хотите узнать, учитывая один AST, как вы получили другой, с нашими более общими инструментами преобразования, вы бы просто записали набор сделанных вами изменений узла; мы не храним неизменный оригинал.   -  person Ira Baxter    schedule 24.01.2016
comment
@JoshVarty: Да, у них общая история. Я вижу, что они совместно используют внутренние GreenNode, как описано в блог Эрика Липперта. Однако общедоступного API для доступа к GreenNodes нет.   -  person 3dGrabber    schedule 25.01.2016
comment
@IraBaxter: спасибо за ваши предложения, но сейчас мне придется придерживаться Рослин по разным причинам. Я проверил ваш профиль и веб-сайт раньше. Вас трудно избежать при просмотре материалов, связанных с AST, на SO;)   -  person 3dGrabber    schedule 25.01.2016


Ответы (1)


У нас внутреннее отличие который живет на уровне компилятора и поэтому использует зеленые узлы, мы просто не представили его как API. На самом деле это то, что мы используем для управления GetChangedSpans. Мы намеренно не отображали зеленые узлы напрямую, потому что это деталь реализации.

Нет конкретной причины, по которой API не может быть общедоступным. Я думаю, что когда это появилось, мы беспокоились о том, как на самом деле определить, что такое поведение, или какое минимальное «добро» вы можете ожидать от diff. Это, и у нас не было мотивирующего сценария, чтобы убедиться, что наша работа действительно полезна.

person Jason Malinowski    schedule 26.01.2016
comment
Это отвечает на первый вопрос: общедоступного API нет. Есть ли шанс, что SyntaxDiffer станет общедоступным? (запрос на вытягивание?). Или мы можем обойти это, используя SyntaxTree.GetChangedSpans или SyntaxTree.GetChanges? - person 3dGrabber; 27.01.2016
comment
В сторону: где я должен задавать вопросы о Roslyn API? Итак, GitHub, MSDN? (например, в чем разница между SyntaxTree.GetChangedSpans и SyntaxTree.GetChanges) - person 3dGrabber; 27.01.2016
comment
Вы можете полностью отправить запрос на вытягивание. Я бы сначала предложил вам открыть ошибку на GitHub, чтобы люди знали, что есть проблема, и было какое-то представление о том, что вы действительно выполняете работу. Это также позволит людям сообщать о любых известных им проблемах, о которых вы хотите исправить, прежде чем опубликовать их. Возможно, этот код на самом деле глючит, как и все остальное, и поэтому мы не публиковали его. Привод по запросу на вытягивание, просто изменив модификаторы доступа на общедоступные, будет отклонен только потому, что мы должны поддерживать поддерживаемый, продуманный, хорошо сформированный API. :-) - person Jason Malinowski; 27.01.2016
comment
Что касается вопросов, StackOverflow или GitHub — отличные форумы. У нас тоже есть канал Gitter. - person Jason Malinowski; 27.01.2016