Перейти до вмісту

Індексований пошук AST

Індексований пошук AST — це версія пошуку AST із прогрітим кешем. Під час першого виклику факти на рівні вузлів (назви викликів, створення екземплярів, оголошення класів і методів) витягуються у сховище на диску; наступні виклики використовують його, щоб пропускати файли, які очевидно не містять структурного збігу. Потім засіб зіставлення повторно перевіряє кандидатів за вихідним кодом.

Індекс фактів доступний через підкоманду greph-index ast-index CLI та методи фасаду Greph::buildAstIndex() / Greph::searchAstIndexed(). Він також використовується у прогрітих сценаріях пошуку в кількох індексах і наборах на основі маніфесту.

Створення індексу

Командна оболонка
# Full build at the current directory
./vendor/bin/greph-index ast-index build .

# Full build at an explicit root
./vendor/bin/greph-index ast-index build path/to/repo

# Use a non-default index directory
./vendor/bin/greph-index ast-index build . --index-dir /tmp/greph-ast-index

# Build a mutable overlay that can refresh cheaply on demand
./vendor/bin/greph-index ast-index build . \
  --lifecycle opportunistic-refresh \
  --auto-refresh-max-files 32 \
  --auto-refresh-max-bytes 1048576

За замовчуванням індекс фактів зберігається в <root>/.greph-ast-index/.

Після успішного створення виводиться однорядковий підсумок:

Text
Built AST index for 2547 files in .greph-ast-index (84931 fact rows, +2547 ~0 -0 =0)

Чотири лічильники показують кількість доданих, оновлених, видалених і незмінених файлів від часу останнього створення індексу.

Оновлення індексу

Командна оболонка
./vendor/bin/greph-index ast-index refresh .

refresh повторно обходить індексований кореневий каталог, повторно аналізує змінені файли та перезаписує лише змінені рядки фактів. У виводі використовуються ті самі чотири лічильники, що й для текстового індексу.

Профілі життєвого циклу працюють так само, як і для прогрітих текстових індексів:

  • static: ніколи автоматично не перевіряє актуальність і не вносить змін
  • manual-refresh: повідомляє про застарілий стан у stats, але не оновлює індекс під час пошуку
  • opportunistic-refresh: оновлює індекс під час пошуку, лише якщо набір змін достатньо малий
  • strict-stale-check: відхиляє пошук із застарілим індексом замість його оновлення

Запити до індексу

Командна оболонка
./vendor/bin/greph-index ast-index search 'new $CLASS()' src
./vendor/bin/greph-index ast-index search '$obj->$method($$$ARGS)' src
./vendor/bin/greph-index ast-index search --json 'array($$$ITEMS)' src
./vendor/bin/greph-index ast-index search -l 'array($$$ITEMS)' src
./vendor/bin/greph-index ast-index search --trace-plan 'new $CLASS()' src

Синтаксис метазмінних такий самий, як у нативному пошуку AST. Повний опис граматики дивіться в Режими / Пошук AST.

Параметри

Прапорець Значення
--lang NAME Мова AST. За замовчуванням: php
-j N, --jobs N Кількість паралельних робочих процесів
-l, --files-with-matches Показувати лише файли, що відповідають умовам
--glob GLOB Включати лише файли, шляхи до яких відповідають GLOB
--type NAME / --type-not NAME Фільтр за типом файлу
--json Виводити дані у форматі JSON
--no-ignore Ігнорувати .gitignore і .grephignore
--hidden Включати приховані файли
--strict-parse Завершувати роботу з помилкою аналізу замість пропуску таких файлів
--fallback MODE Поведінка за відсутності індексу: fail (за замовчуванням) або scan
--index-dir DIR Використовувати нестандартний каталог індексу
--trace-plan Виводити діагностику планувальника прогрітого AST у stderr
--show-index-origin Додавати на початку виводу назву відповідного індексу в режимі кількох індексів або наборів

Резервний режим за відсутності індексу

За замовчуванням ast-index search видає помилку, якщо в запитаному розташуванні немає індексу. Передайте --fallback scan, щоб перейти до нативного сканування AST. Цей параметр підійде інструментам, яким потрібен індексований пошук за його наявності, але які мають видавати результати й до створення індексу.

