# 帳票設計書 5-rename

## 概要

本ドキュメントは、clojure-lspのrename（リネーム）機能によって出力される帳票の設計仕様を定義する。

### 本帳票の処理概要

rename帳票は、シンボルのリネーム結果を出力する帳票である。プロジェクト全体での変更箇所と差分をunified diff形式で表示し、`--dry`オプションで変更を適用せずに差分のみを確認することが可能である。変数名、関数名、名前空間、キーワードなど様々なシンボルのリネームに対応している。

**業務上の目的・背景**：ソフトウェア開発において、リファクタリングは避けられない作業である。特にシンボル名の変更は、コードベース全体に影響を与えるため、手動での変更は漏れや不整合のリスクが高い。本帳票は、プロジェクト全体のシンボル参照を解析し、安全かつ完全なリネームを実現することで、リファクタリングの品質と効率を向上させることを目的とする。

**帳票の利用シーン**：本帳票は以下の場面で利用される。(1) 変数/関数名の改善、(2) 名前空間の再構成、(3) API名の変更、(4) defrecord/deftypeのリネーム、(5) 名前空間エイリアスの変更、(6) 名前空間付きキーワードの変更。

**主要な出力内容**：
1. 変更対象シンボルの全参照箇所
2. 各参照箇所の変更前後の差分
3. ファイルリネーム（名前空間変更時）
4. unified diff形式での変更内容表示

**帳票の出力タイミング**：CLIコマンド`clojure-lsp rename --from <symbol> --to <symbol>`の実行時、またはAPI経由での`clojure-lsp.api/rename!`関数呼び出し時に出力される。`--dry`オプション指定時は差分表示のみ、未指定時はファイル変更も実行される。

**帳票の利用者**：開発者、テックリード、CI/CDシステム（検証用）

## 帳票種別

差分レポート / リファクタリング結果レポート

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| CLI-01 | コマンドライン | `clojure-lsp rename --from <sym> --to <sym>` | コマンド実行 |
| CLI-02 | コマンドライン（ドライラン） | `clojure-lsp rename --from <sym> --to <sym> --dry` | コマンド実行 |
| API-01 | Clojure REPL | `(clojure-lsp.api/rename! opts)` | 関数呼び出し |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | unified diff（テキスト） |
| 用紙サイズ | N/A（コンソール出力） |
| 向き | N/A |
| ファイル名 | 標準出力 |
| 出力方法 | 標準出力 / 標準エラー出力 |
| 文字コード | UTF-8 |

### 出力フォーマット詳細

#### unified diff形式（シンボルリネーム）
```diff
--- a/src/my_project/core.clj
+++ b/src/my_project/core.clj
@@ -10,7 +10,7 @@
-(defn old-function-name
+(defn new-function-name
   [arg]
   body)

@@ -20,3 +20,3 @@
-(old-function-name x)
+(new-function-name x)
```

#### ファイルリネーム（名前空間変更時）
```diff
rename from src/my_project/old_ns.clj
rename to src/my_project/new_ns.clj
--- a/src/my_project/old_ns.clj
+++ b/src/my_project/new_ns.clj
@@ -1,3 +1,3 @@
-(ns my-project.old-ns)
+(ns my-project.new-ns)
```

#### 実行モード別出力

**dryモード（`--dry`）**:
- 差分のみ表示、ファイル変更なし
- result-code: 0

**実行モード（デフォルト）**:
- ファイル変更を実行
- result-code: 0

## 帳票レイアウト

### レイアウト概要

unified diff形式で差分を出力。ファイルリネームがある場合は`rename from/to`ヘッダーも含む。

```
┌─────────────────────────────────────────────────────────────────┐
│  rename from src/old_path.clj                                   │
│  rename to src/new_path.clj                                     │
│  --- a/src/namespace/file.clj                                   │
│  +++ b/src/namespace/file.clj                                   │
│  @@ -n,m +n,m @@                                                │
│  -(old-symbol ...)                                              │
│  +(new-symbol ...)                                              │
└─────────────────────────────────────────────────────────────────┘
```

