# 機能設計書 3-定義へジャンプ

## 概要

本ドキュメントは、Clojure LSP サーバーにおける定義へジャンプ機能の設計仕様を記載する。この機能は LSP プロトコルの `textDocument/definition` リクエストに対応し、シンボルの定義位置への移動を実現する。

### 本機能の処理概要

**業務上の目的・背景**：開発者がコードを読み解く際、変数や関数の定義位置を素早く確認することは極めて重要である。特に大規模なプロジェクトや、外部ライブラリを使用する場合、定義位置への即座の移動は開発効率を大幅に向上させる。本機能は、カーソル位置のシンボルから、その定義が記述されている位置（ファイル、行、列）を特定し、エディタのナビゲーション機能と連携する。

**機能の利用シーン**：開発者がエディタ上で変数名、関数名、名前空間、キーワード、Javaクラスなどのシンボルにカーソルを置き、「定義へジャンプ」コマンド（通常 F12 や Ctrl+Click）を実行した際に本機能が呼び出される。定義元がプロジェクト内の別ファイルや、依存ライブラリの jar 内にある場合でも対応する。

**主要な処理内容**：
1. カーソル位置のシンボル要素を特定
2. 要素のバケット（種類）に応じた定義検索ロジックの実行
3. 定義位置（URI、行、列）を Location オブジェクトとして返却

**関連システム・外部連携**：Java ソースデコンパイル機能（class ファイルからの定義取得時）

**権限による制御**：本機能に権限による実行制御はない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 本プロジェクトは LSP サーバー実装であり、UI 画面は存在しない。エディタの定義ジャンプ機能から呼び出される。 |

## 機能種別

データ検索処理 / ナビゲーション処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| text-document.uri | string | Yes | 対象ドキュメントの URI | 有効な file:// URI |
| position.line | integer | Yes | カーソル行位置（0-indexed） | 0 以上 |
| position.character | integer | Yes | カーソル列位置（0-indexed） | 0 以上 |

### 入力データソース

- clj-kondo による静的解析結果（db の :analysis）
- 依存グラフ（:dep-graph）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| uri | string | 定義位置のドキュメント URI |
| range.start.line | integer | 定義開始行（0-indexed） |
| range.start.character | integer | 定義開始列（0-indexed） |
| range.end.line | integer | 定義終了行（0-indexed） |
| range.end.character | integer | 定義終了列（0-indexed） |

### 出力先

LSP プロトコルを通じてエディタクライアントへ Location オブジェクトとして返却

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ handlers/definition が textDocument/definition を受信

2. カーソル位置の要素特定
   └─ q/find-element-under-cursor でカーソル下の要素を取得

3. 定義検索
   └─ q/find-definition (multimethod) で要素種別に応じた検索

4. 位置変換
   └─ element->location で Location オブジェクトに変換

5. レスポンス返却
   └─ uri と range を含む Location を返却
