Структурный поиск GoCPG находит фрагменты по форме синтаксического дерева (AST). Например, шаблон malloc($SIZE) выбирает вызовы malloc и связывает их аргумент с переменной $SIZE. Используйте поиск, чтобы найти повторяющиеся конструкции при аудите или подготовке рефакторинга.
Рабочий маршрут состоит из трёх этапов: поиск или сканирование YAML-правилами, просмотр находок, затем предпросмотр и подтверждение переписывания. В этом руководстве показаны локальные команды CLI для каждого этапа.
Правила структурного поиска находят форму кода и могут применять CPG-фильтры. Правила архитектуры сначала классифицируют файлы и символы в стабильные компоненты, затем проверяют типизированные зависимости и отдельный release-gate контракт. Для второго случая используйте руководство по контролю архитектуры.
Предварительные условия и область
Нужен установленный CLI GoCPG: команда gocpg должна быть доступна в PATH. В локальной копии исходников инструкция сборки находится в gocpg/README.md. Выполняйте примеры в PowerShell. Для gocpg search нужны исходники; для gocpg scan — также построенный по ним CPG. Замените пути в кавычках на свои. Одинарные кавычки сохраняют $SIZE как переменную AST-шаблона, а не переменную PowerShell.
Поиск и сканирование без изменения исходников
Сохраните этот учебный фрагмент в example.c внутри отдельного каталога. Он содержит два вызова malloc и один вызов calloc:
#include <stdlib.h>
void example(int n) {
void *p = malloc(100);
void *q = calloc(10, sizeof(int));
void *r = malloc(n * 2);
}
Передайте путь к этому каталогу в --input и выполните поиск AST-шаблона:
gocpg search --pattern 'malloc($SIZE)' --lang c --input "<source-root>" --json
В JSON ожидаются match_count: 2 и total_files: 1. Массив matches содержит malloc(100) на строке 3 и malloc(n * 2) на строке 5. Поле bindings.SIZE содержит соответственно 100 и n * 2. Вызов calloc в результат не входит.
Для повторяемой проверки сохраните правило в malloc.yaml в отдельном каталоге правил:
id: docs-malloc
language: c
severity: warning
message: "Allocation: $SIZE"
rule:
pattern: "malloc($SIZE)"
Постройте CPG этого учебного каталога. Выберите новый путь для базы, чтобы сохранить ранее построенные графы. Затем передайте абсолютный путь к каталогу с malloc.yaml и сохраните SARIF:
gocpg parse --input "<source-root>" --output "<cpg-path>" --lang c
gocpg scan --db "<cpg-path>" --rules "<absolute-rule-directory>" --format sarif | Set-Content -Encoding utf8 results.sarif
В results.sarif ожидаются версия 2.1.0 и две записи в runs[0].results с правилом docs-malloc и координатами строк 3 и 5. Это структурные находки: правило отмечает вызовы malloc для проверки. Используйте координаты, чтобы открыть исходники и изучить обработку результата вызова.
gocpg search читает текущие исходники и ограничивает число совпадений в каждом файле параметром --limit. gocpg scan читает выбранный CPG и применяет YAML-правила. Эти команды сохраняют исходники. Сохраните находки, диагностику, хеш правила и связь ревизии CPG с исходниками.
Сначала выполните предпросмотр
Скопируйте учебный example.c в отдельный каталог и постройте для него CPG. В новом каталоге правил сохраните malloc.yaml:
id: docs-malloc-rewrite
language: c
severity: info
message: "Review allocation: $SIZE"
tags: [autofix]
rule:
pattern: "malloc($SIZE)"
fix: "calloc(1, $SIZE)"
Это учебная замена: calloc выделяет память и заполняет её нулями. При подготовке собственного правила выберите преобразование, соответствующее поведению вашей программы.
gocpg scan --db "<cpg-path>" --rules "<absolute-rewrite-rule-directory>" --input "<rewrite-source-root>" --fix --dry-run
Предпросмотр показывает две замены: malloc(100) на calloc(1, 100) и malloc(n * 2) на calloc(1, n * 2). Вызов calloc(10, sizeof(int)) сохраняется. Исходный файл на этом этапе остаётся прежним.
Подтвердите, примените и проверьте
Изучите diff и подтвердите изменения до запуска следующей команды. Нативный CLI применяет --fix сразу; подтверждение выполняете вы. Используйте те же исходники и правило, которые проверили в предпросмотре:
gocpg scan --db "<cpg-path>" --rules "<absolute-rewrite-rule-directory>" --input "<rewrite-source-root>" --fix
Ожидаются две замены в example.c и резервная копия example.c.bak с исходным содержимым. Сравните файл с предпросмотром и проверьте результат поиском:
gocpg search --pattern 'malloc($SIZE)' --lang c --input "<rewrite-source-root>" --json
gocpg search --pattern 'calloc(1, $SIZE)' --lang c --input "<rewrite-source-root>" --json
Первый поиск возвращает match_count: 0, второй — match_count: 2: строки 3 и 5 со значениями SIZE 100 и n * 2. Выполните проверки сборки и тесты проекта. Если установлен GCC, проверьте синтаксис учебного файла:
gcc -fsyntax-only "<rewrite-source-root>/example.c"
После изменения исходников постройте обновлённый CPG по новому пути:
gocpg parse --input "<rewrite-source-root>" --output "<updated-cpg-path>" --lang c
Для восстановления учебного файла используйте сохранённую копию example.c.bak. В проекте сохраняйте исходную ревизию и проверяйте diff перед принятием изменений.
Как выбрать команду
Используйте gocpg search --json для разового поиска, gocpg scan — для повторяемой проверки YAML-правилами. Добавьте --fix --dry-run, чтобы увидеть предлагаемые замены, затем примените проверенное правило с --fix. Операции Python CLI с каталогом правил описаны в руководстве по CLI.