### 出力項目

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | リネーム元パス | ファイルリネーム元 | old-uri | `rename from path` |
| 2 | リネーム先パス | ファイルリネーム先 | new-uri | `rename to path` |
| 3 | 旧ファイルパス | 変更前ファイル | URI | `--- a/path` |
| 4 | 新ファイルパス | 変更後ファイル | URI | `+++ b/path` |
| 5 | 変更範囲 | 行番号範囲 | range | `@@ -n,m +n,m @@` |
| 6 | 削除行 | 削除されるコード | old-text | `-` プレフィックス |
| 7 | 追加行 | 追加されるコード | new-text | `+` プレフィックス |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| from | リネーム元シンボル（完全修飾名 or 名前空間名） | Yes |
| to | リネーム先シンボル（完全修飾名 or 名前空間名） | Yes |
| project-root | プロジェクトルートディレクトリ | No（デフォルト: カレントディレクトリ） |
| dry? | ドライランモード | No（デフォルト: false） |

### シンボル形式

| 形式 | 例 | 説明 |
|------|-----|------|
| 完全修飾シンボル | `my-project.core/my-function` | 関数/変数のリネーム |
| 名前空間のみ | `my-project.core` | 名前空間全体のリネーム |

### 対応シンボルタイプ

| タイプ | 説明 |
|-------|------|
| var-definitions | defn, def等の変数定義 |
| namespace-definitions | ns定義 |
| namespace-alias | require :as エイリアス |
| keyword-definitions | 名前空間付きキーワード定義 |
| locals | let, fn引数等のローカル変数 |
| defrecord | defrecord（->Constructor, map->Constructorも対応） |

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| db.analysis | シンボル解析データ | URI, name, ns |
| db.documents | ドキュメントテキスト | URI |

### 解析データ詳細

| 参照項目 | 用途 | 取得条件 |
|---------|------|---------|
| var-definitions | 変数定義の検索 | ns, name |
| var-usages | 変数使用箇所の検索 | to, name |
| namespace-definitions | 名前空間定義の検索 | name |
| namespace-usages | 名前空間使用箇所の検索 | to |
| keyword-definitions | キーワード定義の検索 | ns, name |
| keyword-usages | キーワード使用箇所の検索 | ns, name |
| locals | ローカル変数の検索 | name |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| result-code | 成功:0, 失敗:1 | - | 終了コード |
| references | q/find-references(db, element, true) | - | 全参照取得 |
| definition | q/find-definition(db, element) | - | 定義取得 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[renameコマンド実行] --> B[オプション解析]
    B --> C{from/to指定あり?}
    C -->|No| D[エラー: Missing required option]
    C -->|Yes| E[プロジェクト解析初期化]
    E --> F[シンボル検索]
    F --> G{シンボル存在?}
    G -->|No| H[エラー: Symbol not found]
    G -->|Yes| I[rename-status確認]
    I --> J{リネーム可能?}
    J -->|No| K[エラー返却]
    J -->|Yes| L[参照一覧取得]
    L --> M[rename-changes生成]
    M --> N{名前空間リネーム?}
    N -->|Yes| O[ファイルリネーム追加]
    N -->|No| P[編集内容生成]
    O --> P
    P --> Q{dry?}
    Q -->|Yes| R[差分文字列生成]
    Q -->|No| S[ファイル変更適用]
    R --> T[差分出力]
    S --> U[変更ログ出力]
    T --> V[終了]
    U --> V
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| シンボル未発見 | fromシンボルが存在しない | Symbol X not found in project | シンボル名確認 |
| 定義未発見 | 定義が見つからない | Can't rename - no definition found. | 定義存在確認 |
| 参照未発見 | 参照が見つからない | Can't rename - no other references found. | 参照存在確認 |
| 無効なソースパス | source-pathsが不正 | Can't rename - invalid source-paths | 設定確認 |
| クライアント非対応 | ファイルリネーム非対応 | Can't rename - client does not support file renames. | クライアント確認 |
| 複数ファイル定義 | 名前空間が複数ファイルで定義 | Can't rename - namespace is defined in multiple files. | 定義統合 |
| 非名前空間キーワード | 非修飾キーワードのリネーム | Can't rename - only namespaced keywords can be renamed. | 修飾キーワード使用 |
| 変更なし | リネーム結果が空 | Nothing to rename | - |
| リネーム失敗 | その他エラー | Could not rename X to Y. <reason> | 原因確認 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数十〜数百参照 |
| 目標出力時間 | 数秒以内 |
| 同時出力数上限 | 1（シングルスレッド処理） |

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

