Написание Простого Анализатора Кода В Roslyn

Привет, Хабр! Не так давно я был на конференции CLRium от Сидристий , где я увидел достаточно простой и удобный способ анализа исходного кода C# в MSVS 2015. Проблема взята из проекта, в котором я участвую: каждый аргумент ссылочного типа должен иметь атрибут NotNull или CanBeNull (который затем использует ReSharper ).

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

Уже есть тесты, которые проверяют сборку и вылетают, если методы или конструкторы не содержат нужных атрибутов, но разработчики все равно довольно часто забывают их поставить, что приводит к сбою сборки, обновлению кода и т. д. Вот если Visual Studio вместе с ReSharper выдавал бы предупреждения о том, что код не совсем хорош, тогда можно было бы сэкономить время и нервы.

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

Исходный код можно посмотреть здесь .

Итак, сначала вы должны скачать Майкрософт Визуал Студия 2015 .

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

Далее вам необходимо скачать расширение для MSVS «Шаблоны SDK платформы компилятора .

NET» ( подробности смотрите здесь , Спасибо Ордос ) Далее создаем проект для нашего анализатора кода:

Написание простого анализатора кода в Roslyn

В результате студия создаст три проекта: рабочий проект, тесты и специальный проект для расширения vsix. Первый проект необходим для реализации нашего анализатора + для создания Code Fixes, то есть подсказки в студию с предложением поправить.

Существует два способа распространения пакета: через расширения vsix и через nuget. Первый позволяет установить проверки Visual Studio на текущий компьютер, не затрагивая ваши проекты.

Второй способ позволяет проверять код во время разработки (причем на любом компьютере будет скачан пакет nuget), а также во время сборки (даже если Visual Studio не установлена), он работает и в предыдущих выпусках Visual Studio. .

Для создания пакета nuget достаточно всего лишь файла nuspec и пары скриптов, но для расширения vsix создается дополнительный проект (который показан здесь только в качестве примера).

Проект с тестами тоже интересен: мы можем тестировать и отлаживать наш анализатор, не запуская Visual Studio отдельно! Мы просто создаем файл C#, загружаем его в компилятор, и он возвращает список предупреждений/ошибок! Visual Studio изначально создает анализатор шаблонов, который требует, чтобы все типы назывались ПРОПИСНЫМИ РЕГИСТРАМИ.

И тесты специально для него.

Чтобы изменить поведение, внесем следующие изменения в класс-потомок DiagnosticAnalyzer: 1. Измените DiagnosticId на свой.

Это ключ нашего предупреждения (типа String).

Программист увидит его в списке ошибок, CodeFix на него отреагирует, а атрибут SuppressMessage воспользуется им.

Чтобы случайно ни с кем не пересечься, лучше всего выбрать более аутентичное имя.

Я выбрал его как _ : NullCheckAnalyzer_MethodContainsNulls 2. Тогда лучше всего поменять все описания на свои: см.

методы Title, MessageFormat, Description, Category. 3. Далее в методе Initialize изменим аргументы функции RegisterSymbolAction: будем реагировать не на типы, а на методы.

Кстати, судя по моим исследованиям и Источники Рослин , некоторые значения SymbolKind вообще не поддерживаются (то есть, например, мы не можем реагировать на параметры).

3. Немного измените метод AnalysisSymbol: — На вход мы получим токен для проверки — Для каждой ошибки необходимо добавить информацию о ней в контекст. То есть для одного метода можно найти сколько угодно ошибок, с разными Id. В результате получается следующий код:

   

