PVS-Studio научился анализировать Blazor компоненты

от автора

Всем привет. Перед вами небольшая статья о добавлении анализа Blazor компонентов в PVS-Studio. По ходу рассказа постараемся предугадать ваши немые вопросы по теме и ответить на них. Приятного прочтения!

О чем статья?

Мы научили PVS-Studio анализировать код внутри компонентов Blazor приложений. В статье расскажем, как появилась идея, чем такой анализ полезен пользователям, какие возможности и ограничения есть в текущей реализации. Также предлагаем обсудить эту и будущие фичи PVS-Studio (об этом в конце статьи).

Давайте для начала освежим в памяти терминологию.

Razor – это синтаксис разметки, позволяющий встроить в веб-страницу C# код.

Разметку Razor используют Blazor/Razor компоненты (.razor файлы), а также Razor Pages (.cshtml файлы). Я указываю двойное название Blazor/Razor т.к. согласно MSDN оба названия приемлемы: «Blazor apps are built using Razor components, informally known as Blazor components«.

Итак, наш разговор пойдет в первую очередь о файлах с расширением .razor.

.razor файл – основной строительный элемент Blazor приложения. Razor компоненты позволяют инкапсулировать логику и отображение для формирования элемента пользовательского интерфейса. Каждый Razor компонент является самостоятельным блоком, что позволяет использовать их для создания новых компонентов и переносить между проектами.

Зачем мне, как пользователю, анализ Razor компонентов?

Web-приложения, использующие Blazor, содержат в файлах .razor C# код. Этот код, как и любой другой, может содержать ошибки, недочеты и опечатки. Они в свою очередь могут быть трудны для поиска «вручную» и дороги в исправлении при обнаружении на поздних этапах разработки. Теперь же PVS-Studio анализирует Razor компоненты, помогая сохранять код в них безопасным и корректным.

Почему раньше не умели анализировать .razor файлы?

Анализ .razor файлов был проблемой из-за наличия конструкций разметки Razor. Они не позволяли корректно получить синтаксическую и семантическую модели соответственно. Из-за этого проверка .razor файлов не была доступна «из коробки». Теперь мы доработали анализатор и научили проверять C# код в этих файлах. На данном этапе анализ производится только в блоках @code{…}. Такое решение было принято по совокупности различных факторов. Основной — желание предоставить пользователям анализ Razor компонентов как можно быстрее, пусть и в виде MVP.

Почему решились взяться за анализ .razor файлов?

Размышляя о том, куда должен двигаться наш C# анализатор, мы раз за разом приходили к тому, что вектор развития должен соответствовать потребностям пользователей. Многие из них так или иначе связаны с web-разработкой. Поэтому мы подумали: «А почему бы не расширить функционал анализатора в области анализа web-проектов?». И, вуаля – анализ .razor файлов добавлен.

И что, в .razor файлах могут быть ошибки?

Да, могут. Давайте рассмотрим несколько наиболее наглядных ошибок в .razor файлах Open Source проектов, которые попались мне при беглой проверке.

Issue 1:

.... RenderFragment<T> child() => item =>   @<text>   @{     var rowClass = new CssBuilder(RowClass)       .AddClass(RowClassFunc?.Invoke(item, rowIndex))       .AddClass(customClass,                  !string.IsNullOrEmpty("mud-table-row-group-indented-1"))       .Build();     ....   } .... 

Сообщение анализатора: V3022 Expression ‘!string.IsNullOrEmpty(«mud-table-row-group-indented-1»)’ is always true.

Начнем с довольно интересного на мой взгляд срабатывания анализатора в проекте MudBlazor. Анализатор предупреждает нас о том, что выражение !string.IsNullOrEmpty(«mud-table-row-group-indented-1») всегда истинно. Спорить с этим вряд ли получится, так как строковый литерал не может стать пустым или обратиться в null. Тяжело сказать, что именно здесь имелось ввиду, но выглядит подозрительно…