- ファイル変更・リネームを伴うため、バージョン管理システムでの差分確認を推奨
- `--dry`オプションでの事前確認を推奨
- 名前空間リネーム時はファイル移動も発生するため注意

## 備考

- defrecordリネーム時は->Constructor, map->Constructorも自動リネーム
- 名前空間リネーム時はファイルパスも自動変更
- キーワードリネームは名前空間付きキーワードのみ対応
- エイリアスリネーム時は使用箇所も自動更新

---

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

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

### 推奨読解順序

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

rename機能で使用される主要なデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | **283-310行目**: `rename-element`関数の戻り値構造 |
| 1-2 | queries.clj | `lib/src/clojure_lsp/queries.clj` | `find-references`, `find-definition`関数 |

**読解のコツ**: rename機能はシンボルのバケット（bucket）に応じて異なる処理を行う。`:var-definitions`, `:namespace-definitions`, `:keyword-definitions`等のバケットタイプを理解することが重要。

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

CLIからの呼び出しフローを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | main.clj | `cli/src/clojure_lsp/main.clj` | **176行目**: `"rename"`アクション分岐 |
| 2-2 | main.clj | `cli/src/clojure_lsp/main.clj` | **205-208行目**: `with-required-options`でfrom/toチェック |

**主要処理フロー**:
1. **156-180行目**: `parse`関数でコマンドライン引数を解析
2. **187-192行目**: `with-required-options`で必須オプション確認
3. **205-208行目**: renameの場合`internal-api/rename!`を呼び出し

#### Step 3: 内部API層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | internal_api.clj | `lib/src/clojure_lsp/internal_api.clj` | **403-432行目**: `rename!*`関数の実装 |

**主要処理フロー**:
- **405行目**: `setup-project-only-analysis!`でプロジェクト解析
- **407-411行目**: fromシンボルからns/name抽出
- **412行目**: `q/find-element-from-sym`でシンボル検索
- **413-415行目**: `f.rename/rename-from-position`でリネーム実行
- **417-432行目**: dry/実行モードに応じた処理

#### Step 4: rename機能コア層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | **312-316行目**: `rename-from-position`エントリーポイント |
| 4-2 | rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | **283-310行目**: `rename-element`メイン処理 |
| 4-3 | rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | **224-267行目**: `rename-status`検証処理 |
| 4-4 | rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | **193-222行目**: `rename-changes`変更生成 |

**主要処理フロー**:
- **312-316行目**: `rename-from-position`がエントリーポイント
- **283-284行目**: `rename-status`でリネーム可否を検証
- **287-289行目**: `rename-changes`で変更内容を生成
- **296-310行目**: 名前空間リネーム時のファイルリネーム追加

#### Step 5: 各シンボルタイプ別のリネーム処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | **18-25行目**: `rename-other`（一般的なシンボル） |
| 5-2 | rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | **27-103行目**: `rename-keyword`（キーワード） |
| 5-3 | rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | **105-113行目**: `rename-ns-definition`（名前空間定義） |
| 5-4 | rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | **115-128行目**: `rename-alias-definition`（エイリアス） |
| 5-5 | rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | **168-191行目**: `rename-defrecord`（defrecord） |

