# 機能設計書 64-インラインリネーム

## 概要

本ドキュメントは、Visual Studio統合におけるF#のインラインリネーム（シンボル名変更）機能の設計について記述する。この機能は、ユーザーが選択したシンボルの名前を変更し、ソリューション全体で一括して名前を更新する。

### 本機能の処理概要

**業務上の目的・背景**：
リファクタリングにおいて、変数や関数の名前を適切なものに変更することは、コードの可読性と保守性を向上させる重要な作業である。本機能により、開発者は安全かつ効率的にシンボル名を変更でき、名前の不一致によるバグを防止できる。

**機能の利用シーン**：
- 変数名をより意味のある名前に変更したい場合
- 関数名を命名規約に合わせて修正したい場合
- 型名を変更してドメインモデルを改善したい場合
- F#キーワードと衝突しない名前に変更したい場合

**主要な処理内容**：
1. カーソル位置のシンボルを特定
2. ソリューション全体でシンボルの使用箇所を検索
3. リネーム用のUI（インラインエディタ）を表示
4. 入力された新しい名前の妥当性を検証
5. すべての使用箇所を新しい名前で置換
6. 変更をドキュメントに反映

**関連システム・外部連携**：
- Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor: Roslynリネームインターフェース
- FSharp.Compiler.Symbols: F#シンボル情報
- FSharp.Compiler.Tokenization: 名前の妥当性検証

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | 言語サービスパフォーマンスオプション画面 | 設定画面 | 高速参照検索とリネームの有効化設定 |

## 機能種別

リファクタリング機能

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| document | Document | Yes | 対象のドキュメント | null不可 |
| position | int | Yes | カーソル位置（文字オフセット） | 0以上、ドキュメント長未満 |
| replacementText | string | Yes | 新しいシンボル名 | 空文字不可、有効な識別子 |

### 入力データソース

- Visual Studioエディタのカーソル位置
- ユーザー入力による新しいシンボル名
- F#コンパイラサービスの解析結果

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| NewSolution | Solution | 変更が適用された新しいソリューション |
| ReplacementTextValid | bool | 新しい名前が有効かどうか |
| DocumentIds | IEnumerable<DocumentId> | 変更があったドキュメントID |

### 出力先

Visual Studio のドキュメント（ソースファイル）

## 処理フロー

### 処理シーケンス

```
1. リネーム情報の取得
   └─ GetRenameInfoAsyncでシンボル情報を取得

2. シンボル検証
   └─ カーソル位置のシンボルが有効か確認

3. 使用箇所の検索
   └─ FindRenameLocationsAsyncでソリューション全体を検索

4. インラインエディタ表示
   └─ ユーザーが新しい名前を入力

5. 名前の妥当性検証
   └─ isValidNameForSymbolで新しい名前を検証

6. 置換の実行
   └─ GetReplacementsAsyncで全箇所を置換

7. ソリューション更新
   └─ 変更を含む新しいSolutionを返却
```

### フローチャート