Issue 2:

@code {   ....   public void Evaluate()   {     ....     var exp = new Expression(CalcExpression);     var result = exp.Eval();     if (result == double.NaN)     {       Current = "ERROR";       return;     }     Current = Math.Round( result,8).ToString(CultureInfo.InvariantCulture);     CalcExpression = Current;   }   .... } 

Сообщение анализатора: V3076 Comparison of ‘result’ with ‘double.NaN’ is meaningless. Use ‘double.IsNaN()’ method instead.

Рассмотрим другой кейс на том же проекте. Анализатор говорит, что сравнение с double.NaN – бессмысленно. Но почему? Согласно MSDN сравнение двух NaN значений через оператор ‘==’ всегда возвращает false. Для корректного сравнения необходимо использовать метод double.IsNaN.

Issue 3:

Ну и куда же без упоминания собственных ошибок. Да-да, мы тоже допускаем ошибки и находим их благодаря собственному анализатору. После добавления анализа .razor файлов мы обнаружили интересные срабатывания в коде наших внутренних утилит.

@code {   async Task Load()   {     var exceptionCustomers = string.Empty;     var exceptionTeam = string.Empty;                            <=     ....     (CustomerNotifier, exceptionCustomers) = DbProvider.GetMailApplication(        CustomerCoreLibrary       .Data.Types       .ConfigMailApplicationType       .CustomerNotifier);      if (!string.IsNullOrEmpty(exceptionCustomers))       await MatDialogService.AlertAsync(exceptionCustomers);      (TeamNotifier, exceptionCustomers) = DbProvider.GetMailApplication(        CustomerCoreLibrary       .Data.Types       .ConfigMailApplicationType       .TeamNotifier);      if (!string.IsNullOrEmpty(exceptionTeam))                    <=       await MatDialogService.AlertAsync(exceptionTeam);     ....   } } 

Сообщения анализатора:

  1. V3022 Expression ‘!string.IsNullOrEmpty(exceptionTeam)’ is always false.

  2. V3127 Two similar code fragments were found. Perhaps, this is a typo and ‘exceptionTeam’ variable should be used instead of ‘exceptionCustomers’.

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

Во-первых, было обнаружено, что условие !string.IsNullOrEmpty(exceptionTeam) всегда ложно. Действительно, переменной exceptionTeam присвоена пустая строка и далее, вплоть до проверки, значение переменной никак не изменяется. Но из-за чего возник такой участок кода? На этот вопрос отвечает второе предупреждение, предполагающее наличие опечатки и использование не той переменной. И правда! Стопроцентное попадание.

На этом предлагаю остановиться, ведь у нас здесь не проверка проектов, а статья о новых возможностях анализатора. Если хотите поискать ошибки в .razor файлах своих проектов, можете взять пробную версию анализатора здесь. Интересными находками делитесь в комментариях.

Что с поддержкой .cshtml файлов?

На данный момент анализ .cshtml файлов не реализован, но это не значит, что мы не возьмемся за это. Если увидим заинтересованность пользователей, то обязательно попробуем поддержать и этот формат. Если вам интересен анализ .cshtml файлов, напишите нам об этом.

Заключение

В заключении прошу вас пройти небольшой опрос по теме в конце статьи и поделиться своим мнением о Razor и Blazor в комментариях.

Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Aleksey Avdeev. PVS-Studio now analyzes Blazor components.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Используете ли вы Blazor в своих проектах?
71.43% Да 5
28.57% Нет 2
Проголосовали 7 пользователей. Воздержались 4 пользователя.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Стоит ли нам добавлять поддержку анализа .cshtml файлов?
57.14% Определенно стоит 4
42.86% Пустая трата времени 3
Проголосовали 7 пользователей. Воздержались 4 пользователя.

ссылка на оригинал статьи https://habr.com/ru/company/pvs-studio/blog/709896/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *