Comments 3
Если из статьи непонятно — на всякий случай явно уточню: тул не использует LLM. Детерминированный статический анализ, работает без интернета, код никуда не уходит.
Чё-то я пока не представляю, как можно добиться анализа инклюдов без compile_commands.json. Возможно, об этом стоило написать в статье.
Справедливый вопрос - про это правда стоило написать в статье, исправлюсь. По сути: compile_commands.json нужен, когда файл надо понять так, как его понимает компилятор: семантика, типы, активные ветки препроцессора. Для графа инклюдов достаточно препроцессорного скана и резолвинга путей по дереву репозитория. Механика такая. Сканер проходит все C/C+±файлы дерева и вытаскивает #include-директивы (комментарии, строковые литералы и raw-строки вычищаются до извлечения). Кавычечный инклюд резолвится в три шага: относительно каталога включающего файла, затем как точный путь от корня репозитория, затем суффиксным поиском по индексу всех файлов проекта — lib/widget.h найдёт include/lib/widget.h без знания include-корней. Угловые без пути (, <string.h>) считаются системными и в граф проекта не входят; <mylib/foo.h> с путём резолвится в файл проекта, если он есть в дереве. Ключевое свойство: инструмент не угадывает. Если кандидатов несколько, зеркальные каталоги отбрасываются, оставшаяся неоднозначность помечается ambiguous и ребра в графе не даёт. Ничего не нашлось — unresolved. #include MACRO не расширяется и фиксируется как диагностика. Экзотический -I-путь, известный только флагам сборки, просто попадёт в unresolved. Про #ifdef - принципиальный момент. archcheck сознательно смотрит все ветки условной компиляции, а не одну конфигурацию сборки. Зависимость под дефайном — всё равно зависимость: она живёт в репозитории, у кого-то собирается и поддерживается. Цикл под #ifdef _WIN32 — это дрейф, даже если сегодняшняя Linux-сборка его не видит. Анализ через compile_commands такой цикл не найдёт в принципе: он видит одну проекцию проекта, а не проект. Крайний случай - «цикл», склеенный из взаимоисключающих веток, который не собирается ни в одной конфигурации. Но если топология графа зависимостей меняется от комбинации дефайнов, это уже само по себе признак плохого дизайна: #ifdef должен выбирать реализацию, а не структуру. Так что и такая находка — не ложная тревога, а повод посмотреть на код. Цена приближения тоже известна не теоретически: классы ложных срабатываний резолвинга выбивались прогонами на корпусе реальных open-source репозиториев - суффиксные коллизии с системными хедерами, зеркальные каталоги, …/-пути, кейс-мисматчи. На каждый класс есть фикс и регрессионный тест. А для семантических правил, которым компилятор действительно нужен, в v0.2 появится опциональный libclang-бэкенд - он как раз читает compile_commands.json
archcheck — на страже архитектуры C++