```

### フローチャート

```mermaid
flowchart TD
    A[definition リクエスト受信] --> B[find-element-under-cursor]
    B --> C{要素あり?}
    C -->|No| D[nil 返却]
    C -->|Yes| E{要素の bucket?}
    E -->|namespace-alias| F[namespace-usages として検索]
    E -->|namespace-usages| G[namespace-definitions 検索]
    E -->|var-usages| H[var-definitions 検索]
    E -->|local-usages| I[locals 検索]
    E -->|keyword-usages| J[keyword-definitions 検索]
    E -->|java-class-usages| K[java-class-definitions 検索]
    E -->|symbols| L[var-usages として検索]
    E -->|var-definitions| M[宣言/import 処理]
    E -->|その他| N[element をそのまま返却]
    F --> O[element->location]
    G --> O
    H --> O
    I --> O
    J --> O
    K --> O
    L --> O
    M --> O
    N --> O
    O --> P[Location 返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | マルチメソッド分岐 | 要素の :bucket に応じて異なる検索ロジックを適用 | 全定義検索 |
| BR-02 | フォールバック | 定義が見つからない場合は nil を返却 | 検索結果なし |
| BR-03 | 言語一致 | 可能な限り同じ言語（clj/cljs）の定義を優先 | 複数候補がある場合 |
| BR-04 | プロジェクト優先 | 内部（プロジェクト内）の定義を外部（依存）より優先 | 複数候補がある場合 |
| BR-05 | declare スキップ | declare による前方宣言は実際の定義に遷移 | var-definitions の場合 |

### 計算ロジック

- 定義検索: find-definition マルチメソッドにより、要素の :bucket に応じた検索を実行
- 位置変換: element の :name-row, :name-col, :name-end-row, :name-end-col から range を生成

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

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 要素検索 | db :analysis | SELECT | カーソル位置の要素を検索 |
| 定義検索 | db :analysis | SELECT | 要素種別に応じた定義を検索 |

### テーブル別操作詳細

#### db :analysis

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | 各バケット | uri, row, col でカーソル位置の要素特定 | find-element-under-cursor |
| SELECT | :namespace-definitions | :name でマッチング | 名前空間定義検索 |
| SELECT | :var-definitions | :ns, :name でマッチング | 変数定義検索 |
| SELECT | :keyword-definitions | :ns, :name でマッチング | キーワード定義検索 |
| SELECT | :java-class-definitions | :class でマッチング | Java クラス定義検索 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | nil 返却 | カーソル位置に要素がない | nil を返却 |
| - | nil 返却 | 定義が見つからない | nil を返却（エラーログ出力） |

### リトライ仕様

リトライは行わない。

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

本機能は読み取り専用であり、トランザクション管理は不要。

## パフォーマンス要件

- 応答時間: 通常 50ms 以内
- 依存グラフを活用して検索範囲を絞り込み、パフォーマンスを最適化

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

- 外部ネットワーク通信なし
- ファイルシステムアクセスは解析対象ファイルのみ

## 備考

- Java クラスの定義ジャンプ時、class ファイルの場合はデコンパイル機能と連携
- potemkin/import-vars で定義された変数は、元の名前空間の定義に遷移

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | queries.clj | `lib/src/clojure_lsp/queries.clj` | 要素の :bucket フィールドが要素種別を表すことを理解（254-256行目の defmulti） |

**読解のコツ**: Clojure の defmulti/defmethod パターンで、:bucket の値に応じた分岐処理を実現している。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | handlers.clj | `lib/src/clojure_lsp/handlers.clj` | definition 関数（288-294行目）が LSP リクエストのエントリーポイント |

**主要処理フロー**:
1. **290-291行目**: position を row, col に変換
2. **293行目**: q/find-definition-from-cursor を呼び出し
3. **294行目**: element->location で Location に変換

#### Step 3: 定義検索のマルチメソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | queries.clj | `lib/src/clojure_lsp/queries.clj` | find-definition defmulti（254-256行目）で分岐ポイントを確認 |
| 3-2 | queries.clj | `lib/src/clojure_lsp/queries.clj` | namespace-alias の定義検索（258-262行目） |
| 3-3 | queries.clj | `lib/src/clojure_lsp/queries.clj` | namespace-usages の定義検索（264-270行目） |
| 3-4 | queries.clj | `lib/src/clojure_lsp/queries.clj` | var-usages の定義検索（272-290行目） |
| 3-5 | queries.clj | `lib/src/clojure_lsp/queries.clj` | local-usages の定義検索（310-313行目） |
| 3-6 | queries.clj | `lib/src/clojure_lsp/queries.clj` | keyword-usages の定義検索（315-321行目） |
| 3-7 | queries.clj | `lib/src/clojure_lsp/queries.clj` | var-definitions の定義検索（323-344行目） |
| 3-8 | queries.clj | `lib/src/clojure_lsp/queries.clj` | java-class-usages の定義検索（354-380行目） |

**主要処理フロー**:
- **272-290行目**: var-usages の場合、:to と :name で var-definitions を検索。見つからなければ cljs マクロ、フォールバック、エイリアスからの名前空間定義を試行
- **323-344行目**: var-definitions の場合、potemkin/import-vars のハンドリングと declare スキップ処理

#### Step 4: 要素位置変換を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | handlers.clj | `lib/src/clojure_lsp/handlers.clj` | element->location（153-155行目）で要素を Location に変換 |
| 4-2 | shared.clj | `lib/src/clojure_lsp/shared.clj` | ->range 関数で range オブジェクト生成 |

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

```
handlers/definition
    │
    ├─ shared/position->row-col
    │
    └─ q/find-definition-from-cursor
           │
           ├─ q/find-element-under-cursor
           │
           └─ q/find-definition (multimethod)
                  │
                  ├─ :namespace-alias
                  │      └─ find-definition (namespace-usages として再帰)
                  │
                  ├─ :namespace-usages
                  │      └─ xf-analysis->namespace-definitions
                  │
                  ├─ :var-usages
                  │      ├─ xf-analysis->var-definitions
                  │      ├─ (fallback) :cljs マクロ検索
                  │      └─ (fallback) namespace 定義検索
                  │
                  ├─ :symbols
                  │      └─ find-definition (var-usages として再帰)
                  │
                  ├─ :local-usages
                  │      └─ locals から id で検索
                  │
                  ├─ :keyword-usages
                  │      └─ xf-analysis->keyword-definitions
                  │
                  ├─ :var-definitions
                  │      ├─ potemkin/import-vars 処理
                  │      └─ declare スキップ処理
                  │
                  ├─ :protocol-impls
                  │      └─ xf-analysis->var-definitions
                  │
                  ├─ :java-class-usages
                  │      ├─ xf-analysis->java-member-definitions
                  │      ├─ xf-analysis->java-class-definitions
                  │      └─ (fallback) defrecord 検索
                  │
                  └─ :default
                         └─ element をそのまま返却
```

### データフロー図

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

textDocument/definition ──▶ handlers/definition ──▶ Location
  - uri                          │
  - position (line, char)        ▼
                            find-definition-from-cursor
                                 │
                                 ├──▶ find-element-under-cursor
                                 │      └─ db :analysis[uri]
                                 │
                                 ├──▶ find-definition (multimethod)
                                 │      └─ db :analysis (各バケット)
                                 │
                                 └──▶ element->location
                                        │
                                        ▼
                                   Location {uri, range}
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| handlers.clj | `lib/src/clojure_lsp/handlers.clj` | ソース | LSP リクエストハンドラー（definition 関数） |
| queries.clj | `lib/src/clojure_lsp/queries.clj` | ソース | 定義検索のマルチメソッド（find-definition） |
| shared.clj | `lib/src/clojure_lsp/shared.clj` | ソース | 位置変換ユーティリティ（->range） |
| java_interop.clj | `lib/src/clojure_lsp/feature/java_interop.clj` | ソース | Java クラス定義の URI 変換 |
| dep_graph.clj | `lib/src/clojure_lsp/dep_graph.clj` | ソース | 依存グラフによる検索範囲最適化 |
| handlers_test.clj | `lib/test/clojure_lsp/handlers_test.clj` | テスト | ユニットテスト |
| definition_test.clj | `cli/integration-test/integration/definition_test.clj` | テスト | 統合テスト |
