# 機能設計書 9-リネーム

## 概要

本ドキュメントは、Clojure LSP サーバーにおけるリネーム機能の設計仕様を記載する。この機能は LSP プロトコルの `textDocument/rename` リクエストに対応し、シンボル名の一括変更（変数、関数、名前空間、キーワードに対応）を実現する。

### 本機能の処理概要

**業務上の目的・背景**：ソフトウェア開発において、変数名や関数名の変更は頻繁に発生する作業である。手動での変更は漏れや誤りが発生しやすく、特に大規模なプロジェクトでは影響範囲の把握が困難である。本機能は、シンボルの全ての参照箇所を自動的に特定し、一括で変更することで、安全かつ効率的なリファクタリングを支援する。

**機能の利用シーン**：開発者がシンボルにカーソルを置き、「名前の変更」コマンドを実行し、新しい名前を入力すると、プロジェクト全体で該当シンボルの全使用箇所が一括で変更される。名前空間のリネームの場合は、ファイル名の変更も伴う。

**主要な処理内容**：
1. カーソル位置のシンボル要素を特定
2. シンボルの定義と全参照を取得
3. 各参照箇所の編集内容を計算
4. 名前空間の場合はファイル名変更も含む
5. WorkspaceEdit として返却

**関連システム・外部連携**：ファイルシステム（名前空間リネーム時のファイル変更）

**権限による制御**：本機能に権限による実行制御はない。クライアントのワークスペース編集機能サポートが必要。

## 関連画面

| 画面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 以上 |
| new-name | string | Yes | 新しいシンボル名 | 空文字列でない |

### 入力データソース

- clj-kondo による静的解析結果（db の :analysis）
- ドキュメントバージョン情報（db の :documents）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| document-changes | TextDocumentEdit[] | 各ファイルの編集内容 |
| [].text-document | VersionedTextDocumentIdentifier | 対象ドキュメント |
| [].edits | TextEdit[] | 編集内容 |
| (名前空間の場合) | RenameFile | ファイル名変更 |

### 出力先

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

## 処理フロー

### 処理シーケンス

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

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

3. リネーム可否判定
   └─ rename-status で各種条件をチェック

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

5. 編集内容計算
   └─ rename-changes で各参照の編集を計算

6. 名前空間の場合
   └─ ファイル名変更情報を追加

7. レスポンス返却
   └─ WorkspaceEdit を返却
