# 機能設計書 16-参照検索 (textDocument/references)

## 概要

本ドキュメントは、Lua Language Serverにおける「参照検索」機能の設計を記述する。この機能は、LSPの`textDocument/references`リクエストに対応し、シンボルの全参照箇所を検索する機能を提供する。

### 本機能の処理概要

参照検索機能は、カーソル位置のシンボル（変数、関数、フィールドなど）の全参照箇所を検索し、その位置情報のリストを返す機能である。開発者はシンボルがプロジェクト内でどこで使用されているかを一覧で確認できる。

**業務上の目的・背景**：大規模なLuaプロジェクトでは、変数や関数がどこで使用されているかを把握することは重要である。リファクタリング前の影響範囲調査、コード理解、デバッグなどの場面で参照検索は必須の機能となる。

**機能の利用シーン**：
- 変数や関数の使用箇所を全て確認したい場合
- リファクタリング前に影響範囲を調査したい場合
- コードの依存関係を理解したい場合
- 未使用コードを特定したい場合

**主要な処理内容**：
1. カーソル位置のソースノードを特定
2. `vm.getRefs`で全参照を取得
3. メタファイルからの参照を除外（ソース自体がメタファイルの場合は除く）
4. 宣言を含めるかどうかをオプションで制御
5. ドキュメントアノテーション系のノードを適切にフィルタ
6. 結果をソートして重複を除去
7. `@source`アノテーションがある場合は外部ファイルパスを解決

**関連システム・外部連携**：
- LSPプロトコルの`textDocument/references`リクエストハンドラ
- 参照検索システム（vm.getRefs）

**権限による制御**：特になし

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 8 | 参照検索 | 主機能 | シンボルの全参照箇所を検索する主処理 |
| 10 | 名前変更 | 補助機能 | リネーム対象の全参照箇所を特定 |
| 15 | コードレンズ | 補助機能 | 参照数のカウント処理 |

## 機能種別

コードナビゲーション / 検索処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| uri | uri | Yes | 対象ファイルのURI | 有効なファイルURI |
| position | integer | Yes | カーソル位置 | 正の整数 |
| includeDeclaration | boolean | Yes | 宣言を含めるかどうか | true/false |

### 入力データソース

- 対象ファイルのAST状態（files.getState）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| target | parser.object | 参照のソースノード |
| uri | uri | 参照のファイルURI |
| source | parser.object | 検索元のソースノード |

### 出力先

LSPレスポンスとしてクライアントに返される

## 処理フロー

### 処理シーケンス

```
1. ASTを取得
   └─ files.getState(uri)でファイル状態を取得
2. カーソル位置のソースを特定
   └─ findSource(ast, position, accept)で該当ノードを検索
3. メタファイルかどうかをチェック
   └─ vm.isMetaFile(uri)でチェック
4. vm.getRefsで参照を取得
   └─ ソースノードの全参照を収集
5. 各参照をフィルタリング
   └─ メタファイルからの参照を除外（ソースがメタでない場合）
   └─ self型を除外
   └─ includeDeclarationがfalseの場合、宣言/リテラルを除外
   └─ doc系ノードのソース型制限
6. 結果をソート
   └─ URI順、開始位置順でソート
   └─ ネストした結果は範囲が小さい方を優先
7. jumpSourceで@source解決
   └─ 外部ファイルパスがある場合はそちらを使用
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B[AST取得]
    B --> C{AST存在?}
    C -->|No| D[nil を返す]
    C -->|Yes| E[ソースノード特定]
    E --> F{ソース存在?}
    F -->|No| D
    F -->|Yes| G[メタファイルチェック]
    G --> H[vm.getRefs実行]
    H --> I[各参照をループ]
    I --> J{メタファイルから?}
    J -->|Yes| K{ソースもメタ?}
    K -->|No| I
    K -->|Yes| L[通過]
    J -->|No| L
    L --> M{self型?}
    M -->|Yes| I
    M -->|No| N{宣言を含む?}
    N -->|No| O{宣言/リテラル?}
    O -->|Yes| I
    O -->|No| P[結果に追加]
    N -->|Yes| P
    P --> Q{全参照処理完了?}
    Q -->|No| I
    Q -->|Yes| R{結果あり?}
    R -->|No| D
    R -->|Yes| S[結果をソート]
    S --> T[jumpSource処理]
    T --> U[結果を返す]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | メタファイル除外 | メタファイルからの参照は除外（ソースがメタファイルの場合は除く） | フィルタリング時 |
| BR-02 | self除外 | type='self'のノードは除外 | フィルタリング時 |
| BR-03 | 宣言オプション | includeDeclarationがfalseの場合、guide.isAssignまたはguide.isLiteralな参照を除外 | フィルタリング時 |
| BR-04 | doc型制限 | doc.class.name等のノードは、ソースがdoc系でない場合は除外 | フィルタリング時 |
| BR-05 | function例外 | リテラルでもfunctionは除外しない | フィルタリング時 |
| BR-06 | ネスト優先 | 同一URI内でネストした結果は範囲が小さい方を優先 | ソート処理時 |

### 計算ロジック

宣言/リテラル判定:
```lua
-- includeDeclarationがfalseの場合
if guide.isAssign(src) or guide.isLiteral(src) then
    -- function以外は除外
    if src.type ~= 'function' then
        goto CONTINUE
    end
