﻿# Превратили PVS\-Studio в город

Вы когда\-нибудь хотели взглянуть на свой код под новым углом? Например, увидеть, как бы выглядела ваша кодовая база, будь она городом? Звучит как что\-то невероятное\. Давайте вместе заглянем в город PVS\-Studio и посмотрим, какие тайны он в себе хранит :\)\.

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

## Начнём с начала

Гуляя по просторам интернета, мы наткнулись на инструмент, который может представить код в виде города\. [Grappl](https://grappl.io/) строит визуальную карту вашей кодовой базы, показывая масштаб и иерархию всех файлов и классов\. А получившаяся картина захватывает дух, и вы будто летите над собственным проектом\.

Если вы, как и я, когда\-то задавались вопросом, как выглядит собственный код с высоты птичьего полёта, то теперь ответ на этот вопрос можно получить при помощи текстового редактора Visual Studio Code и [расширения Grappl](https://marketplace.visualstudio.com/items?itemName=grappl.grappl)\.

Создатели инструмента предлагают это решение для следующих задач:

* визуализация архитектуры кодовой базы для улучшения взаимодействия между техническими и нетехническими членами команды \(например, менеджерами и аналитиками\);
* автоматическое связывание между собой кода, задач из таск\-трекеров \(вроде Trello или Jira\) и коммитов\. Это должно ускорять процесс доставки кода, сокращать время на его обслуживание и помогать рецензентам и тестировщикам\.

Однако сегодня я предлагаю немного побаловаться и просто поисследовать здания нашего огромного города PVS\-Studio\.

В Grappl каждому типу элементов кода соответствует свой цвет\. Для наглядности разберёмся с обозначениями по следующей схеме:

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

Для начала протестируем инструмент на других проектах\. Так как мы часто [проверяем разные проекты](https://pvs-studio.ru/ru/blog/inspections/) с помощью нашего анализатора, у меня сохранилось несколько репозиториев\. Возьмём, к примеру, проект [PHP](https://github.com/php/php-src)\. Про ошибки в этом проекте я писала [статью](https://pvs-studio.ru/ru/blog/posts/cpp/1280/)\. Взгляните на архитектуру его кодового города:

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

На этой карте мы видим множество файлов, функций и структур, но полностью отсутствуют классы и пространства имён\. Всё дело в том, что код написан на C, где этих сущностей просто нет\.

Если вы уже изучили эту карту, то наверняка, обратили внимание на высокие синие башни\. Мне стало интересно, что скрывается в самой левой из них\. Оказалось, что это функция `lex_scan(zval * , zend_parser_stack_elem * )` из файла `Zend/zend_language_scanner.c`\. Её размер составляет около десяти тысяч строк, что и объясняет, почему здание такое высокое\.

Ещё один пример — проект [Xenia](https://github.com/xenia-project/xenia) на языке C\+\+\. Мы также проверяли его с помощью PVS\-Studio, а с результатами анализа можно ознакомиться в этой [статье](https://pvs-studio.ru/ru/blog/posts/cpp/1177/)\. А вот как выглядит его город:

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

Сам проект небольшой, поэтому парсинг кода не занял много времени, но результат впечатляет\. Тут уже можно увидеть большое количество разных пространств имён и классов\. Сравните эту карту с PHP\. Если проект на C был похож на Вашингтон, то здесь мы видим уже Нью\-Йорк\. А благодаря разделению их собственного кода от `third-party`\-библиотек, вдали от города мы можем увидеть этот "посёлок ~~городского типа~~", чей код значительно уступает по объёму основной части\.

## Ну и какой же город этот ваш PVS\-Studio?

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

<details>
   <summary>Краткая памятка</summary>

[PVS\-Studio](https://pvs-studio.ru/ru/) — [статический анализатор кода](https://pvs-studio.ru/ru/blog/terms/0046/), который развивается на рынке уже более 15 лет\. Изначально он был создан для поиска проблем при переходе с 32\-битных на 64\-битные системы и поддерживал языки C и C\+\+\. Однако со временем его функциональность значительно расширилась, и сегодня он эффективно выявляет широкий спектр ошибок общего назначения\. Узнать больше об этапах развития проекта можно по [ссылке](https://pvs-studio.ru/ru/blog/posts/0465/)\.



Сейчас PVS\-Studio может находить ошибки не только в коде на языках C и C\+\+, но и в C\# и Java\. Кроме того, анализатор имеет обширный набор диагностических правил, выявляющих потенциальные уязвимости из перечня [CWE](https://pvs-studio.ru/ru/pvs-studio/sast/cwe/), критические ошибки согласно [ГОСТ Р 71207\-2024](https://pvs-studio.ru/ru/pvs-studio/gost-71207/), а также отклонения от стандартов [MISRA](https://pvs-studio.ru/ru/pvs-studio/sast/misra/) и [OWASP ASVS](https://pvs-studio.ru/ru/pvs-studio/sast/owasp/)\.


</details>
Сегодня я предлагаю посмотреть на визуализацию кода C и C\+\+ анализатора\. Поскольку я сама занимаюсь разработкой этой части в инструменте, мне очень интересно узнать, как именно будет выглядеть наш город\. Давайте же заглянем под капот и изучим архитектуру PVS\-Studio\.

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

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

### Обширный жилой квартал: модули тестирования



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

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

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

* Rules — функциональные тесты диагностических правил\. Это наш главный индикатор: любые изменения в ядре или диагностических правилах сразу отражаются здесь, показывая прогресс или регресс;
* DocumentationTests — функциональные тесты, проверяющие, что анализатор выдаёт предупреждения на примеры из документации\. Если в документации описана ошибка — анализатор обязан её найти;
* ParseTests — функциональные тесты парсинга кода\. Большинство тестов — это комбинация наибольшего числа стандартных заголовочных файлов, которые мы генерируем с помощью утилиты\. Цель — проверить, что парсинг кода проходит без ошибок или падений\. Мы пополняем их при значительных изменения в стандартной библиотеке;
* UETests — функциональные тесты, проверяющие работу анализатора с нестандартными контейнерами игрового движка Unreal Engine;
* StructTests — тесты на точность вычисления размеров и выравниваний структур\. Именно поэтому здесь их так много — мы проверяем все возможные сценарии;
* AnnotationsTests — функциональные тесты работы системы [пользовательских аннотаций](https://pvs-studio.ru/ru/docs/manual/6743/), которые позволяют размечать типы и функций в формате JSON с целью дать анализатору дополнительную информацию;
* CodeCheck — функциональные тесты, проверяющие разнообразные конструкции, специфичные для компиляторов\.

Как вы могли заметить, чтобы надёжно находить ошибки в ваших кодовых базах, PVS\-Studio проходит через большое количество тестов, в том числе через самопроверку\. Если вы хотите попробовать наш статический анализатор на своём продукте, то получить триал можно по [ссылке](https://pvs-studio.ru/ru/pvs-studio/try-free/)\.

### Крупный деловой район: ядро анализатора

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

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

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

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

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

Для того, чтобы изучить ядро получше, предлагаю перенестись на "стройплощадку" — в процесс анализа кода\.

Все начинается с **препроцессора**\. Сначала мы грузим `*.i` файл, сгенерированный внешним препроцессором, и выполняем его первоначальную подготовку:

* заменяем табы на пробелы;
* удаляем BOM;
* записываем builtin\-функции;
* обрабатываем наши специальные комментарии;
* сопоставляем исходный и препроцессированный файлы через директивы `#line`;
* отслеживаем расхождения в нумерации строк между файлами\.

Потом такой код отправляется на "[разборки](https://pvs-studio.ru/ru/blog/terms/0025/)" к **лексеру** \(**Lexer**\)\. Да, он невелик, но выполняет критически важную работу: разбивает сплошной текст программы на базовые кирпичики — токены \(ключевые слова, операторы, идентификаторы и т\. д\.\)\.

После эти токены передаются **парсеру** \(**Parser**\)\. Его задача — понять структуру кода, собрав из разрозненных кирпичиков целую архитектурную схему — синтаксическое дерево\. Именно по этому дереву и будут путешествовать наши диагностические правила\.

После построения дерева за работу принимается **семантический анализатор** \(**Analyzer**\)\. В его задачи входит построение системы типов, ведение символьных таблиц и установление семантических связей между элементами кода\. Исторически сложилось, что в оригинальной архитектуре семантический анализатор и парсер функционировали независимо друг от друга, что создавало определённые ограничения для развития системы\.

А вот в релизе [PVS\-Studio 7\.38](https://pvs-studio.ru/ru/docs/manual/0010/#ID20E44DD9EE) было добавлено **новое ядро**\. Оно включает в себя полностью переработанные компоненты: парсер, семантический анализатор и систему типов\. И оно получилось в разы больше:

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

В новой архитектуре парсер и семантический анализатор работают в тесной связке, формируя синтаксическое дерево\. Более того, в новое ядро уже заложена основа для [**абстрактного синтаксического дерева**](https://pvs-studio.ru/ru/blog/terms/0004/) \(**AST**\), которое ждёт завершения доработок для полного включения в работу\. А пока что парсер формирует дерево старого типа с помощью **SyntaxTreeBuilder**\.

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

Неотъемлемой частью анализатора является **блок аннотаций** — внутренняя и внешняя система аннотирования сущностей\. Благодаря ей мы понимаем намного больше о проверяемом коде\. Система содержит семантику классов стандартной библиотеки, информацию о поведении функций, их предусловиях и побочных эффектах\. Также в этой части находится [механизм пользовательских аннотаций в формате JSON](https://pvs-studio.ru/ru/docs/manual/6743/)\.

После того, как дерево построено, к нему нужно добавить больше деталей\. Для этого используется [**анализ потока данных**](https://pvs-studio.ru/ru/blog/terms/7004/) \(**data\-flow analysis**\), который отслеживает значения переменных, спускаясь по коду программы\.

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

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

А когда весь код становится понятен анализатору, в работу включаются диагностические правила\.

### Пункт управления: статический анализатор

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

Здесь сосредоточены ключевые компоненты, отвечающие за организацию работы:

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

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

### Интеллектуальный центр: диагностические правила

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

А вот и самая густонаселённая зона нашего города, где находится более 700 [специалистов](https://pvs-studio.ru/ru/docs/warnings/) по анализу кода\. Каждое диагностическое правило — узкопрофильный эксперт, и вместе они составляют идеальную команду для проверки проектов\.

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

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

## Заканчиваем путешествие

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

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

Стройте город из своего кода и делитесь впечатляющими видами в комментариях :\)