﻿# Как получить и использовать бесплатную лицензию PVS\-Studio на практике\. Часть 3: работа с отчётом и разбор срабатываний

Продолжаем изучать использование PVS\-Studio на практике для бесплатных \(и не только\) проектов\. В этой статье мы рассмотрим основной этап взаимодействия с инструментом — работу с отчётом\! Подробно рассмотрим первый опыт разбора срабатываний, изучим интерфейс и посмотрим на ошибки в проекте osu\! 

![1294_PVS_4FREE_CH3_ru/image1.png](https://import.viva64.com/docx/blog/1294_PVS_4FREE_CH3_ru/image1.png)

## Введение

PVS\-Studio — это инструмент для поиска потенциальных ошибок и уязвимостей в коде на C, C\+\+, C\# и Java\. Он работает на Windows, Linux и macOS и имеет множество сценариев интеграции: плагина в IDE, игровые движки, системы качества кода и многое другое\. В коммерческом сегменте PVS\-Studio — платное B2B\-решение, которым пользуются многие команды и компании по всему миру\.

Это третья часть из цикла статей про использование PVS\-Studio с бесплатной лицензией\. Мы продолжаем знакомство с инструментом и сегодня на практике рассмотрим основной этап работы со статическим анализатором — изучение отчёта и разбор ошибок\!


> \*\*Примечание\\\.\*\* Если вам интересно, как получить бесплатную лицензию и настроить PVS\\\-Studio перед первым анализом проекта, то обязательно ознакомьтесь с \[первой\]\(https://pvs\-studio\.ru/ru/blog/posts/1286/\) и \[второй\]\(https://pvs\-studio\.ru/ru/blog/posts/1292/\) частью цикла статей\\\.

## Первый разбор ошибок

Мы остановились в прошлой статье на том, что провели первичный анализ кода на open source проекте osu\! и получили отчёт анализатора\. Казалось бы, основная работа инструмента завершена, но нет\. Самое интересное только начинается :\)

Но правила игры немного меняются: теперь основная ответственность лежит на разработчике\. От него зависит, правильно ли будут интерпретированы результаты анализа или нет, как будут исправлены выявленные проблемы\. А анализатор в свою очередь будет выступать уже помощником, а не основным персонажем\.

Но хватит лирики, давайте продолжать\. Анализ был завершён и, как мы уже разбирали в прошлой статье, лучшим способом быстро оценить полезность инструмента для проекта будет использование механизма отбора самых интересных срабатываний через интерфейс\. 

### Интерфейс и Best срабатывания

Чтобы отобразить самые интересные срабатывания, нужно нажать на кнопку **Best** в интерфейсе отчёта\. В результате останутся 10 отобранных сообщений анализатора\.

![1294_PVS_4FREE_CH3_ru/image2.png](https://import.viva64.com/docx/blog/1294_PVS_4FREE_CH3_ru/image2.png)

Новых пользователей обилие кнопок в интерфейсе может немного напрягать, но поверьте, он достаточно простой\. Давайте его рассмотрим поближе\. На скриншоте мы отметили места, на которые сейчас можно обратить внимание, это: номер диагностического правила \(1\), сообщение анализатора \(2\), файл с ошибкой и строка, на которой было предупреждение \(3 и 4\)\.

### Разбор ошибок

Пора бы уже перейти к главному — разбору срабатываний\! Выберем первое сообщение из 10, полученных благодаря **Best** механизму\.


> \*\*Примечание\\\.\*\* Учтите, что это не ТОП по срабатываниям анализатора, а лишь список наиболее интересных\\\. Места и порядок тут значения не имеют\\\.



![1294_PVS_4FREE_CH3_ru/image3.png](https://import.viva64.com/docx/blog/1294_PVS_4FREE_CH3_ru/image3.png)

При нажатии на предупреждение откроется файл, в котором возникла потенциальная ошибка\. Анализатор наведётся на строку и выделит подозрительный фрагмент кода\.

Давайте разберём его поподробнее:

```cpp
public partial class TestSceneBeatmapDifficultyCache
{
  ....
  AddStep(....)
  {
    var modRateAdjust = (ModRateAdjust)lookup.OrderedMods.SingleOrDefault(....);
    return new StarDifficulty
     (BASE_STARS + modRateAdjust?.SpeedChange.Value ?? 0, 0);
  }
}
```

<details>
   <summary>Предупреждение PVS\\\-Studio</summary>

V3123 Perhaps the '??' operator works in a different way than it was expected\. Its priority is lower than priority of other operators in its left part\. TestSceneBeatmapDifficultyCache\.cs 66


</details>


Из сообщения анализатора можно понять, что потенциальная ошибка заключается в проблеме с приоритетом операций, а если точнее, то в приоритете оператора `??`\. Его приоритетность ниже остальных операторов\. Мы можем дополнительно копнуть в диагностическое правило и заглянуть в документацию, нажав на код ошибки:

![1294_PVS_4FREE_CH3_ru/image4.png](https://import.viva64.com/docx/blog/1294_PVS_4FREE_CH3_ru/image4.png)

Документация откроется прямо в IDE:

![1294_PVS_4FREE_CH3_ru/image5.png](https://import.viva64.com/docx/blog/1294_PVS_4FREE_CH3_ru/image5.png)

Там мы сможем найти описание проблемы, пример ошибки и её исправления\.

Вернёмся к срабатыванию анализатора\. Для наглядности в логику можно добавить дополнительны скобки \(документация к диагностике тоже советует добавлять их, чтобы избегать подобных ошибок\)\. Исходя из текущего кода, можно сделать предположение, что разработчик ожидал такую проверку:

```cpp
BASE_STARS + (modRateAdjust?.SpeedChange.Value ?? 0)
```

Но мог ошибиться, не приняв во внимание особенности работы оператора `??`, и получил такую:

```cpp
(BASE_STARS + modRateAdjust?.SpeedChange.Value) ?? 0
```

Но почему мы считаем именно так? А всё просто: если взглянуть на код, а не только на отрывок, отмеченный анализатором \(что и требуется делать при изучении потенциальной ошибки\), мы сможем обнаружить важный контекст:

```cpp
public partial class TestSceneBeatmapDifficultyCache
{
  public const double BASE_STARS = 5.55;
  ....
  AddStep(....)
  {
    var modRateAdjust = (ModRateAdjust)lookup.OrderedMods.SingleOrDefault(....);
    return new StarDifficulty
     (BASE_STARS + modRateAdjust?.SpeedChange.Value ?? 0, 0);
  }
  ....
  AddUntilStep($"star difficulty -> {BASE_STARS + 1.5}", 
    () =>   starDifficultyBindable.Value.Stars == BASE_STARS + 1.5);
  ....
  AddUntilStep($"star difficulty -> {BASE_STARS + 1.25}", 
    () =>   starDifficultyBindable.Value.Stars == BASE_STARS + 1.25);
  ....
  AddUntilStep($"star difficulty -> {BASE_STARS + 1.75}", 
    () =>   starDifficultyBindable.Value.Stars == BASE_STARS + 1.75);

}
```

Уже можно заметить, что `BASE_STARS` является константой и подобного паттерна, как в потенциальной ошибке, дальше тоже нет\. Учитывая наличие константы `BASE_STARS`, было бы странно обнулять сумму, а не значение `modRateAdjust?.SpeedChange.Value` в случае, если проверка `modRateAdjust?` не пройдет\.

Стоит учесть, что мы сейчас рассмотрели код со стороны внешнего наблюдателя, не зная "внутренней кухни" проекта и контекста разработчика\.  Если брать во внимание, что вы будете пользоваться инструментом на знакомом для вас проекте, то будет гораздо проще исправить проблемы, которые нашёл анализатор\. 

Но дело не только в исправлении проблем\. Анализатор может ошибиться, и его результаты необходимо верифицировать разработчику\. Давайте разберём, как понять, что анализатор ошибся, и что делать в этом случае\.

### Подавление ложного срабатывания

Разберём на примере аналогичного срабатывания \(диагностика [V3123](https://pvs-studio.ru/ru/docs/warnings/v3123/)\) из того же проекта:

```cpp
public class SamePatternsGroupedHitObjects
{
  public IReadOnlyList<SameRhythmHitObjectGrouping> Groups { get; }

  public SamePatternsGroupedHitObjects? Previous { get; }

  public double GroupInterval => 
    Groups.Count > 1 ? Groups[1].Interval :   Groups[0].Interval;

  public double IntervalRatio => 
    GroupInterval / Previous?.GroupInterval ?? 1.0d;
}
```

<details>
   <summary>Предупреждение PVS\\\-Studio</summary>

V3123 Perhaps the '??' operator works in a different way than it was expected\. Its priority is lower than priority of other operators in its left part\. SamePatternsGroupedHitObjects\.cs 28


</details>


Сейчас сложно сказать, есть ли тут ошибка, о которой говорит нам анализатор\. Но всё встаёт на свои места, если отобразить комментарий к этому коду:

```cpp
public class SamePatternsGroupedHitObjects
{
  ....

  /// The ratio of GroupInterval between this 
and the previous SamePatternsGroupedHitObjects. 
  ///In the case where there is no previous 
SamePatternsGroupedHitObjects, this will have a value of 1.

  public double IntervalRatio => 
    GroupInterval / Previous?.GroupInterval ?? 1.0d;
}
```

Благодаря этому фактору мы можем понять, что же именно хотел разработчик\. Если `Previous?.GroupInterval` отсутствует \(`null`\), то все выражение будет `1`\. Или, если добавить скобочки, то получится так:

```cpp
public double IntervalRatio => 
  (GroupInterval / Previous?.GroupInterval) ?? 1.0d;
```

И мы можем понять одну вещь: ошибки нет\! Да, конечно, это не так очевидно, если смотреть только на код\. Без комментария понять не получилось бы\.\.\. Но факт остаётся фактом: проблемы нет\. 

Что же это значит?\.\. Анализатор плохо работает? Отнюдь\! Ложноположительные срабатывания — это не проблема, а особенность технологии, с которой надо уметь взаимодействовать и понимать, как отличить истинное срабатывание от ложного\. При разработке диагностических правил мы стараемся минимизировать возможность возникновения ложных срабатываний, отсекаем очевидные и не очень случаи, учитываем различные известные паттерны использования тех или иных конструкций\. Но иногда анализатору просто не хватает контекста\. Как раз в этом может помочь настройка инструмента, о которой мы говорили в [предыдущей статье](https://pvs-studio.ru/ru/blog/posts/1292/)\.

А что же делать нам? Не просто же игнорировать срабатывание\.\.\. Конечно же, нет\! Мы берём и отмечаем его ложным, нажав правой кнопкой мыши по сообщению анализатора и выбрав первый пункт в меню:


> \*\*Примечание\\\.\*\* Этот способ отмечает срабатывание комментарием в исходном коде\\\. Можно поступить иначе и нажать кнопку \*\*Add selected message to Suppression file\*\*, таким образом вы поместите их в файл, созданный анализатором, без модификации исходного кода\\\.



![1294_PVS_4FREE_CH3_ru/image6.png](https://import.viva64.com/docx/blog/1294_PVS_4FREE_CH3_ru/image6.png)

Этот механизм не удаляет срабатывание из списка сообщений, а отмечает его ложным и скрывает из отчёта\. Видимость для таких срабатываний можно вернуть, если включить настройку **DisplayFalseAlarm** в пункте **Specific Analyzer Setting:**

![1294_PVS_4FREE_CH3_ru/image7.png](https://import.viva64.com/docx/blog/1294_PVS_4FREE_CH3_ru/image7.png)


> \*\*Примечание\\\.\*\* После того, как вы "уберёте" сообщение из вкладки \*\*Best\*\*, место этого срабатывания займёт другое\\\.



Затем так же смотрим оставшиеся срабатывания анализатора\! 

Понравился опыт? Хотите продолжить? Тогда идём дальше\!

### Дальнейшее взаимодействие

Окей, все 10 срабатываний разобраны и, возможно, исправлены\. А что делать дальше? Логично будет пойти смотреть и исправлять остальные, правда ведь?\.\.\. Да?\.\.

Ну\.\.\. почти\.

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

![1294_PVS_4FREE_CH3_ru/image8.png](https://import.viva64.com/docx/blog/1294_PVS_4FREE_CH3_ru/image8.png)

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

Но не всё потерянно\! На этот случай в нашем инструменте имеется особый механизм массового подавления:

![1294_PVS_4FREE_CH3_ru/image9.png](https://import.viva64.com/docx/blog/1294_PVS_4FREE_CH3_ru/image9.png)

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

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

Более подробно мы рассказали про это в [другой нашей статье](https://pvs-studio.ru/ru/blog/posts/1272/)\.

## Разбор интерфейса

После первого опыта давайте посмотрим на более продвинутые техники работы с отчётом\. Для этого взглянем на интерфейс:

![1294_PVS_4FREE_CH3_ru/image10.png](https://import.viva64.com/docx/blog/1294_PVS_4FREE_CH3_ru/image10.png)

Здесь можно:

* помечать интересные срабатывания;
* подавлять ложноположительные срабатывания;
* сортировать их по разным категориям;
* выбирать уровни достоверности;
* открывать документацию к диагностикам;
* и ещё много чего полезного\!

А теперь давайте разберем его более подробно\.

### Основной интерфейс отчёта

Давайте пройдемся ещё раз по функционалу интерфейса, но в этот раз охватим все функции\.

**Отбор лучших срабатываний**

Для того, чтобы быстро оценить работу инструмента, имеется механизм **Best**, который соберёт 10 самых интересных срабатываний со всего отчёта\. Чтобы его включить, нужно нажать кнопку **Best** в верхней части интерфейса:

![1294_PVS_4FREE_CH3_ru/image11.png](https://import.viva64.com/docx/blog/1294_PVS_4FREE_CH3_ru/image11.png)

**Сортировка по уровням достоверности**

В анализаторе можно сортировать сообщения по трём уровням достоверности: **High**, **Medium**, **Low**\. Чем выше уровень достоверности, тем больше вероятность того, что ошибка реальна и может оказать влияние на программу\. Для стандартной работы с результатами анализа мы советуем выключать уровень **Low**\.

![1294_PVS_4FREE_CH3_ru/image12.png](https://import.viva64.com/docx/blog/1294_PVS_4FREE_CH3_ru/image12.png)

**Включение/выключение групп диагностик**

Вы можете включать и выключать группы диагностик, не заходя в настройки\. К примеру, диагностики [оптимизации](https://pvs-studio.ru/ru/blog/posts/csharp/1071/) или диагностики [по стандарту OWASP](https://pvs-studio.ru/ru/pvs-studio/sast/owasp/):

![1294_PVS_4FREE_CH3_ru/image13.png](https://import.viva64.com/docx/blog/1294_PVS_4FREE_CH3_ru/image13.png)

**Быстрая сортировка**

Этот механизм позволяет отсортировать сообщения анализатора по введённому значению для определённого поля\. Например, можно настроить вывод только сообщений диагностического правила [V3022](https://pvs-studio.ru/ru/docs/warnings/v3022/) из конкретного файла:

![1294_PVS_4FREE_CH3_ru/image14.png](https://import.viva64.com/docx/blog/1294_PVS_4FREE_CH3_ru/image14.png)

**Отметка интересных срабатываний**

Анализатор позволяет добавить срабатывания в **Избранное**\. Эти отметки сохраняются в отчёте\. По ним также можно отсортировать срабатывания:

![1294_PVS_4FREE_CH3_ru/image15.png](https://import.viva64.com/docx/blog/1294_PVS_4FREE_CH3_ru/image15.png)

**Дополнительные возможности**

![1294_PVS_4FREE_CH3_ru/image16.png](https://import.viva64.com/docx/blog/1294_PVS_4FREE_CH3_ru/image16.png)

* отметить срабатывание ложным;
* не проверять файлы из выбранного каталога;
* подавить все сообщения в отчёте;
* отобразить подавленные сообщения\.

### Работа с сообщениями анализатора

При нажатии правой кнопкой по сообщению анализатора у нас появляется контекстное меню:

![1294_PVS_4FREE_CH3_ru/image17.png](https://import.viva64.com/docx/blog/1294_PVS_4FREE_CH3_ru/image17.png)

В нём можно: 

* отметить срабатывание ложным;
* убрать отметку ложного срабатывания;
* подавить сообщение;
* скрыть все подобные сообщения по номеру диагностики;
* не проверять файлы и скрыть срабатывания из выбранного каталога;
* отобразить дополнительные колонки \(ID, Project, SAST, CWE\);
* отобразить полный путь до файла;
* скопировать сообщение анализатора;
* отметить сообщение анализатора;
* добавить TODO комментарий;
* перейти к другому сообщению по ID\.

За дополнительной информацией о работе с отчётом в плагине PVS\-Studio для Visual Studio вы всегда можете обратиться к [документации](https://pvs-studio.ru/ru/docs/manual/0021/)\.


> \*\*Примечание\\\.\*\* Во время работы над этим циклом статей мы нашли достаточно большое количество новых ошибок в проекте osu\\\! И, конечно, хотим их показать вам\\\! Ждите новую статью с проверкой проекта \[у нас в блоге\]\(https://pvs\-studio\.ru/ru/blog/posts/\)\\\.



## Заключение

В первой, второй и третьей части статей про использование статического анализатора PVS\-Studio для бесплатных проектов мы разобрали основные возможности инструмента и рассмотрели путь новичка\. Надеемся, эта информация помогла вам\!

Если у вас есть пожелания о том, что можно разобрать, пишите свои предложения в комментариях\.