
# ASTインデックス検索

ASTインデックス検索は、[AST検索](https://greph.inline0.dev/ja/docs/modes/ast)にキャッシュを追加したモードです。最初の呼び出しではノード単位の情報（呼び出し名、インスタンス化、クラス宣言、メソッド宣言）をディスク上のストアに抽出します。以降の呼び出しではこのストアを使い、構造パターンに一致する可能性が明らかにないファイルを除外します。その後、一致候補をソースに照らして再検証します。

ファクトインデックスは、`greph-index ast-index` CLIサブコマンドと`Greph::buildAstIndex()` / `Greph::searchAstIndexed()`ファサードメソッドから利用できます。事前作成済みインデックスを使った検索や、マニフェストを使ったセット検索にも対応しています。

## インデックスの作成

```bash
# 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/`に保存されます。

作成に成功すると、概要が1行で表示されます:

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

4つのカウンターには、前回の作成以降に追加、更新、削除されたファイル数と、変更されていないファイル数が表示されます。

## インデックスの更新

```bash
./vendor/bin/greph-index ast-index refresh .
```

`refresh`はインデックス対象のルートを再走査し、変更されたファイルを再解析して、変更があったファクト行のみを書き換えます。出力にはテキストインデックスと同じ4つのカウンターが使われます。

ライフサイクルプロファイルの動作は、事前作成済みテキストインデックスと同じです:

- `static`: 鮮度の確認も自動変更も行わない
- `manual-refresh`: 古い状態を`stats`で報告するが、検索中は更新しない
- `opportunistic-refresh`: 変更対象が十分少ない場合に限り、検索中に更新する
- `strict-stale-check`: 更新せず、古いインデックスでの検索を拒否する

## インデックスの検索

```bash
./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検索](https://greph.inline0.dev/ja/docs/modes/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スキャンを実行します。インデックスがあれば利用し、まだ作成されていない場合も検索結果を返したいツールに適した設定です。

```bash
./vendor/bin/greph-index ast-index search --fallback scan 'new $CLASS()' src
```

### 複数インデックスの検索

`--index-dir`を繰り返し指定すると、1つのコマンドで複数の事前作成済みASTインデックスを検索できます。WordPressのコアにプラグインやテーマを加えた構成などで便利です。

```bash
./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`に処理させます:

```bash
./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ファクト抽出器は「重要な」ノードごとに1行を記録します。ファクトの種類は、ASTパターンでよく対象になる構文を網羅しています:

- 関数とメソッドの呼び出し（呼び出し名別）
- クラスのインスタンス化（クラス名別）
- クラス、インターフェース、トレイト、enumの宣言（名前別）
- 関数宣言（名前別）
- メソッド宣言（名前と可視性別）
- use文

クエリを受け取ると、`Greph\Ast\AstFactQuery`は検索パターンを大まかなファクトシグネチャ（例:「任意のクラスの`new`を含む」）に変換し、ファクトストアと照合します。残ったファイルを再解析し、完全なパターンと照合します。

つまり、ファクトインデックスは完全な一致情報を保存するものではなく、候補を絞り込むための*事前フィルター*です。一致処理ではソースを引き続き解析するため、構造の正確さは標準のAST検索と同じで、候補の数だけが減ります。

## 使用する場面

次のような場合は、ASTインデックスモードが適しています:

- 同じコードベースに対して同じ構造クエリを繰り返し実行する
- パターンが、ファクト抽出器の保存する識別可能な形（呼び出し名、クラス名、宣言の種類）を対象にしている
- すべてのファイルを再解析するより、待ち時間を短縮したい

パターンを区別する特徴がファクトセットに含まれない場合（例: 識別可能な先頭部分を持たない複雑な入れ子式）は、[ASTキャッシュモード](https://greph.inline0.dev/ja/docs/indexed/cache)が一般に適しています。大まかなシグネチャに頼らず、解析の手順そのものを省略できます。

## プログラムからの利用

```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`は標準のAST検索と同じ`AstSearchOptions`を受け取り、同じ形式の`list<AstMatch>`を返します。複数インデックスやマニフェストを使う場合は、`searchAstIndexedMany(...)`と`searchAstIndexedSet(...)`を使用してください。