**主要処理フロー**:
- 各シンボルタイプに応じた専用のリネーム関数が存在
- `rename-changes`内でバケットタイプに応じて適切な関数を呼び出し

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

```
clojure-lsp.main/-main
    |
    +-- parse (コマンド解析)
    |
    +-- with-required-options (from/toチェック)
    |
    +-- handle-action!
           |
           +-- clojure-lsp.internal-api/rename!
                  |
                  +-- build-components (コンポーネント初期化)
                  |
                  +-- rename!*
                         |
                         +-- setup-api!
                         |
                         +-- setup-project-only-analysis!
                         |
                         +-- q/find-element-from-sym
                         |
                         +-- open-file!
                         |
                         +-- f.rename/rename-from-position
                         |      |
                         |      +-- q/find-element-under-cursor
                         |      |
                         |      +-- rename-element
                         |             |
                         |             +-- rename-status
                         |             |      |
                         |             |      +-- q/find-references
                         |             |      +-- q/find-definition
                         |             |
                         |             +-- rename-changes
                         |             |      |
                         |             |      +-- rename-other
                         |             |      +-- rename-keyword
                         |             |      +-- rename-ns-definition
                         |             |      +-- rename-alias-definition
                         |             |      +-- rename-defrecord
                         |             |      +-- rename-local
                         |             |
                         |             +-- shared/client-changes
                         |
                         +-- document-change->edit-summary
                         |
                         +-- [dry?] edits->diff-string
                         |             |
                         |             +-- diff/unified-diff
                         |             +-- diff/rename-diff
                         |             +-- diff/colorize-diff
                         |
                         +-- [!dry?] apply-workspace-edit-summary!
```

### データフロー図

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

--from symbol ────────▶ parse ────────────────────────▶ from-ns, from-name
--to symbol ──────────▶ parse ────────────────────────▶ replacement
     |                                                      |
     v                                                      v
project-root ─────────▶ analyze! ─────────────────────▶ db (analysis)
     |                                                      |
     v                                                      v
from-ns/name ─────────▶ find-element-from-sym ────────▶ element
     |                                                      |
     v                                                      v
element ──────────────▶ rename-status ────────────────▶ references, definition
     |                                                      |
     v                                                      v
references + to ──────▶ rename-changes ───────────────▶ [{:range :new-text ...}]
     |                                                      |
     v                                                      v
changes ──────────────▶ client-changes ───────────────▶ document-changes
     |                                                      |
     v                                                      v
doc-changes ──────────▶ edit-summary ─────────────────▶ [{:kind :uri :old-text :new-text}]
     |                                                      |
     v                                                      v
edit-summary ─────────▶ unified-diff + rename-diff ───▶ diff string
                                                            |
                                                            v
                       colorize-diff ─────────────────▶ stdout
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| main.clj | `cli/src/clojure_lsp/main.clj` | ソース | CLIエントリーポイント |
| api.clj | `lib/src/clojure_lsp/api.clj` | ソース | 公開API定義 |
| internal_api.clj | `lib/src/clojure_lsp/internal_api.clj` | ソース | 内部API実装 |
| rename.clj | `lib/src/clojure_lsp/feature/rename.clj` | ソース | rename機能コア |
| queries.clj | `lib/src/clojure_lsp/queries.clj` | ソース | シンボル検索 |
| handlers.clj | `lib/src/clojure_lsp/handlers.clj` | ソース | LSPハンドラ |
| diff.clj | `lib/src/clojure_lsp/diff.clj` | ソース | diff生成 |
| shared.clj | `lib/src/clojure_lsp/shared.clj` | ソース | 共通ユーティリティ |
| rename_test.clj | `cli/integration-test/integration/rename_test.clj` | テスト | rename統合テスト |
| rename_test.clj | `cli/integration-test/integration/api/rename_test.clj` | テスト | rename API統合テスト |