```mermaid
flowchart TD
    A[リネームコマンド実行] --> B[GetRenameInfoAsync]
    B --> C{シンボル発見?}
    C -->|No| Z[キャンセル]
    C -->|Yes| D[FindRenameLocationsAsync]
    D --> E[インラインエディタ表示]
    E --> F[ユーザー入力]
    F --> G[GetReplacementsAsync]
    G --> H{名前有効?}
    H -->|No| I[エラー表示]
    I --> F
    H -->|Yes| J[applyChanges]
    J --> K[NewSolution返却]
    K --> L[完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-64-01 | バッククォート正規化 | GenericTypeParameter/StaticallyResolvedTypeParameter/Operator以外はNormalizeIdentifierBackticksを適用 | 置換テキスト生成時 |
| BR-64-02 | 識別子妥当性検証 | シンボル種別に応じた識別子の有効性チェック | 新しい名前入力時 |
| BR-64-03 | スパン修正 | Tokenizer.fixupSpanで正確なテキスト範囲を計算 | 参照スパン取得時 |
| BR-64-04 | phantom accessor除外 | get/setアクセサキーワード上でのリネームは禁止 | リネーム開始時 |

### 計算ロジック

名前の正規化（63-68行目）：
```fsharp
match symbolKind with
| LexerSymbolKind.GenericTypeParameter
| LexerSymbolKind.StaticallyResolvedTypeParameter
| LexerSymbolKind.Operator -> replacementText
| _ -> FSharpKeywords.NormalizeIdentifierBackticks replacementText
```

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | シンボル不在 | カーソル位置にシンボルがない | nullを返却（リネーム不可） |
| - | 無効な識別子 | 新しい名前がF#識別子として無効 | ReplacementTextValid=falseを返却 |
| - | phantom accessor | get/setキーワード上でリネーム開始 | nullを返却 |

### リトライ仕様

リトライなし。無効な名前の場合はユーザーが再入力。

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

- Solutionオブジェクトは不変（イミュータブル）
- applyChangesは再帰的に新しいSolutionを構築
- エラー時は元のSolutionが保持される

## パフォーマンス要件

- ソリューション全体の検索は非同期で実行
- リネーム箇所が多い場合もUIをブロックしない

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

該当なし

## 備考

- InlineRenameInfoがリネーム対象の情報を保持
- InlineRenameLocationSetが全使用箇所を管理
- InlineRenameReplacementInfoが置換結果を保持

---

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

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

### 推奨読解順序

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

インラインリネームで使用される主要なデータ型を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | InlineRenameService.fs | `vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs` | InlineRenameReplacementInfo、InlineRenameLocationSet、InlineRenameInfo型 |

**読解のコツ**:
- InlineRenameReplacementInfo（23-29行目）: 置換結果を保持
- InlineRenameLocationSet（31-76行目）: 全使用箇所と置換ロジック
- InlineRenameInfo（78-180行目）: リネーム対象の詳細情報

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

FSharpInlineRenameServiceImplementationの実装から読み始める。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | InlineRenameService.fs | `vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs` | InlineRenameServiceクラス |

**主要処理フロー**:
1. **182-228行目**: InlineRenameServiceクラスの定義
2. **187-228行目**: GetRenameInfoAsyncメソッド

#### Step 3: リネーム情報取得を理解する

GetRenameInfoAsyncがリネーム対象の情報を取得。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | InlineRenameService.fs | `vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs` | GetRenameInfoAsync実装 |

**主要処理フロー**:
- **188-228行目**: GetRenameInfoAsyncメソッド本体
- **195-196行目**: レキサーシンボル取得
- **202-210行目**: シンボル使用情報取得
- **215-217行目**: TextSpanへの変換
- **218-226行目**: phantom accessor（get/set）のチェックとInlineRenameInfo生成

#### Step 4: 使用箇所検索を理解する

FindRenameLocationsAsyncがソリューション全体を検索。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | InlineRenameService.fs | `vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs` | InlineRenameInfo.FindRenameLocationsAsync |

**主要処理フロー**:
- **150-180行目**: FindRenameLocationsAsyncメソッド
- **100-101行目**: SymbolHelpers.getSymbolUsesInSolutionでシンボル使用を取得
- **154-172行目**: 各ドキュメントの使用箇所をFSharpInlineRenameLocationに変換
- **176-178行目**: InlineRenameLocationSetを生成

#### Step 5: 置換ロジックを理解する

GetReplacementsAsyncが実際の置換を実行。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | InlineRenameService.fs | `vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs` | InlineRenameLocationSet.GetReplacementsAsync |

**主要処理フロー**:
- **57-76行目**: GetReplacementsAsyncメソッド
- **36-53行目**: applyChanges再帰関数（ドキュメントごとに変更適用）
- **63-68行目**: シンボル種別に応じた名前正規化
- **70-71行目**: isValidNameForSymbolで妥当性検証
- **74行目**: InlineRenameReplacementInfoを生成

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

```
InlineRenameService.GetRenameInfoAsync
    │
    ├─ document.TryFindFSharpLexerSymbolAsync
    │
    ├─ document.GetFSharpParseAndCheckResultsAsync
    │
    ├─ checkFileResults.GetSymbolUseAtLocation
    │
    └─ InlineRenameInfo (生成)
           │
           ├─ SymbolHelpers.getSymbolUsesInSolution (遅延実行)
           │
           └─ FindRenameLocationsAsync
                  │
                  ├─ [各ドキュメント]
                  │      └─ Tokenizer.TryFSharpRangeToTextSpanForEditor
                  │
                  └─ InlineRenameLocationSet (生成)
                         │
                         └─ GetReplacementsAsync
                                │
                                ├─ applyChanges (再帰)
                                │      └─ solution.WithDocumentText
                                │
                                ├─ FSharpKeywords.NormalizeIdentifierBackticks
                                │
                                ├─ Tokenizer.isValidNameForSymbol
                                │
                                └─ InlineRenameReplacementInfo (生成)
```

### データフロー図

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

Document + Position ────▶ GetRenameInfoAsync ────────────────┐
                              │                              │
                              └─ InlineRenameInfo ───────────┤
                                      │                      │
                                      ▼                      │
                              FindRenameLocationsAsync       │
                                      │                      │
                                      └─ InlineRenameLocationSet
                                              │              │
                                              ▼              │
User Input (新しい名前) ──▶ GetReplacementsAsync ────────────┤
                                      │                      │
                                      ├─ applyChanges        │
                                      │                      │
                                      └─ InlineRenameReplacementInfo
                                              │              │
                                              ▼              ▼
                                         NewSolution ────▶ 更新されたドキュメント
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| InlineRenameService.fs | `vsintegration/src/FSharp.Editor/InlineRename/InlineRenameService.fs` | ソース | インラインリネームサービスの実装 |
| SymbolHelpers.fs | `vsintegration/src/FSharp.Editor/Common/SymbolHelpers.fs` | ソース | シンボル検索ヘルパー |
| Tokenizer.fs | `vsintegration/src/FSharp.Editor/Common/Tokenizer.fs` | ソース | 名前妥当性検証・スパン修正 |
| FSharpKeywords.fs | `src/Compiler/SyntaxTree/FSharpKeywords.fs` | ソース | 識別子正規化 |
