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

По сути, если вы пишете на любом из современных языков программирования, вы уже — не зная об этом — прогоняете свой код через статический анализатор. Видите ли, любой современный компилятор предоставляет набор, пусть и крошечный, предупреждений для сообщения о потенциальных проблемах в вашем коде. Например, при компиляции кода C++ в Visual Studio может появиться следующее сообщение:

Этим выводом компилятор сообщает нам, что переменная var нигде в функции не использовалась. Итак, вы фактически использовали простой статический анализатор кода все это время. Однако, в отличие от профессиональных анализаторов, таких как Coverity, Klocwork или PVS-Studio, предупреждения компилятора выявляют лишь небольшой круг проблем.

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

Какова цель статического анализа?

Одним словом: сделать разработку быстрее и проще.

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

auto x = obj.x;
auto y = obj.y;
auto z = obj.z;

as:

auto x = obj.x;
auto y = obj.y;
auto z = obj.x;

Вы видите опечатку в последней строке. PVS-Studio сообщит об этой ошибке следующим предупреждением:

V537 Рассмотрите возможность проверки правильности использования элемента y.

Если вы хотите поиграть с этой ошибкой, попробуйте готовый фрагмент в Compiler Explorer: *клик*.

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

Тем не менее, эта ошибка была достаточно прозрачной. Но что, если ваша программа работает не самым оптимальным образом, потому что вы забыли о какой-то тонкой особенности языка? Или даже закончилось неопределенным поведением? К сожалению, подобные вещи случаются каждый день, и программисты тратят большую часть своего времени на отладку кода с ошибками из-за опечаток, типичных ошибок или неопределенного поведения.

Именно для решения таких задач и был изобретен статический анализ. Это помощник, который указывает вам на различные дефекты в вашем коде и объясняет с помощью прилагаемой документации, почему не стоит писать ту или иную конструкцию, что в ней плохого и как это исправить. Вот один из примеров: *клик*.

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

Теперь, когда вы узнали о статическом анализе и стали последователем этой методологии, вам, вероятно, не терпится попробовать ее. С чего начать? Как интегрировать новый инструмент в существующий проект? Как помочь своей команде подружиться с ним? На все эти вопросы будут даны ответы ниже.

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

0. Начало работы с инструментом

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

Что вы узнаете на этом этапе:

  • Какими способами можно взаимодействовать с анализатором;
  • Совместим ли анализатор с вашей IDE;
  • Какие проблемы есть у ваших проектов в настоящее время.

После того, как вы установили все необходимые компоненты, самое первое, что вам нужно сделать, это проанализировать весь проект (Windows, Linux, macOS). Если взять PVS-Studio в качестве примера, вывод, который вы получите в Visual Studio, будет выглядеть примерно так (щелкните, чтобы увеличить):

Проблема в том, что при запуске на проектах с большой кодовой базой статические анализаторы будут выдавать огромное количество предупреждений. Но вам не нужно исправлять их все, так как ваш проект уже работает достаточно хорошо, а значит, проблемы, которые выдает анализатор, не слишком критичны. Вы по-прежнему можете просмотреть наиболее интересные предупреждения и исправить их, если это необходимо. Для этого отфильтруйте выходные данные, чтобы оставить только самые важные предупреждения. В плагине PVS-Studio для Visual Studio это делается фильтрацией предупреждений по уровням и категориям. Чтобы отображались только самые точные предупреждения, отключите все уровни, кроме Высокий и Общий (нажмите, чтобы увеличить):

Осталось всего 178 предупреждений, с которыми, конечно, легче справиться, чем с несколькими тысячами…

Полезные предупреждения также часто можно найти на вкладках Средний и Низкий, но диагностика, включенная в эти категории, не очень точна (что означает высокую вероятность ложных срабатываний). Подробнее об уровнях предупреждений и способах работы с PVS-Studio в Windows читайте в следующей статье: *клик*.

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

1. Автоматизация

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

Что вы узнаете на этом этапе:

  • Как можно автоматизировать инструмент;
  • Совместим ли анализатор с вашей системой сборки.

Поскольку ни одна документация не идеальна, иногда приходится обращаться в поддержку. Ничего страшного — мы готовы помочь. :)

Теперь нам нужно интегрироваться с сервисами CI. Фактически они обеспечивают плавную интеграцию любого анализатора. Вам просто нужно добавить еще один этап конвейера — обычно следующий за этапом сборки и модульными тестами. Это можно сделать с помощью различных консольных утилит. Например, PVS-Studio предоставляет следующие утилиты:

Интеграция анализатора в CI состоит из трех шагов:

  • Установить анализатор;
  • Запустить его;
  • Доставьте результаты.

Например, чтобы установить PVS-Studio на Linux (на основе Debian), вам нужно выполнить следующие команды:

wget -q -O - https://files.viva64.com/etc/pubkey.txt \
    | sudo apt-key add -
sudo wget -O /etc/apt/sources.list.d/viva64.list \
  https://files.viva64.com/etc/viva64.list
  
sudo apt-get update -qq
sudo apt-get install -qq pvs-studio