Командна оболонка
./vendor/bin/greph-index ast-index search --fallback scan 'new $CLASS()' src

Щоб шукати однією командою в кількох прогрітих індексах AST, можна повторювати --index-dir. Це зручно для структур, як-от WordPress ядра з плагіном або темою.

Командна оболонка
./vendor/bin/greph-index ast-index search \
  --index-dir ../wordpress/.greph-ast-index \
  --index-dir ./.greph-ast-index \
  --show-index-origin \
  'new $CLASS()' .

Якщо ввімкнено --show-index-origin, перед результатом виводиться назва відповідного запису прогрітого індексу, щоб було видно, з якого кореневого каталогу отримано збіг.

Набори індексів на основі маніфесту

Для стабільних прогрітих конфігурацій створіть маніфест, щоб greph-index set працював із групами індексів:

Командна оболонка
./vendor/bin/greph-index set build
./vendor/bin/greph-index set stats --mode ast-index --dry-refresh
./vendor/bin/greph-index set search --mode ast-index --show-index-origin 'new $CLASS()' .

Підкоманди наборів використовують ті самі параметри життєвого циклу, перевірки застарілого стану та діагностики планувальника, що й пряме використання ast-index.

Діагностика планувальника

--trace-plan показує, як Greph звузив запит перед запуском повного засобу зіставлення. Для ast-index це зазвичай охоплює:

  • грубий підпис фактів, витягнутий із шаблону
  • кількість прогрітих індексів, у яких виконувався пошук
  • кількість файлів, відсіяних фільтром фактів
  • кількість файлів-кандидатів, повторно проаналізованих для точної структурної перевірки

Що зберігає індекс

Для кожного індексованого файлу засіб витягування фактів AST створює рядок для кожного «цікавого» вузла. Набір типів фактів охоплює конструкції, які найчастіше шукають за шаблонами AST:

  • Виклики функцій і методів (за назвою викликаної функції чи методу)
  • Створення екземплярів класів (за назвою класу)
  • Оголошення класів, інтерфейсів, трейтів і переліків (за назвою)
  • Оголошення функцій (за назвою)
  • Оголошення методів (за назвою та видимістю)
  • Інструкції використання

Коли надходить запит, Greph\Ast\AstFactQuery перетворює шаблон пошуку на грубий підпис фактів (наприклад, «має містити new будь-якого класу») і відбирає відповідні записи зі сховища фактів. Файли, що залишилися після відбору, повторно аналізуються та зіставляються з повним шаблоном.

Отже, індекс фактів слугує попереднім фільтром, а не сховищем повних збігів. Під час зіставлення вихідний код усе одно аналізується, тому структурна точність така сама, як у нативному пошуку AST; зменшується лише набір файлів-кандидатів.

Коли використовувати

Режим індексованого AST стане у пригоді, якщо:

  • Ви багаторазово виконуєте ті самі структурні запити до однієї кодової бази.
  • Шаблони мають розпізнавані ознаки (назву виклику, назву класу або тип оголошення), які зберігає засіб витягування фактів.
  • Вам потрібна менша затримка, ніж під час повторного аналізу кожного файлу.

Для шаблонів, характерна ознака яких відсутня в наборі фактів (наприклад, складних вкладених виразів без розпізнаваного початкового елемента), зазвичай краще підходить режим кешованого AST: він повністю пропускає етап аналізу, не покладаючись на грубий підпис.

Програмне використання

PHP
use Greph\Greph;
use Greph\Ast\AstSearchOptions;
use Greph\Index\IndexLifecycleProfile;

Greph::buildAstIndex('.', lifecycle: IndexLifecycleProfile::OpportunisticRefresh);

$matches = Greph::searchAstIndexed(
    'new $CLASS()',
    'src',
    new AstSearchOptions(jobs: 4, tracePlan: true),
);

searchAstIndexed приймає те саме AstSearchOptions, що й нативний пошук AST, і повертає той самий формат list<AstMatch>. Для роботи з кількома індексами або потоками на основі маніфесту використовуйте searchAstIndexedMany(...) і searchAstIndexedSet(...).