# 機能設計書 24-分割代入

## 概要

本ドキュメントは、clojure-lspの「分割代入」機能（destructure-keysコマンド）の設計仕様を定義する。この機能は、ローカル変数へのマップアクセスを分割代入（destructuring）形式に自動変換するリファクタリング機能を提供する。

### 本機能の処理概要

分割代入機能は、マップから特定のキーを取得しているローカル変数の使用箇所を解析し、それらを分割代入形式（{:keys [...]}など）に変換する。例えば、`(let [m data] (:a m) (:b m))`を`(let [{:keys [a b]} data] a b)`に変換する。

**業務上の目的・背景**：Clojureでは、マップから複数のキーを取得する際、分割代入を使用することでコードが簡潔になり可読性が向上する。手動での分割代入への書き換えは、使用箇所の特定と変換に手間がかかるため、この機能により効率的なリファクタリングが可能になる。

**機能の利用シーン**：
- letバインディングでマップを受け取り、複数のキーにアクセスしているコードを簡潔にしたい場合
- 関数の引数でマップを受け取り、内部で複数のキーを使用しているコードをリファクタリングしたい場合
- コードレビューで分割代入の使用を推奨された場合
- 既存コードの可読性を向上させたい場合

**主要な処理内容**：
1. カーソル位置のローカル変数定義を特定
2. そのローカル変数の使用箇所を検索
3. 各使用箇所がキーワードアクセス（`(:key m)`）またはシンボルアクセス（`('sym m)`）かを判定
4. 分割代入可能なアクセスパターンを収集
5. {:keys [...]}、{:syms [...]}などの分割代入形式を生成
6. 元の変数定義と使用箇所を置換

**関連システム・外部連携**：LSPプロトコルを通じてエディタと連携し、コードアクションまたはコマンドとして実行される。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 本プロジェクトはLSPサーバーであり、UI画面は存在しない。エディタのコードアクションメニューから呼び出される。 |

## 機能種別

リファクタリング（コード変換処理）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| zloc | zipper location | Yes | カーソル位置のzipperロケーション | ローカル変数定義上にあること |
| uri | string | Yes | 対象ファイルのURI | 有効なURI形式 |
| db | database | Yes | LSPデータベース | - |

### 入力データソース

- エディタから送信されるLSPリクエスト
- ドキュメントのパース結果（rewrite-clj zipper）
- clj-kondo解析データ（ローカル変数使用箇所の検索）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| range | map | 変更対象範囲（:row, :col, :end-row, :end-col） |
| loc | zipper location | 変換後のノード |

### 出力先

LSPプロトコルを通じてエディタに返却され、テキスト編集として適用される。

## 処理フロー

### 処理シーケンス