[DiagnosticAnalyzer(LanguageNames.CSharp)] public class NullCheckAnalyzer : DiagnosticAnalyzer { public const string ParameterIsNullId = "NullCheckAnalyzer_MethodContainsNulls"; // You can change these strings in the Resources.resx file. If you do not want your analyzer to be localize-able, you can use regular strings for Title and MessageFormat. internal static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.AnalyzerTitle), Resources.ResourceManager, typeof(Resources)); internal static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.AnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources)); internal static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.AnalyzerDescription), Resources.ResourceManager, typeof(Resources)); internal const string Category = "Naming"; internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(ParameterIsNullId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description); private static readonly ImmutableArray<DiagnosticDescriptor> supportedDiagnostics = ImmutableArray.Create(Rule); public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => supportedDiagnostics; public override void Initialize(AnalysisContext context) { context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.Method); } private static void AnalyzeSymbol(SymbolAnalysisContext context) { var methodSymbol = context.Symbol as IMethodSymbol; if (ReferenceEquals(null, methodSymbol) || methodSymbol.DeclaredAccessibility == Accessibility.Private) { return; } foreach (var parameter in ParametersGetter.GetParametersToFix(methodSymbol)) { var type = methodSymbol.ContainingType; // For all such symbols, produce a diagnostic. var diagnostic = Diagnostic.Create(Rule, parameter.Locations[0], methodSymbol.Name, type.Name, parameter.Name); context.ReportDiagnostic(diagnostic); } } }

Всё, теперь наш маленький анализатор будет заставлять Visual Studio выдавать ошибки.

Давайте проведем тесты для проверки.

Microsoft тщательно создала две: проверку правильности пустого файла и проверку правильности работы диагностики + исправлений.

Первый выполняется правильно, а второй завершается сбоем, поскольку мы никогда не исправляли код. Я попробовал быстро сделать Code Fix и понял, что даже такое простое исправление уже содержит нюансы, которые не так-то просто решить: — Из какого пространства имен следует добавить атрибут NotNull? От Решарпера.

*? А если вариантов несколько: свои атрибуты и пакет от Resharper? — Как добавить, используя: внутри пространства имен или вверху файла? Будут ли столкновения? Возможно, лучше было бы зарегистрировать псевдоним? — Если нет ссылки на сборку с атрибутами, то ее надо добавить, но по каким правилам? Стоит ли брать первый попавшийся или попробовать скачать с сайта nuget? Или из корпоративного репозитория Nuget? Попробовав несколько исправлений, я понял, что: 1. Они работают. Рослин фактически добавляет атрибуты и компилирует результат. 2. Алгоритм достаточно прост: нужно найти нужный элемент *Syntax, затем с помощью SyntaxFactory создать правильный и вызвать replaceNode. 3. Исправить правильный код не так просто, как кажется на первый взгляд. И вместо того, чтобы предлагать проблемное решение, лучше попросить программиста исправить ситуацию самостоятельно.

Для того, чтобы протестировать анализатор, вам достаточно установить пакет Nuget (т.е.

ввести в консоли диспетчера пакетов команду: Install-Package NullCheckAnalyzer).

Однако, скорее всего, собранный вами пакет работать не будет, так как изначально PowerShell-скрипты содержат ошибку: по пути в dll с анализатором по какой-то причине добавляется подпапка «C#».

Поэтому лучше изменить эти строки так: как это здесь сделано .

После этих действий пакет nuget готов, его можно загрузить на nuget.org, а затем добавить в проект. А вот как это выглядит в Microsoft Visual Studio 2015:

Написание простого анализатора кода в Roslyn

В результате на выходе мы получаем расширение: 1. Который подключается и обновляется через Nuget 2. Проверяет код при написании и компиляции (в том числе без MSVS) 3. Написано настолько просто и быстро, что рассмотрение среднего пул-реквеста в компании займет больше времени И напоследок пара советов: 1. Как видите, Microsoft отдала предпочтение неизменяемым типам.

Поэтому большинство структур Code Fix можно создать заранее, а затем просто предоставить ссылки.

2. Во время тестирования можно легко проверить только один файл, а потому лучше специально предусмотреть варианты с частичными классами и другими многофайловыми конструкциями 3. Релизной версии Roslyn пока нет, поэтому API может немного измениться.

Сейчас некоторые ответы на Stackoverflow содержат советы по устаревшему API. 4. Ордос предложенный страница в Интернете с похожим описанием .

Теги: #roslyn #visual studio 2015 #Visual Studio #microsoft #.

NET #C++ #анализатор кода #статический анализ #C# 6.0 #.

net 4.6 #проверки во время компиляции #.

NET #Visual Studio #C++

Вместе с данным постом часто просматривают: