Как динамически переписывать AST в плагине resharper?

Запрос:

Я бы хотел написать анализатор, который может предоставить значение прокси для определенного выражения и вызвать повторный анализ документа.

Мотивация:

Наш код завален ABTests, который может быть либо в развернутом, либо в активном состоянии с группой управления и варианта. Определение состояния теста выполняется через поиск базы данных. Для тестов, которые развертываются с контрольной группой, любой оператор следующей формы будет оценивать значение false:

if(ExperimentService.IsInVariant(ABTest.Test1))
{
}

Я пытаюсь предоставить инструменты, чтобы сделать это легче иметь дело во время разработки, поместив его в этом сценарии. Как бы то ни было, это довольно ограниченно и не является надежным, потому что я в основном должен сам играть в парсер.

Что делать, если фактический код

if(!ExperimentService.IsInVariant(ABTest.Test1))

или

if(ExperimentService.IsInVariant(ABTest.Test1) || true)

или

var val = ..... && (ExperimentService.IsInVariant(ABTest.Test1);
if(val){
  // val is always going to be false if we deployed control.
}

Возможный подход, который я мог видеть, заключается в том, что мы можем написать анализаторы, которые запускаются один раз и переписывать дерево до того, как произойдет синтаксический анализ IDE (или, просто, просто проанализируйте его второй раз). Они должны срабатывать только один раз и позволять нам заменять определенное выражение другим. Это позволило бы мне поменять все эти эксперименты на истинные и ложные литералы.

В результате эти разделы могут извлечь выгоду из всех других функций IDE, таких как кодирование кода для недостижимого кода, но также более сложные, такие как переменная, которая никогда не будет иметь другое значение

Очевидно, это просто пример, и я не уверен, насколько это возможно. Любые предложения относительно правильной функции или того, что уже существует, более чем приветствуются.

Ответ 1

Я не думаю, что есть подход, который не имеет компромисса.

ReSharper не поддерживает переписывание AST перед анализом - это просто переписывает текст в файле.

Вы можете написать анализатор, который вычеркивает код, применяя выделение "мертвого кода" к содержимому блока if, но, как вы говорите, вам нужно проанализировать код и проанализировать поток управления в чтобы это было правильно, и я думаю, что это было бы очень сложно (ReSharper действительно обеспечивает граф потока управления, поэтому вы можете его прогуливать, но вам будет нужно найти A. возвращаемое значение IsInVariant и B. проследите это значение в любых условиях, && или ||, пока не найдете соответствующий блок if).

В качестве альтернативы вы можете пометить метод IsInVariant атрибутом ContractAnnotation, например:

[ContractAnnotation("=> false")]
public bool IsInVariant(string identifier)
{
  // whatever...
}

Это скажет анализу ReSharper, что этот метод всегда возвращает false (вы также можете сказать, что он вернет true/false/null/not null на основе конкретного ввода). Поскольку он всегда возвращает false, ReSharper будет серого кода в выражении if или ветке else, если вы выполняете if (!IsInVariant(…)).

Недостатком здесь является то, что ReSharper также добавит предупреждение в оператор if, чтобы сообщить вам, что выражение всегда возвращает false. Итак, это компромисс, но вы можете изменить серьезность этого предупреждения на подсказку, так что это не так навязчиво.

Ответ 2

Этого недостаточно, чтобы действительно гарантировать награду, но одно решение, которое может применяться в документации разработчика, заключается в создании пользовательский язык и расширьте основные правила.

Вы сказали

Я пытаюсь предоставить инструменты, чтобы облегчить их работу во время разработки, поместив его в этом сценарии.

Серость соответствующих частей может быть выполнена только путем изменения правил подсветки синтаксиса.

Смотрите этот пример для файлов .tt.