# 機能設計書 19-インライン化

## 概要

本ドキュメントは、clojure-lspのインライン化（inline-symbol）機能の設計を記述する。この機能はシンボル（変数や定義）をその定義値で置換し、定義自体を削除するリファクタリング機能である。

### 本機能の処理概要

インライン化機能は、letバインディングまたはdefで定義されたシンボルを、その定義値で全ての参照箇所を置換する。

**業務上の目的・背景**：コードの簡素化やリファクタリングにおいて、不要な中間変数を削除したり、一度しか使用されない定義をインライン化することは一般的なパターンである。本機能により、手動でコードを書き換える手間を省き、素早くシンボルをインライン化できる。

**機能の利用シーン**：
- 一度しか使用されない変数を削除したい場合
- 中間変数を減らしてコードを簡素化したい場合
- リファクタリングの一環として定義を展開したい場合
- 関数の抽出の逆操作として

**主要な処理内容**：
1. カーソル位置のシンボルの定義を特定
2. 定義タイプ（let/def）を判別
3. シンボルの全参照箇所を取得
4. 各参照箇所を定義値で置換
5. 定義自体を削除

**関連システム・外部連携**：clj-kondoの解析結果を使用して定義と参照を検出する。

**権限による制御**：特になし。すべてのユーザーが利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| N/A | エディタ | 主画面 | LSPクライアント（VS Code等）からコードアクションまたはコマンドとして実行 |

## 機能種別

リファクタリング / コード変換

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| uri | string | Yes | 対象ファイルのURI | file://形式のURI |
| row | integer | Yes | カーソル位置の行番号（1-indexed） | 正の整数 |
| col | integer | Yes | カーソル位置の列番号（1-indexed） | 正の整数 |

### 入力データソース

- LSPクライアントからのworkspace/executeCommandリクエスト（inline-symbolコマンド）
- コードアクションから実行

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| changes-by-uri | map | URI別の編集リスト |

### 出力先

- LSPクライアントへWorkspaceEditとして返却

## 処理フロー

### 処理シーケンス

