Перейти к основному содержимому

Структурный поиск шаблонов и управляемое переписывание

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

Руководства

Структурный поиск 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.

Связанные руководства