end
```

## データベース操作仕様

この機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 無視 | ASTが取得できない | nilを返す |
| - | 無視 | ソースノードが特定できない | nilを返す |
| - | 無視 | 参照が見つからない | nilを返す |
| - | 無視 | 参照のルートが取得できない | その参照をスキップ |

### リトライ仕様

リトライは行わない。

## トランザクション仕様

該当なし

## パフォーマンス要件

- `vm.getRefs`は非同期処理（@async）で実行
- ワークスペース全体を検索するため、大規模プロジェクトでは時間がかかる可能性がある
- LSPの応答性を維持するためprogress表示（0.5秒以上の処理時）

## セキュリティ考慮事項

- ワークスペース外のファイルへのアクセスは制限される

## 備考

- メタファイル（ビルトイン定義等）は特別扱いされる
- コードレンズや名前変更機能から内部的に呼び出される場合がある
- 結果はLocation形式で返される

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

参照検索の結果構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | reference.lua | `script/core/reference.lua` | 結果オブジェクト構造：{ target, uri, source } |
| 1-2 | reference.lua | `script/core/reference.lua` | accept テーブル（33-54行目）で対象ノード型を定義 |

**読解のコツ**: `accept`にはfunction、setindex、getindex、tableindexも含まれ、他のナビゲーション機能より広い範囲を対象とする。

#### Step 2: エントリーポイントを理解する

メイン関数の構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | reference.lua | `script/core/reference.lua` | メイン関数（57-160行目）がモジュールの戻り値 |
| 2-2 | provider.lua | `script/provider/provider.lua` | textDocument/references ハンドラ（495-528行目） |

**主要処理フロー**:
1. **62-65行目**: AST取得、存在しなければnil
2. **67-70行目**: ソースノード特定、存在しなければnil
3. **72行目**: メタファイルチェック
4. **74行目**: vm.getRefsで参照取得
5. **76-149行目**: 各参照のフィルタリング
6. **151-157行目**: 結果のソートとjumpSource処理

#### Step 3: フィルタリング条件を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | reference.lua | `script/core/reference.lua` | メタファイル除外（83-85行目） |
| 3-2 | reference.lua | `script/core/reference.lua` | self除外（86-88行目） |
| 3-3 | reference.lua | `script/core/reference.lua` | 宣言除外（89-94行目） |
| 3-4 | reference.lua | `script/core/reference.lua` | doc系フィルタ（123-136行目） |

### プログラム呼び出し階層図

```
provider.lua ('textDocument/references' ハンドラ)
    │
    └─ reference.lua (メイン関数)
           │
           ├─ files.getState() [AST取得]
           ├─ findSource() [ソースノード特定]
           ├─ vm.isMetaFile() [メタファイル判定]
           ├─ vm.getRefs() [参照取得]
           ├─ guide.isAssign() [代入判定]
           ├─ guide.isLiteral() [リテラル判定]
           ├─ sortResults() [ソート処理]
           └─ jumpSource() [@source解決]
```

### データフロー図

```
[入力]                    [処理]                           [出力]

URI ─────────────────────┐
                         │
カーソル位置 ─────────────┼──▶ reference() ──▶ results[]
                         │         │
includeDeclaration ──────┘         │
                                   ▼
                         ┌────────────────┐
                         │ ソースノード特定 │
                         └────────────────┘
                                   │
                                   ▼
                         ┌────────────────┐
                         │  vm.getRefs    │
                         └────────────────┘
                                   │
                                   ▼
                         ┌────────────────┐
                         │ フィルタリング   │
                         │ - メタファイル   │
                         │ - self除外      │
                         │ - 宣言オプション │
                         │ - doc型制限    │
                         └────────────────┘
                                   │
                                   ▼
                         [{ target, uri, source }]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| reference.lua | `script/core/reference.lua` | ソース | 参照検索のメイン実装 |
| provider.lua | `script/provider/provider.lua` | ソース | LSPハンドラ、参照リクエストを処理 |
| find-source.lua | `script/core/find-source.lua` | ソース | カーソル位置のソースノード特定 |
| jump-source.lua | `script/core/jump-source.lua` | ソース | @sourceアノテーション解決 |
| guide.lua | `script/parser/guide.lua` | ソース | isAssign、isLiteral関数を提供 |
| vm/init.lua | `script/vm/init.lua` | ソース | getRefs、isMetaFile関数を提供 |
| rename.lua | `script/core/rename.lua` | ソース | 参照検索を利用 |
| code-lens.lua | `script/core/code-lens.lua` | ソース | 参照数カウントに利用 |