```
1. 定義の特定
   └─ inline-dataで定義情報を取得

2. 定義タイプの判別
   └─ def または let を判別

3. 参照の取得
   └─ q/find-referencesで全参照を取得

4. 参照の置換
   └─ 各参照を定義値で置換

5. 定義の削除
   └─ inline-def または inline-let-binding を実行

6. 編集結果の生成
   └─ changes-by-uriマップを返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[inline-dataで定義を取得]
    B --> C{定義が存在?}
    C -->|No| D[nil返却]
    C -->|Yes| E[q/find-references]
    E --> F{def-op判定}
    F -->|def| G[inline-def]
    F -->|let| H[inline-let-binding]
    G --> I[参照を定義値で置換]
    H --> I
    I --> J[定義を削除]
    J --> K[changes-by-uri生成]
    K --> L[終了]
    D --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 対象シンボル | :locals（let）または:var-definitions（def）のみ対象 | bucket判定 |
| BR-02 | 複数ファイル対応 | defの参照は複数ファイルにまたがる可能性あり | changes-by-uri形式 |
| BR-03 | 単一let削除 | letの最後のバインディングを削除する場合はletフォーム全体を置換 | inline-sole-let-binding |
| BR-04 | 複数let削除 | 複数バインディングのletから1つを削除 | inline-one-let-binding |
| BR-05 | implicit do | 単一のボディ式の場合、doでラップしない | one-child?判定 |

### 計算ロジック

- 削除範囲: 前のノードの終端から定義の終端まで
- implicit do判定: `establishes-implicit-do?`で囲む形式を確認

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

本機能はデータベース（db）を読み取り専用で使用する。

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 定義検出 | :analysis | SELECT | q/find-definition-from-cursorで使用 |
| 参照検出 | :analysis | SELECT | q/find-referencesで使用 |

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

#### :analysis

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | :locals, :var-definitions | uri, row, colで検索 | 定義の特定 |
| SELECT | :var-usages, :local-usages | 定義に対する参照 | 参照の取得 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| N/A | nil返却 | 対象シンボルが見つからない | nilを返却（何もしない） |
| N/A | nil返却 | インライン化できない定義タイプ | nilを返却 |

### リトライ仕様

特になし。同期的に1回のみ実行。

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

- クライアントに編集結果を返却するのみで、サーバー側でのトランザクション管理は不要
- 複数ファイルの編集は単一のWorkspaceEditで処理

## パフォーマンス要件

- 参照検索と複数ファイル編集を含むが、通常のプロジェクトサイズでは即時完了

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

- ファイルシステムへの直接書き込みは行わない（LSP経由でクライアントに委譲）

## 備考

- 変換例（letの場合）:
  - 入力:
    ```clojure
    (let [a 1
          b (inc a)]
      (+ a b))
    ```
  - インライン化: `b`
  - 出力:
    ```clojure
    (let [a 1]
      (+ a (inc a)))
    ```
- 変換例（defの場合）:
  - 入力:
    ```clojure
    (def x 42)
    (println x)
    ```
  - インライン化: `x`
  - 出力:
    ```clojure
    (println 42)
    ```

---

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

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

### 推奨読解順序

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

処理の起点となる関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | command.clj | `lib/src/clojure_lsp/feature/command.clj` | run-command :inline-symbol（98-99行目） |
| 1-2 | inline_symbol.clj | `lib/src/clojure_lsp/feature/inline_symbol.clj` | inline-symbol関数（146-152行目） |

**主要処理フロー**:
1. **147行目**: `inline-data`で定義情報を取得
2. **148行目**: `q/find-references`で参照を取得
3. **149-152行目**: def-opに応じてinline-defまたはinline-let-bindingを呼び出し

#### Step 2: 定義情報の取得を理解する

inline-data関数のロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | inline_symbol.clj | `lib/src/clojure_lsp/feature/inline_symbol.clj` | inline-data関数（17-27行目） |

**主要処理フロー**:
- **18行目**: `q/find-definition-from-cursor`で定義を取得
- **19-20行目**: bucket判定（:locals または :var-definitions）
- **23行目**: edit/find-opで定義の種類（let/def）を取得

#### Step 3: def のインライン化を理解する

inline-def関数のロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | inline_symbol.clj | `lib/src/clojure_lsp/feature/inline_symbol.clj` | inline-def関数（44-59行目） |

**主要処理フロー**:
- **49-51行目**: 前のノードまたは開始位置を取得
- **57行目**: def定義を削除
- **58-59行目**: `merge-edits`と`ref-replacements`で参照を置換

#### Step 4: let のインライン化を理解する

inline-let-binding関数とその補助関数を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | inline_symbol.clj | `lib/src/clojure_lsp/feature/inline_symbol.clj` | inline-let-binding関数（135-141行目） |
| 4-2 | inline_symbol.clj | `lib/src/clojure_lsp/feature/inline_symbol.clj` | inline-sole-let-binding関数（116-133行目） |
| 4-3 | inline_symbol.clj | `lib/src/clojure_lsp/feature/inline_symbol.clj` | inline-one-let-binding関数（61-73行目） |

**主要処理フロー**:
- **137-138行目**: letの最後のバインディングかどうかを判定
- **140行目**: 最後なら`inline-sole-let-binding`
- **141行目**: そうでなければ`inline-one-let-binding`

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

```
handlers/execute-command
    │
    └─ f.command/call-command
           │
           └─ run-command :inline-symbol
                  │
                  └─ f.inline-symbol/inline-symbol
                         │
                         ├─ inline-data
                         │      ├─ q/find-definition-from-cursor
                         │      └─ edit/find-op
                         │
                         ├─ q/find-references
                         │
                         └─ (def-op = 'def)
                                ├─ inline-def
                                │      ├─ delete-between
                                │      └─ ref-replacements
                                │
                                └─ inline-let-binding
                                       ├─ (sole binding)
                                       │      └─ inline-sole-let-binding
                                       │             ├─ replace-refs
                                       │             └─ let削除
                                       │
                                       └─ (multiple bindings)
                                              └─ inline-one-let-binding
                                                     └─ ref-replacements
```

### データフロー図

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

uri, row, col ────────┬─> inline-data ──────────> def-elem, def-zloc, def-op
                      │
db[:analysis] ────────┴─> q/find-references ───> references
                              │
def-op ───────────────────────┼─> (分岐)
                              │
(def)                         ├─> inline-def
                              │       ├─> delete-between (定義削除)
                              │       └─> ref-replacements (参照置換)
                              │
(let)                         └─> inline-let-binding
                                      ├─> inline-sole-let-binding
                                      │       └─> letフォーム置換
                                      └─> inline-one-let-binding
                                              └─> バインディング削除
                                                      │
                                                      └─> {:changes-by-uri {...}}
                                                               │
                                                               └─> WorkspaceEdit
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| inline_symbol.clj | `lib/src/clojure_lsp/feature/inline_symbol.clj` | ソース | インライン化のメインロジック |
| command.clj | `lib/src/clojure_lsp/feature/command.clj` | ソース | コマンドディスパッチャー |
| code_actions.clj | `lib/src/clojure_lsp/feature/code_actions.clj` | ソース | コードアクション提供 |
| queries.clj | `lib/src/clojure_lsp/queries.clj` | ソース | 定義・参照検出クエリ |
| edit.clj | `lib/src/clojure_lsp/refactor/edit.clj` | ソース | ジッパー操作ユーティリティ |
| inline_symbol_test.clj | `lib/test/clojure_lsp/feature/inline_symbol_test.clj` | テスト | 単体テスト |