```

### フローチャート

```mermaid
flowchart TD
    A[rename リクエスト受信] --> B[find-element-under-cursor]
    B --> C{要素あり?}
    C -->|No| D[エラー返却]
    C -->|Yes| E[rename-status]
    E --> F{リネーム可能?}
    F -->|No| G[エラー返却]
    F -->|Yes| H[find-references]
    H --> I{要素種別?}
    I -->|namespace-alias| J[rename-alias-definition]
    I -->|namespace-definitions| K[rename-ns-definition + ファイル変更]
    I -->|keywords| L[rename-keyword]
    I -->|locals| M[rename-local]
    I -->|defrecord| N[rename-defrecord]
    I -->|その他| O[rename-other]
    J --> P[WorkspaceEdit 構築]
    K --> P
    L --> P
    M --> P
    N --> P
    O --> P
    P --> Q[WorkspaceEdit 返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 定義必須 | 定義が見つからない場合はエラー | 全リネーム |
| BR-02 | 参照必須 | 参照が見つからない場合はエラー | 全リネーム |
| BR-03 | ソースパス必須 | 名前空間リネームには有効なソースパスが必要 | 名前空間リネーム |
| BR-04 | クライアント対応 | ファイル変更はクライアントの documentChanges 対応が必要 | 名前空間リネーム |
| BR-05 | 単一定義 | 名前空間が複数ファイルで定義されている場合はエラー | 名前空間リネーム |
| BR-06 | 名前空間キーワードのみ | 非名前空間修飾キーワードのリネームは不可 | キーワードリネーム |
| BR-07 | defrecord 派生名 | defrecord のリネームは ->Name, map->Name も連動 | defrecord リネーム |

### 計算ロジック

- 新しいテキスト: new-name から "/" 以降の部分を抽出（名前空間修飾の場合）
- 範囲計算: element の :name-col, :name-end-col から編集範囲を算出
- ファイル URI: namespace->uri で名前空間から新しいファイル URI を計算

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 要素検索 | db :analysis | SELECT | カーソル位置の要素を検索 |
| 参照検索 | db :analysis | SELECT | 全参照を取得 |
| バージョン取得 | db :documents | SELECT | ドキュメントバージョンを取得 |

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

#### db :analysis

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | 各バケット | uri, row, col で要素特定 | 要素検索 |
| SELECT | 各バケット | 要素種別に応じた参照検索 | 参照検索 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| :invalid-params | 要素なし | カーソル位置に要素がない | エラーメッセージ返却 |
| :invalid-params | 定義なし | 定義が見つからない | エラーメッセージ返却 |
| :invalid-params | 参照なし | 参照が見つからない | エラーメッセージ返却 |
| :invalid-params | ソースパス不正 | 名前空間リネームでソースパスが不正 | エラーメッセージ返却 |
| :invalid-params | クライアント非対応 | ファイル変更をクライアントがサポートしない | エラーメッセージ返却 |
| :invalid-params | 複数定義 | 名前空間が複数ファイルで定義 | エラーメッセージ返却 |
| :invalid-params | 非修飾キーワード | 名前空間修飾されていないキーワード | エラーメッセージ返却 |

### リトライ仕様

リトライは行わない。

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

- 全ての編集は WorkspaceEdit として一括で返却される
- クライアント側で一括適用またはロールバックが行われる

## パフォーマンス要件

- 応答時間: 通常 200ms 以内
- 参照検索が主なボトルネック

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

- 外部ネットワーク通信なし
- ファイルシステムへの書き込みはクライアント側で実行

## 備考

- エイリアス付きの使用箇所からリネームする場合、エイリアスも連動して変更される
- キーワードの分割代入（:keys）も正しくハンドリング

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | ident-split（10-16行目）で識別子の分割方法を確認 |

**読解のコツ**: プレフィックス（:, ::）、名前空間部分、名前部分の3要素に分割される。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | handlers.clj | `lib/src/clojure_lsp/handlers.clj` | rename 関数（282-286行目）が LSP リクエストのエントリーポイント |
| 2-2 | rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | rename-from-position 関数（312-316行目）がメインエントリー |

**主要処理フロー**:
1. **314行目**: find-element-under-cursor で要素特定
2. **315行目**: rename-element を呼び出し

#### Step 3: リネーム可否判定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | rename-status 関数（224-267行目）でリネーム可否の条件を確認 |

**主要処理フロー**:
- **225-226行目**: find-references と find-definition を呼び出し
- **232-267行目**: 各種エラー条件をチェック

#### Step 4: 編集内容計算を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | rename-changes 関数（193-222行目）で要素種別ごとの編集計算を確認 |
| 4-2 | rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | rename-other（18-25行目）で基本的な編集を確認 |
| 4-3 | rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | rename-keyword（27-103行目）でキーワード編集を確認 |
| 4-4 | rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | rename-defrecord（168-191行目）で defrecord 編集を確認 |

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

```
handlers/rename
    │
    └─ f.rename/rename-from-position
           │
           ├─ q/find-element-under-cursor
           │
           └─ f.rename/rename-element
                  │
                  ├─ rename-status
                  │      ├─ q/find-references
                  │      ├─ q/find-definition
                  │      └─ [各種エラーチェック]
                  │
                  └─ [リネーム可能な場合]
                         │
                         ├─ rename-changes
                         │      ├─ rename-alias-definition
                         │      ├─ rename-usages-with-alias
                         │      ├─ rename-ns-definition
                         │      ├─ rename-keyword
                         │      ├─ rename-local
                         │      ├─ rename-defrecord
                         │      └─ rename-other
                         │
                         └─ [名前空間の場合]
                                └─ ファイル名変更情報追加
```

### データフロー図

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

textDocument/rename ──▶ handlers/rename ──▶ WorkspaceEdit
  - uri                          │
  - position (line, char)        ▼
  - new-name                rename-from-position
                                 │
                                 ├──▶ find-element-under-cursor
                                 │      └─ db :analysis[uri]
                                 │
                                 ├──▶ rename-status
                                 │      ├─ find-references
                                 │      └─ find-definition
                                 │
                                 └──▶ rename-changes
                                        │
                                        ├──▶ [編集計算]
                                        │      └─ TextEdit[]
                                        │
                                        └──▶ [名前空間]
                                               └─ RenameFile
                                                      │
                                                      ▼
                                                 WorkspaceEdit
                                                   {documentChanges}
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | ソース | リネームのメインロジック |
| handlers.clj | `lib/src/clojure_lsp/handlers.clj` | ソース | LSP リクエストハンドラー |
| queries.clj | `lib/src/clojure_lsp/queries.clj` | ソース | 要素・参照検索 |
| shared.clj | `lib/src/clojure_lsp/shared.clj` | ソース | 範囲変換、URI 変換 |
| rename_test.clj | `lib/test/clojure_lsp/feature/rename_test.clj` | テスト | ユニットテスト |
| rename_test.clj | `cli/integration-test/integration/rename_test.clj` | テスト | 統合テスト |
