# 機能設計書 33-パラメータの前方移動

## 概要

本ドキュメントは、Clojure LSPの「パラメータの前方移動（drag-param-backward）」機能の設計仕様を記載する。この機能は、関数定義のパラメータを前方（左方向）に移動させ、同時にその関数のすべての呼び出し箇所の引数順序も自動的に更新するリファクタリング操作を提供する。

### 本機能の処理概要

**業務上の目的・背景**：関数のパラメータ順序を変更する必要が生じた場合、手動で行うとすべての呼び出し箇所を見つけて更新する必要があり、ミスが発生しやすい。本機能は、関数定義のパラメータ移動と同時に、プロジェクト全体の呼び出し箇所を自動的に更新することで、安全かつ確実なリファクタリングを実現する。

**機能の利用シーン**：この機能は以下の場面で利用される：
- 関数シグネチャの改善（より論理的なパラメータ順序への変更）
- 部分適用（partial）を容易にするためのパラメータ順序調整
- チーム間のAPI統一のための引数順序変更

**主要な処理内容**：
1. カーソル位置がdefn/defn-/defmacroのパラメータベクタ内にあることを確認
2. 可変長引数（&）を除外した移動対象を特定
3. 関数定義内のパラメータを前方に移動
4. プロジェクト全体の呼び出し箇所を検索
5. 各呼び出し箇所の引数を同様に前方に移動
6. スレッディングマクロ（->、->>）やpartial呼び出しを検出して警告

**関連システム・外部連携**：LSPプロトコルを通じてエディタと連携。clj-kondoの解析データベースを使用して呼び出し箇所を特定。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | エディタ画面 | 主画面 | コードアクションメニューから「Drag param backward」を選択 |

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| uri | string | Yes | 対象ファイルのURI | 有効なファイルURIであること |
| line | number | Yes | カーソル行（0-indexed） | 0以上の整数 |
| character | number | Yes | カーソル列（0-indexed） | 0以上の整数 |

### 入力データソース

- エディタからのLSP `workspace/executeCommand` リクエスト
- コマンド名: `drag-param-backward`

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| changes-by-uri | map | URI別のテキスト編集リスト（複数ファイルを含む可能性あり） |
| show-document-after-edit | map | 編集後に表示・フォーカスするドキュメントとカーソル位置 |

### 出力先

- LSPレスポンスとしてエディタに返却
- 複数ファイルの編集を含む場合がある

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ コマンドと引数を取得

2. パラメータベクタの特定
   └─ カーソル位置がdefn/defn-/defmacroのパラメータ内か確認
   └─ 対象外の場合はnilを返却

3. 可変長引数の除外
   └─ & 記号以降のパラメータを除外

4. 関数定義の編集
   └─ パラメータを前方に移動する編集を生成

5. 呼び出し箇所の収集
   └─ clj-kondoデータベースから参照を検索
   └─ 各ファイルのテキストを取得

6. 呼び出し箇所の編集
   └─ 各呼び出しで対応する引数を前方に移動
   └─ スレッディングマクロ内の場合はスキップフラグを設定

7. スキップ判定
   └─ スキップされた呼び出しがある場合は警告メッセージを表示しnil返却

8. 結果の返却
   └─ 全ファイルの編集をマージして返却
