# 機能設計書 15-実装へ移動 (textDocument/implementation)

## 概要

本ドキュメントは、Lua Language Serverにおける「実装へ移動」機能の設計を記述する。この機能は、LSPの`textDocument/implementation`リクエストに対応し、インターフェースの実装位置へジャンプする機能を提供する。

### 本機能の処理概要

実装へ移動機能は、カーソル位置のシンボルの「実装」を検索し、その位置情報を返す機能である。Luaには明示的なインターフェースの概念はないが、この機能は`vm.getRefs`を使用して代入（assign）操作を検索し、実際に値が割り当てられている箇所を返す。

**業務上の目的・背景**：オブジェクト指向スタイルのLuaコードでは、メソッドの宣言と実装が分離されている場合がある。また、抽象的な型定義と具体的な実装が別の場所にある場合もある。この機能により、宣言から実装箇所へ素早く移動でき、コードの理解と保守が効率化される。

**機能の利用シーン**：
- メソッド宣言から実際の実装を確認したい場合
- 型定義から具体的な代入箇所を確認したい場合
- フィールド宣言から値が設定されている箇所を確認したい場合

**主要な処理内容**：
1. カーソル位置のソースノードを特定
2. `vm.getRefs`で全参照を取得
3. `guide.isAssign`で代入操作のみをフィルタ
4. ドキュメントアノテーション系のノードを除外
5. 結果をソートして重複を除去
6. `@source`アノテーションがある場合は外部ファイルパスを解決

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

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 7 | 実装へ移動 | 主機能 | インターフェースの実装位置へジャンプする主処理 |

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| uri | uri | Yes | 対象ファイルのURI | 有効なファイルURI |
| offset | integer | Yes | カーソルのオフセット位置 | 正の整数 |

### 入力データソース

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

## 出力仕様

### 出力データ

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

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. ASTを取得
   └─ files.getState(uri)でファイル状態を取得
2. カーソル位置のソースを特定
   └─ findSource(ast, offset, accept)で該当ノードを検索
   └─ convertIndex()でインデックスアクセスを親に変換
3. vm.getRefsで参照を取得
   └─ ソースノードの全参照を収集
4. 代入操作のみをフィルタリング
   └─ guide.isAssign()で代入かどうか判定
   └─ global型、self、doc系ノードを除外
5. 結果をソート
   └─ URI順、開始位置順でソート
   └─ ネストした結果は範囲が小さい方を優先
6. 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[vm.getRefs実行]
    G --> H[各参照をループ]
    H --> I{代入操作か?}
    I -->|No| H
    I -->|Yes| J{除外対象?}
    J -->|Yes| H
    J -->|No| K[結果に追加]
    K --> L{全参照処理完了?}
    L -->|No| H
    L -->|Yes| M{結果あり?}
    M -->|No| D
    M -->|Yes| N[結果をソート]
    N --> O[jumpSource処理]
    O --> P[結果を返す]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 代入のみ | guide.isAssign()がtrueの参照のみを採用 | フィルタリング時 |
| BR-02 | global除外 | type='global'のノードは除外 | フィルタリング時 |
| BR-03 | self除外 | type='self'のノードは除外 | フィルタリング時 |
| BR-04 | doc型除外 | doc.type.function、doc.type.table等のドキュメントノードは除外 | フィルタリング時 |
| BR-05 | doc定義除外 | doc.class、doc.alias、doc.enum、doc.type.field、doc.class.name等は除外 | フィルタリング時 |
| BR-06 | ネスト優先 | 同一URI内でネストした結果は範囲が小さい方を優先 | ソート処理時 |

### 計算ロジック

代入判定（guide.isAssign）:
```lua
-- 以下の型が代入として判定される
-- setlocal, local, setglobal, setfield, setmethod, setindex, tablefield, tableindex
```

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

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

## エラー処理

### エラーケース一覧

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

### リトライ仕様

リトライは行わない。

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

該当なし

## パフォーマンス要件

- `vm.getRefs`は非同期処理（@async）で実行
- 結果のソートはO(n log n)
- ネスト除去は線形時間O(n)
- LSPの応答性を維持するためprogress表示（0.5秒以上の処理時）

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

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

## 備考

- Luaには明示的なインターフェースの概念がないため、「実装」は「代入操作」として解釈される
- 「定義へ移動」は宣言を、「実装へ移動」は代入を返す
- メタファイルの実装は対象外となる場合がある

---

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

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

### 推奨読解順序

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

実装検索の結果構造を理解する。

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

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

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

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

**主要処理フロー**:
1. **81-84行目**: AST取得、存在しなければnil
2. **86-89行目**: ソースノード特定、存在しなければnil
3. **93行目**: vm.getRefsで参照取得
4. **95-159行目**: 各参照のフィルタリング
5. **161-167行目**: 結果のソートとjumpSource処理

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | implementation.lua | `script/core/implementation.lua` | isAssignチェック（97-99行目） |
| 3-2 | implementation.lua | `script/core/implementation.lua` | 除外条件（100-152行目） |
| 3-3 | guide.lua | `script/parser/guide.lua` | isAssign関数の定義 |

**主要な除外条件**:
- global型（100-102行目）
- self型（107-109行目）
- doc.type系（122-128行目）
- doc.class、doc.alias、doc.enum（129-137行目）

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

```
provider.lua ('textDocument/implementation' ハンドラ)
    │
    └─ implementation.lua (メイン関数)
           │
           ├─ files.getState() [AST取得]
           ├─ findSource() [ソースノード特定]
           ├─ convertIndex() [インデックス変換]
           ├─ vm.getRefs() [参照取得]
           ├─ guide.isAssign() [代入判定]
           ├─ sortResults() [ソート処理]
           └─ jumpSource() [@source解決]
```

### データフロー図

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

URI ─────────────────────┐
                         │
オフセット位置 ───────────┼──▶ implementation() ──▶ results[]
                         │         │
                         │         ▼
                         │   ┌────────────────┐
                         │   │ ソースノード特定 │
                         │   └────────────────┘
                         │         │
                         │         ▼
                         │   ┌────────────────┐
                         │   │  vm.getRefs    │
                         │   └────────────────┘
                         │         │
                         │         ▼
                         │   ┌────────────────┐
                         │   │ 代入フィルタ    │
                         │   │ (isAssign=true) │
                         │   └────────────────┘
                         │         │
                         │         ▼
                         │   ┌────────────────┐
                         │   │ 除外フィルタ    │
                         │   │ (global, self, │
                         │   │  doc系除外)    │
                         │   └────────────────┘
                         │         │
                         │         ▼
                         └─ [{ target, uri, source }]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| implementation.lua | `script/core/implementation.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関数を提供 |
| vm/init.lua | `script/vm/init.lua` | ソース | getRefs関数を提供 |