```
1. ローカル変数の特定
   └─ local-to-destructure関数でローカル変数定義を検索
2. 分割代入済みチェック
   └─ 既に{:keys [...]}などの分割代入内にある場合は対象外
3. 使用箇所の検索
   └─ q/find-referencesで全使用箇所を検索
4. 使用パターンの解析
   └─ usage-datum関数で各使用箇所のアクセスパターンを判定
5. 分割代入形式の生成
   └─ :keys、:symsなどのキーでグループ化
6. 既存の分割代入とのマージ
   └─ :asがある場合は既存の分割代入と統合
7. コードの置換
   └─ 元の定義と使用箇所を新しい形式で置換
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{ローカル変数?}
    B -->|No| C[nil返却]
    B -->|Yes| D{既に分割代入?}
    D -->|Yes| C
    D -->|No| E[使用箇所検索]
    E --> F[使用パターン解析]
    F --> G{分割代入可能?}
    G -->|No| C
    G -->|Yes| H[:keys/:symsでグループ化]
    H --> I{全使用箇所が分割代入可能?}
    I -->|Yes| J[分割代入のみ生成]
    I -->|No| K[分割代入 + :as 生成]
    J --> L[コード置換]
    K --> L
    L --> M[結果返却]
    M --> N[終了]
    C --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | キーワードアクセス | (:key m) 形式を {:keys [key]} に変換 | キーワードが関数位置にある場合 |
| BR-002 | シンボルアクセス | ('sym m) 形式を {:syms [sym]} に変換 | クォートされたシンボルが関数位置にある場合 |
| BR-003 | 部分分割代入 | 一部の使用箇所のみ分割代入可能な場合、:asで元の変数も保持 | 分割代入不可の使用箇所がある場合 |
| BR-004 | 既存分割代入マージ | :asで既に分割代入されている変数は、既存の分割代入に追加 | :as指定のローカル変数の場合 |
| BR-005 | 名前空間修飾キーワード | ::keyや:ns/keyは、そのまま:keysに含める | 修飾キーワードアクセスの場合 |

### 計算ロジック

特になし。

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

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

本機能はデータベース操作を行わない。clj-kondo解析データの読み取りのみ。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 暗黙的エラー | ローカル変数でない場合 | nil返却 |
| - | 暗黙的エラー | 分割代入可能な使用箇所がない場合 | nil返却 |

### リトライ仕様

リトライは不要。

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

該当なし（メモリ上の操作のみ）。

## パフォーマンス要件

使用箇所の検索を含め、1秒以内に完了すること。

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

特になし。ローカルファイルの操作のみ。

## 備考

- 分割代入の順序はアクセス順ではなくキーの順序で並ぶ
- :or（デフォルト値）は本機能では生成されない

---

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

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

### 推奨読解順序

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

分割代入のデータ構造と使用パターンの判定ロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | destructure_keys.clj | `lib/src/clojure_lsp/feature/destructure_keys.clj` | usage-datum関数（42-70行目）で使用パターンの判定ロジック |

**読解のコツ**: usage-datumは各使用箇所を解析し、:destructure?、:destructure-key（:keys or :syms）、:local、:replacing-locを含むマップを返す。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | command.clj | `lib/src/clojure_lsp/feature/command.clj` | destructure-keysコマンドの定義（53-54行目） |
| 2-2 | code_actions.clj | `lib/src/clojure_lsp/feature/code_actions.clj` | destructure-keys-actionでUIアクション生成（182-187行目） |

**主要処理フロー**:
1. **53-54行目**: run-commandのdestructure-keysメソッドがf.destructure-keys/destructure-keysを呼び出し

#### Step 3: 変換処理の実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | destructure_keys.clj | `lib/src/clojure_lsp/feature/destructure_keys.clj` | local-to-destructure（21-37行目）で分割代入対象を特定 |
| 3-2 | destructure_keys.clj | `lib/src/clojure_lsp/feature/destructure_keys.clj` | can-destructure-keys?（39-40行目）で可能性判定 |
| 3-3 | destructure_keys.clj | `lib/src/clojure_lsp/feature/destructure_keys.clj` | destructure-keys（89-118行目）でメイン処理 |

**主要処理フロー**:
- **21-37行目**: local-to-destructure関数でローカル変数定義を特定し、既存の分割代入状態を確認
- **42-70行目**: usage-datum関数で使用箇所のパターンを解析
- **72-87行目**: merge-destructuring関数で既存の分割代入とマージ
- **89-118行目**: destructure-keys関数で全体の処理を実行
- **95行目**: destructure?でフィルタして分割代入可能な使用箇所のみ処理
- **106-108行目**: :asの追加判定（すべての使用箇所が分割代入可能でない場合）

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

```
call-command (command.clj)
    │
    └─ run-command :destructure-keys (command.clj:53-54)
           │
           └─ f.destructure-keys/destructure-keys (destructure_keys.clj:89-118)
                  │
                  ├─ local-to-destructure (destructure_keys.clj:21-37)
                  │      ├─ q/find-definition-from-cursor
                  │      └─ loc-destructuring-key
                  │
                  ├─ q/find-references
                  │
                  ├─ usage-datum (destructure_keys.clj:42-70)
                  │      └─ キーワード/シンボルアクセスパターン判定
                  │
                  ├─ merge-destructuring (destructure_keys.clj:72-87)
                  │
                  └─ z/of-node n/coerce
```

### データフロー図

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

LSPリクエスト ───▶ zloc取得 ───▶ local-to-destructure ───▶ 使用箇所検索 ───▶ パターン解析 ───▶ 分割代入生成 ───▶ TextEdit
(uri, pos)                              │                      │
                                        └─ 定義取得            └─ :keys/:symsグループ化
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| destructure_keys.clj | `lib/src/clojure_lsp/feature/destructure_keys.clj` | ソース | 分割代入変換処理の実装 |
| command.clj | `lib/src/clojure_lsp/feature/command.clj` | ソース | コマンドディスパッチ |
| code_actions.clj | `lib/src/clojure_lsp/feature/code_actions.clj` | ソース | コードアクションUI生成 |
| queries.clj | `lib/src/clojure_lsp/queries.clj` | ソース | ローカル変数使用箇所の検索 |
| destructure_keys_test.clj | `lib/test/clojure_lsp/feature/destructure_keys_test.clj` | テスト | 分割代入変換のテスト |