```

### フローチャート

```mermaid
flowchart TD
    A[コマンド受信] --> B{パラメータベクタ内?}
    B -->|No| C[nil返却]
    B -->|Yes| D{defn/defn-/defmacro?}
    D -->|No| C
    D -->|Yes| E[可変長引数除外]
    E --> F[関数定義の編集生成]
    F --> G[呼び出し箇所検索]
    G --> H{各呼び出しを処理}
    H --> I{スレッディング内?}
    I -->|Yes| J[スキップフラグ設定]
    I -->|No| K[引数の編集生成]
    J --> L{全呼び出し処理完了?}
    K --> L
    L -->|No| H
    L -->|Yes| M{スキップあり?}
    M -->|Yes| N[警告表示・nil返却]
    M -->|No| O[編集結果返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-33-01 | 対象関数 | defn、defn-、defmacroのパラメータのみ対象 | パラメータベクタ内で実行時 |
| BR-33-02 | 可変長引数除外 | &以降のパラメータは移動対象外 | 可変長引数を持つ関数 |
| BR-33-03 | 先頭パラメータ | 先頭パラメータは前方移動不可 | 先頭パラメータ選択時 |
| BR-33-04 | スレッディング検出 | ->、->>、partial、apply内の呼び出しは安全に変更不可 | スレッディングマクロ内 |
| BR-33-05 | 複数アリティ | 複数アリティ関数では対応するアリティの引数のみ更新 | 複数アリティ関数 |

### 計算ロジック

**移動対象インデックスの計算**：
```clojure
;; origin-clauseのインデックスから移動先を計算
clause-idx = (:idx origin-clause)
;; 呼び出し箇所では、このインデックス番目の引数を移動
```

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

本機能はclj-kondo解析データベースを参照のみ行う。

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 参照 | :analysis/:var-definitions | SELECT | 関数定義の位置を取得 |
| 参照 | :analysis/:var-usages | SELECT | 関数の呼び出し箇所を検索 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 警告メッセージ | スレッディングマクロ内の呼び出しが存在 | ユーザーに警告を表示しnil返却 |
| - | 操作不可 | パラメータベクタ外で実行 | nil返却 |
| - | 操作不可 | 先頭パラメータで前方移動を試行 | nil返却 |

### リトライ仕様

リトライは行わない。

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

複数ファイルの編集はエディタ側で単一のアンドゥ操作として扱われる。

## パフォーマンス要件

- 応答時間: 500ms以内（呼び出し箇所が多い場合は1秒以内）

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

- ファイルシステムへの書き込みは行わない
- プロジェクト全体の読み取りアクセスが必要

## 備考

- partialやapply等の高階関数呼び出しは安全に変換できないため、スキップされる
- マルチアリティ関数では、各アリティが独立して扱われる

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | drag_param.clj | `lib/src/clojure_lsp/feature/drag_param.clj` | param-establishing-symbolsを確認 |

**読解のコツ**: `param-establishing-symbols`は`'#{defn defn- defmacro}`を定義しており、パラメータ移動の対象関数を限定している。

**主要処理フロー**:
- **15-16行目**: 対象シンボルの定義

#### Step 2: コア機能を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | drag_param.clj | `lib/src/clojure_lsp/feature/drag_param.clj` | plan関数とusage-edit関数 |

**主要処理フロー**:
- **18-35行目**: `plan` - パラメータベクタの検証と可変長引数の除外
- **37-60行目**: `usage-edit` - 個々の呼び出し箇所の編集を生成
- **62-84行目**: `usage-edits` - 全呼び出し箇所の編集を収集
- **101-115行目**: `drag` - メイン処理（定義と呼び出しの編集をマージ）
- **95-99行目**: `warn-skipped-usages` - スキップ時の警告メッセージ

#### Step 3: 呼び出し箇所検索を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | queries.clj | `lib/src/clojure_lsp/queries.clj` | find-references関数 |

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

```
workspace/executeCommand (LSP)
    │
    └─ command/call-command
           │
           └─ run-command :drag-param-backward
                  │
                  └─ f.drag-param/drag-backward
                         │
                         ├─ plan
                         │     ├─ z/vector? 確認
                         │     ├─ param-establishing-symbols 確認
                         │     └─ 可変長引数除外
                         │
                         ├─ f.drag/identify-clauses
                         │
                         ├─ f.drag/drag-clause (定義の編集)
                         │
                         └─ usage-edits
                               │
                               ├─ q/find-references (呼び出し検索)
                               │
                               └─ usage-edit (各呼び出しの編集)
                                     │
                                     ├─ in-threading? 判定
                                     │
                                     └─ f.drag/node-edits
```

### データフロー図

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

URI, row, col      ──▶  plan                       ──▶  clause-spec
                         (パラメータ検証)

clause-spec        ──▶  identify-clauses           ──▶  clause-data
                         (句の特定)

clause-data        ──▶  drag-clause                ──▶  defn-edits
                         (定義の編集)

var-definition     ──▶  find-references            ──▶  var-usages
                         (呼び出し検索)

var-usages         ──▶  usage-edits                ──▶  usage-edits-by-uri
                         (呼び出しの編集)

defn-edits         ──▶  deep-merge                 ──▶  {:changes-by-uri {...}}
+ usage-edits            (結果マージ)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| drag_param.clj | `lib/src/clojure_lsp/feature/drag_param.clj` | ソース | パラメータ移動のコアロジック |
| drag.clj | `lib/src/clojure_lsp/feature/drag.clj` | ソース | 基本的なドラッグ機能 |
| clauses.clj | `lib/src/clojure_lsp/feature/clauses.clj` | ソース | 句の特定 |
| queries.clj | `lib/src/clojure_lsp/queries.clj` | ソース | 参照検索 |
| command.clj | `lib/src/clojure_lsp/feature/command.clj` | ソース | コマンドディスパッチ |
| code_actions.clj | `lib/src/clojure_lsp/feature/code_actions.clj` | ソース | コードアクション生成 |
| drag_param_test.clj | `lib/test/clojure_lsp/feature/drag_param_test.clj` | テスト | パラメータ移動のテスト |
