Анализатор Roslyn анализирует пространства имен

#c# #roslyn #roslyn-code-analysis

#c# #roslyn #roslyn-анализ кода

Вопрос:

У нас есть некоторые рекомендации, как мы хотим использовать наши пространства имен, а также существуют ограничения доступа к ним. Поскольку разработчики иногда делают это неправильно, нам необходимо проанализировать эти правила. В настоящее время мы делаем это с помощью NDepend, который работает хорошо. Но процесс, при котором кто-то должен следить за этим, идти к парню, который нарушил эти правила, и заставить его это исправить, занимает очень много времени. Поэтому было бы очень приятно получать мгновенное уведомление во время разработки или, по крайней мере, после создания текущих изменений. Это должно быть задачей анализатора roslyn.

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

Мы говорим о решении с > 1 млн строк кода и почти 35000 типов. Таким образом, производительность действительно имеет большое значение.

Что я хочу сделать:

  1. получаем текущий класс
  2. получаем пространство имен текущего класса
  3. получить все используемые типы с их полным именем

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

Комментарии:

1. Есть ли у вас сервер непрерывной интеграции? Вы должны иметь возможность запускать NDepend (и любые другие проверки, такие как модульные тесты) там для каждой фиксации.

Ответ №1:

Анализатор Roslyn может регистрировать множество различных действий с кодом, например. на уровне «всего файла», метода, каждого отдельного синтаксического узла или символа. В зависимости от того, что именно вы пытаетесь проанализировать, любое из них может быть применимо для вас. Особенно, как вы указали, вас беспокоит производительность. Смотрите AnalysisContext.Register*Action() методы для возможных «зацепок», которые вы можете добавить.

Чтобы получить то, что вы хотите:

1 Получаем текущий класс

В принципе, с помощью любого из них вы должны быть в состоянии получить текущий класс (при регистрации синтаксического узла или символьного действия) или все объявленные классы (например, при регистрации действия компиляции или действия синтаксического дерева). Но самый простой вариант — зарегистрировать синтаксический анализ узлов для узлов класса, вы можете сделать это следующим образом:

 context.RegisterSyntaxNodeAction(AnalyzeClassNode, SyntaxKind.ClassDeclaration);
  

Где AnalyzeClassNode — действие для анализа объявления класса. Это приведет к получению дополнительного контекста (a SyntaxNodeAnalysisContext ), который содержит синтаксический узел объявления класса.

2 Получаем пространство имен текущего класса

Для этого вам понадобится семантическая модель. Допустим, вы использовали RegisterSyntaxNodeAction метод и объявили метод AnalyzeClassNode , затем в теле вы можете сделать это:

 var classNode = context.Node;
var model = context.SemanticModel;
var classSymbol = model.GetDeclaredSymbol(classNode);
  

И вы получаете символ пространства имен с:

 var @namespace = classSymbol.ContainingNamespace;
  

И .MetadataName выдаст вам пространство имен в виде строки.

3 Получите все используемые типы с их полным именем

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

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


Кстати, загляните на «Learn Roslyn Now», сайт с кучей руководств по Roslyn. В частности, вы хотите проверить часть 3 (для синтаксических узлов), 7 (для символов) и 10 (введение в анализаторы).

Комментарии:

1. Спасибо за ваш очень хороший ответ! Я проверю ссылки, которые вы мне дали, и вернусь, когда буду знать, что мне делать. Я не знаю, поможет ли это: мы хотим ограничить доступ к пространствам имен в нашем собственном коде (пространствам имен, начинающимся с названия нашей компании). За исключением некоторых элементов фреймворка, разрешен доступ только к иерархии вверх или до 3-го уровня также по всей, потому что у нас есть что-то вроде [company]. [модуль]. [особенность]. Доступ к функциям разрешен всем, но не их дочерним элементам. Подсказка «на лету», если вы остановите это, была бы очень милой.

2. А, понятно. В этой ситуации вы также могли бы просто проверить импортированные пространства имен и сопоставить их с пространством имен файла, если у вас есть только одно пространство имен для каждого файла. В отличие от использования семантической модели (которая, вероятно, будет намного дороже). Разве это не сработало бы? Лично я бы попытался применить это на уровне сборки, используя общедоступность для всех типов на третьем уровне. Однако, исходя из приведенных вами цифр, я могу предположить, что для вашего проекта это больше не будет возможно…

3. Кстати, я не смог фактически запустить свой код, поскольку писал его на своем Mac. Если в коде что-то не так, дайте мне знать, чтобы я мог обновить ответ. Возможно, завтра я смогу проверить образцы на своем рабочем компьютере.

4. Проблема с попыткой синтаксически использовать пространства имен заключается в том, что вам, возможно, придется иметь дело с вложенными. Кроме того, если вам нужно поддерживать VB.NET бывают случаи, когда синтаксического дерева недостаточно для определения пространства имен.

5. Вероятно, это хороший случай, когда вам следует просто использовать семантическую модель, а если она слишком медленная, то вернуться к ней снова. Преждевременная оптимизация и все такое.