# 機能設計書 39-関数作成提案

## 概要

本ドキュメントは、Clojure LSPの「関数作成提案」機能の設計仕様を記載する。この機能は、未解決のシンボルに対して、新しい関数の作成を提案・実行するクイックフィックス操作を提供する。

### 本機能の処理概要

**業務上の目的・背景**：テスト駆動開発（TDD）やトップダウン開発を行う際、まだ存在しない関数を呼び出すコードを先に書くことがある。clj-kondoは`unresolved-symbol`として警告を出すが、関数のスケルトンを手動で作成するのは面倒である。本機能は、呼び出し箇所から関数シグネチャを推測し、関数のスケルトンを自動生成することで、開発フローを効率化する。

**機能の利用シーン**：この機能は以下の場面で利用される：
- TDDでテストを先に書いてから実装する場合
- トップダウン設計で呼び出し側を先に書く場合
- 別の名前空間に新しい関数を追加する場合

**主要な処理内容**：
1. 未解決シンボルが関数呼び出しの位置にあるか判定
2. 呼び出しコンテキストから引数を推測
3. プライベート関数または公開関数のスケルトンを生成
4. 別の名前空間への関数追加もサポート

**関連システム・外部連携**：LSPプロトコルを通じてエディタと連携。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | エディタ画面 | 主画面 | クイックフィックスメニューから「Create function」を選択 |

## 機能種別

コードアクション（クイックフィックス）

## 入力仕様

### 入力パラメータ

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

### 入力データソース

- エディタからのLSP `textDocument/codeAction` リクエスト
- コマンド名: `create-function`

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| edits | vector | 関数定義の追加編集 |
| changes-by-uri | map | 複数ファイルへの編集（公開関数作成時） |
| resource-changes | vector | ファイル作成（新規名前空間の場合） |
| show-document-after-edit | map | 編集後にフォーカスするドキュメント |

### 出力先

- LSPレスポンスとしてエディタに返却

## 処理フロー

### 処理シーケンス

```
1. シンボルの解析
   └─ 未解決シンボルの取得
   └─ 修飾子（エイリアス）の有無を確認

2. 呼び出しコンテキストの解析
   └─ 引数の数と名前を推測
   └─ スレッディングマクロ内かどうかを判定

3. 関数タイプの決定
   └─ プライベート関数（同一ファイル）
   └─ 公開関数（別名前空間）

4. 関数スケルトンの生成
   └─ defn/defn- の生成
   └─ パラメータリストの生成

5. 挿入位置の決定
   └─ 現在のトップレベルフォームの前に挿入

6. 結果の返却
   └─ 編集操作を返却
```

### フローチャート

```mermaid
flowchart TD
    A[クイックフィックス要求] --> B[シンボル解析]
    B --> C{修飾子あり?}
    C -->|Yes| D{名前空間存在?}
    C -->|No| E[プライベート関数作成]
    D -->|Yes| F[公開関数作成]
    D -->|No| G[名前空間と関数を作成]
    E --> H[スケルトン生成]
    F --> H
    G --> H
    H --> I[挿入位置決定]
    I --> J[編集返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-39-01 | プライベート関数 | 修飾子なしのシンボルはdefn-で作成 | 同一ファイル内 |
| BR-39-02 | 公開関数 | 修飾子付きシンボルはdefnで作成 | 別名前空間 |
| BR-39-03 | 引数推測 | 呼び出しの引数から名前を推測 | シンボル引数の場合 |
| BR-39-04 | スレッディング対応 | ->や->>内では暗黙の引数を考慮 | スレッディングマクロ内 |
| BR-39-05 | 名前空間作成 | 存在しない名前空間への関数追加時はファイルも作成 | 新規名前空間の場合 |

### 計算ロジック

**引数名の推測**：
```clojure
;; シンボル引数からパラメータ名を生成
;; シンボルでない場合は arg1, arg2, ... を使用
(create-function-param node index)
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 参照 | :analysis | SELECT | 名前空間エイリアスを検索 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 操作不可 | 関数呼び出し位置でない | nil返却 |
| - | 外部エラー | 外部ライブラリの名前空間 | 処理をスキップ |

### リトライ仕様

リトライは行わない。

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

トランザクション管理は不要。

## パフォーマンス要件

- 応答時間: 100ms以内

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

- ファイル作成はresource-changesとしてエディタに委譲

## 備考

- partial呼び出し内での関数作成にも対応
- use-metadata-for-privacy?設定に応じてdefn ^:private形式を使用

---

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

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

### 推奨読解順序

#### Step 1: 関数作成可否の判定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | can-create-function? |

**主要処理フロー**:
- **1030-1032行目**: `can-create-function?` - 作成可否判定

#### Step 2: 公開関数の作成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | find-public-function-to-create |

**主要処理フロー**:
- **1034-1058行目**: `find-public-function-to-create` - 公開関数の情報を抽出

#### Step 3: 関数スケルトンの生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | create-function |

**主要処理フロー**:
- **1060-1068行目**: `create-function-param` - パラメータ名の生成
- **1070-1112行目**: `create-function-for-alias` - 別名前空間への関数作成
- **1339-1387行目**: `create-function` - メイン処理

#### Step 4: defnの生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | new-defn-zloc |

**主要処理フロー**:
- **384-407行目**: `new-defn-zloc` - defn構文ツリーの生成

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

```
textDocument/codeAction (LSP)
    │
    └─ code-actions/all
           │
           ├─ find-private-function-to-create
           │     └─ can-create-function?
           │
           └─ find-public-function-to-create
                 │
                 └─ [ユーザー選択]
                        │
                        └─ command/run-command :create-function
                              │
                              └─ r.transform/create-function
                                    │
                                    ├─ create-function-param
                                    │
                                    ├─ new-defn-zloc
                                    │
                                    ├─ prepend-preserving-comment
                                    │
                                    └─ create-function-for-alias (別ns時)
```

### データフロー図

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

未解決シンボル      ──▶  can-create-function?       ──▶  boolean
                         (作成可否判定)

シンボル           ──▶  find-public-function-to-create ──▶  {:ns, :name}
                         (公開関数情報)

呼び出し引数       ──▶  create-function-param      ──▶  パラメータ名
                         (パラメータ推測)

関数情報           ──▶  new-defn-zloc              ──▶  defn zloc
                         (スケルトン生成)

defn zloc          ──▶  prepend-preserving-comment  ──▶  [{:range, :loc}]
                         (挿入位置決定)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | ソース | 関数作成のコアロジック |
| code_actions.clj | `lib/src/clojure_lsp/feature/code_actions.clj` | ソース | コードアクション生成 |
| command.clj | `lib/src/clojure_lsp/feature/command.clj` | ソース | コマンドディスパッチ |
| add_missing_libspec.clj | `lib/src/clojure_lsp/feature/add_missing_libspec.clj` | ソース | require追加（公開関数作成時） |