В системах на базе Windows вы не можете установить анализатор с помощью менеджера пакетов, но вы можете развернуть его с помощью командной строки:

PVS-Studio_setup.exe /verysilent /suppressmsgboxes 
/norestart /nocloseapplications

Подробнее о развертывании PVS-Studio в системах на базе Windows см. *данное руководство*.

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

Поскольку выбор того или иного способа запуска анализатора зависит от платформы и особенностей проекта, я покажу, как это сделать на примере C++-кода (в Linux):

pvs-studio-analyzer analyze -j8 \
                            -o PVS-Studio.log
plog-converter -t errorfile PVS-Studio.log --cerr -w

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

Примечание. Текстовый формат не очень удобен. Я предложил это выше только в качестве примера. Вместо этого обратите внимание на более подходящий формат FullHtml, который поддерживает навигацию по коду.

Подробнее об интеграции анализатора с CI читайте в статье PVS-Studio и непрерывная интеграция (для Windows) или Как настроить PVS-Studio в Travis CI (для Linux).

Итак, анализатор запущен и работает на вашем сервере сборки. С этого момента, если член команды отправит непроверенный код, шаг анализа завершится с ошибкой, что позволит вам обнаружить проблему. Правда, это не совсем удобно, потому что более эффективная практика — проверять проект перед мержем веток, на этапе создания пулл-реквеста, а не после него.

Запуск анализа пул-реквестов не сильно отличается от запуска обычной проверки CI, за исключением того, что вам нужно получить список измененных файлов. Обычно его можно получить, запросив разницу между ветками с помощью git:

git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list

Теперь нужно передать этот список анализатору на вход. В PVS-Studio это делается с помощью флага -S:

pvs-studio-analyzer analyze -j8 \
                            -o PVS-Studio.log \
                            -S .pvs-pr.list

Подробнее об анализе запросов на включение см. в *этой статье*. Даже если ваш CI-сервис там не упоминается, вам все равно будет полезен раздел об общих принципах этого типа анализа.

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

Все это, конечно, хорошо, но хотелось бы, чтобы все типы предупреждений были собраны в одном месте — не только от статического анализатора, но и от юнит-тестов или от динамического анализатора. Для этого есть множество сервисов и плагинов. Например, в состав PVS-Studio входит плагин для SonarQube.

2. Интеграция на компьютерах команды

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

Самый простой вариант — поручить установку анализатора вашим разработчикам самостоятельно, но это займет довольно много времени и отвлечет их от работы. Вместо этого вы можете автоматизировать этот процесс с помощью установщика и соответствующих флагов. PVS-Studio поддерживает ряд флагов для автоматической установки. Тем не менее, вместо этого вы все равно можете использовать менеджеры пакетов, такие как Chocolatey (Windows), Homebrew (macOS) или десятки способов, доступных для Linux.

Затем вам нужно будет установить необходимые плагины — для Visual Studio, IDEA, Rider и т. д.

3. Повседневное использование

На этом этапе нам нужно поговорить о методах ускорения работы анализатора в его повседневном использовании. Полный анализ всего проекта занимает слишком много времени, но всегда ли мы модифицируем весь код сразу? Вряд ли существует рефакторинг такого глобального масштаба, чтобы задействовать всю кодовую базу. Обычно вы не изменяете более дюжины файлов за раз, так почему бы не проверить только эти файлы? Именно для этого и был создан режим инкрементального анализа. Не волнуйтесь, это не очередная утилита. Это просто специальный режим, который позволяет проверять только измененные файлы и их зависимости. Проверка запускается автоматически после завершения сборки проекта — при условии, что вы работаете в IDE с установленным соответствующим плагином.

Если анализатор обнаружит проблемы в недавно измененном коде, он автоматически сообщит вам об этом. PVS-Studio делает это, показывая следующее сообщение:

Конечно, просто сказать разработчикам, чтобы они просто использовали этот инструмент, не поможет. Вы должны рассказать им, что это такое и что с этим делать. Вот несколько статей по началу работы с PVS-Studio, но аналогичные руководства можно найти и для любого другого инструмента, который вы выберете:

Подобные статьи не требуют много времени для прочтения, предоставляя разработчикам всю необходимую информацию для ежедневного использования анализатора. :)

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

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

Пост-интеграция

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

Однако без регулярного использования статический анализ едва ли облегчил бы вашу жизнь. Его сильная сторона на самом деле не в том, чтобы находить запутанные и сомнительные места как таковые, а в том, чтобы делать это заблаговременно. Все согласятся, что найти ошибку в модифицированном коде на этапе тестирования не только неприятно, но и неоптимально. С другой стороны, статический анализ — при регулярном использовании — немедленно проверяет каждое изменение на вашем компьютере и информирует вас о любых подозрительных местах, пока вы продолжаете писать код.

Если вы или ваши товарищи по команде все еще не решаетесь внедрить статический анализ, рекомендую прочитать статью «Почему стоит выбрать статический анализатор PVS-Studio для интеграции в ваш процесс разработки». В нем рассматриваются типичные опасения разработчиков о том, что статический анализ является пустой тратой времени, и многое другое.