# 機能設計書 25-メソッド抽出

## 概要

本ドキュメントは、Roslynにおける「メソッド抽出」機能の設計を記述するものである。メソッド抽出機能は、選択されたコードブロックを新しいメソッドまたはローカル関数として抽出し、元の場所にそのメソッドへの呼び出しを配置するリファクタリング機能である。

### 本機能の処理概要

メソッド抽出機能は、ユーザーが選択したステートメントまたは式を分析し、新しいメソッド(またはローカル関数)を自動生成する。抽出されるコードで使用される変数を分析してパラメータを決定し、戻り値や出力パラメータも適切に生成する。

**業務上の目的・背景**：大きなメソッドは理解しにくく、テストしにくく、再利用しにくい。メソッド抽出は、長いメソッドを小さな単位に分割し、各メソッドに単一の責任を持たせるための最も基本的なリファクタリング手法である。手動でのメソッド抽出は、変数のスコープ分析やパラメータの決定が複雑であり、自動化が強く求められる。

**機能の利用シーン**：
1. 長いメソッドから一部の処理を切り出して再利用可能にする
2. 複雑なロジックを小さな単位に分割して可読性を向上させる
3. テスト可能な単位にコードを分割する
4. 重複コードを一箇所にまとめる

**主要な処理内容**：
1. 選択範囲のバリデーション(抽出可能かどうかの判定)
2. 変数フロー分析(データフロー分析)
3. パラメータ、戻り値、出力パラメータの決定
4. 新しいメソッド/ローカル関数の生成
5. 元のコードを呼び出しに置換

**関連システム・外部連携**：
- CodeRefactoringProvider経由でエディタに統合
- 制御フロー分析サービスとの連携

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | ライトバルブメニュー | 主画面 | メソッド抽出アクションの選択 |
| 20 | プレビューペイン | 補助画面 | 抽出結果のプレビュー |

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| selectionResult | SelectionResult | Yes | 選択範囲の分析結果 | 有効な選択であること |
| options | ExtractMethodGenerationOptions | Yes | 生成オプション | - |
| localFunction | bool | Yes | ローカル関数として抽出するか | - |

### 入力データソース

- ドキュメントの構文ツリー(SyntaxTree)
- セマンティックモデル(SemanticModel)
- 選択範囲のテキスト情報

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ExtractMethodResult | ExtractMethodResult | 抽出結果 |
| succeeded | bool | 成功したかどうか |
| document | Document | 変更後のドキュメント(成功時) |
| invocationNameToken | SyntaxToken | 呼び出し箇所のトークン |

### 出力先

- 新しいメソッドが追加されたドキュメント
- 元のコードが呼び出しに置換されたドキュメント

## 処理フロー

### 処理シーケンス

```
1. 選択範囲の分析(SelectionResult)
   └─ 選択されたステートメント/式の取得と検証
2. 変数フロー分析(Analyze)
   └─ 使用される変数、定義される変数、戻り値の分析
3. 挿入ポイントの決定
   └─ 新しいメソッドを挿入する位置を決定
4. コード生成(CreateCodeGenerator)
   └─ 新しいメソッドとその呼び出しを生成
5. トリビア保持
   └─ コメントやフォーマットを維持
6. 整形
   └─ Simplifier, Formatterで最終整形
```

### フローチャート

```mermaid
flowchart TD
    A[開始: ExtractMethod] --> B[Analyze]
    B --> C{変数型チェック}
    C -->|失敗| D[Fail結果返却]
    C -->|成功| E[GetInsertionPointNode]
    E --> F{挿入可能?}
    F -->|No| D
    F -->|Yes| G[CreateCodeGenerator]
    G --> H[GetNewMethodStatements]
    H --> I{ステートメント取得成功?}
    I -->|No| D
    I -->|Yes| J[GetAnnotatedDocumentAndInsertionPoint]
    J --> K[PreserveTrivia]
    K --> L[GenerateAsync]
    L --> M[ApplyTrivia]
    M --> N[GetFormattedDocument]
    N --> O[Success結果返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 不正な型の除外 | TypeKind.Error/Unknownの型を含む場合は失敗 | 常時 |
| BR-02 | System.Void許可 | 戻り値がvoidの場合は許可 | 常時 |
| BR-03 | 型パラメータ検証 | 型パラメータが別の型に隠されていないかチェック | 常時 |
| BR-04 | 挿入位置検証 | 挿入先がコード生成可能か、隠しコード領域でないかチェック | 常時 |

### 計算ロジック

パラメータ決定ロジック:
1. 選択範囲内で使用される変数を特定
2. 選択範囲外で定義され、範囲内で使用される変数 → パラメータ
3. 選択範囲内で定義され、範囲外で使用される変数 → 出力パラメータ/戻り値
4. 選択範囲が式の場合 → 式の値が戻り値

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 型エラー | 不正な型(Error/Unknown)を含む | 抽出不可として報告 |
| - | 挿入位置エラー | 有効な挿入位置がない | 抽出不可として報告 |
| - | 隠しコード領域 | 挿入先が隠しコード領域 | 抽出不可として報告 |

### リトライ仕様

なし

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

該当なし

## パフォーマンス要件

- 変数フロー分析は構文解析とセマンティック分析を組み合わせて実行
- 結果はasyncで返却され、UIスレッドをブロックしない

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

- 特になし

## 備考

- メソッド抽出とローカル関数抽出の両方をサポート
- ローカル関数の場合は挿入位置の前に空行を挿入
- MakeMethodName関数でメソッド名を生成(camelCaseオプションあり)

---

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

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

### 推奨読解順序

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

まず、メソッド抽出で使用される主要なデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ExtractMethodResult.cs | `src/Features/Core/Portable/ExtractMethod/ExtractMethodResult.cs` | 抽出結果の構造 |
| 1-2 | SelectionResult.cs | `src/Features/Core/Portable/ExtractMethod/SelectionResult.cs` | 選択範囲の分析結果 |
| 1-3 | AnalyzerResult.cs | `src/Features/Core/Portable/ExtractMethod/AnalyzerResult.cs` | 変数分析結果 |

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

処理の起点となるMethodExtractor.csを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | MethodExtractor.cs | `src/Features/Core/Portable/ExtractMethod/MethodExtractor.cs` | メイン処理 |

**主要処理フロー**:
1. **47-136行目**: ExtractMethod - メイン処理フロー
2. **36行目**: Analyze - 変数フロー分析(抽象メソッド)
3. **37行目**: GetInsertionPointNode - 挿入位置決定(抽象メソッド)
4. **40行目**: CreateCodeGenerator - コード生成器の作成(抽象メソッド)

#### Step 3: 変数分析を理解する

パラメータや戻り値を決定する変数分析を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AnalyzerResult.cs | `src/Features/Core/Portable/ExtractMethod/AnalyzerResult.cs` | 分析結果の構造 |

**読解ポイント**:
- Variables: 選択範囲に関連する変数一覧
- CoreReturnType: 戻り値の型

#### Step 4: コード生成を理解する

新しいメソッドとその呼び出しの生成を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | CodeGenerator.cs | `src/Features/Core/Portable/ExtractMethod/CodeGenerator.cs` | コード生成 |

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

```
MethodExtractor.ExtractMethod
    │
    ├─ Analyze
    │      └─ 変数フロー分析
    │
    ├─ CheckVariableTypes
    │      └─ 変数の型をチェック
    │
    ├─ GetInsertionPointNode
    │      └─ 挿入位置の決定
    │
    ├─ CanAddTo
    │      └─ 挿入可能かチェック
    │
    ├─ CreateCodeGenerator
    │      │
    │      └─ CodeGenerator.GetNewMethodStatements
    │             └─ 新しいメソッドのステートメント生成
    │
    └─ (非同期処理)
           │
           ├─ GetAnnotatedDocumentAndInsertionPointAsync
           │
           ├─ PreserveTriviaAsync
           │
           ├─ CodeGenerator.GenerateAsync
           │      └─ メソッドの生成
           │
           ├─ TriviaResult.ApplyAsync
           │
           └─ GetFormattedDocumentAsync
                  ├─ Simplifier.ReduceAsync
                  └─ Formatter.Format
```

### データフロー図

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

SelectionResult ───▶ Analyze ───▶ AnalyzerResult
                          │
                          ▼
AnalyzerResult ───▶ CheckVariableTypes ───▶ OperationStatus
                          │
                          ▼
Document ───▶ GetInsertionPointNode ───▶ SyntaxNode (挿入位置)
                          │
                          ▼
Inputs ───▶ CreateCodeGenerator ───▶ CodeGenerator
                          │
                          ▼
CodeGenerator ───▶ GenerateAsync ───▶ (メソッド, 呼び出し)
                          │
                          ▼
Document ───▶ GetFormattedDocument ───▶ (Document, invocationNameToken)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| MethodExtractor.cs | `src/Features/Core/Portable/ExtractMethod/MethodExtractor.cs` | ソース | メイン処理 |
| ExtractMethodResult.cs | `src/Features/Core/Portable/ExtractMethod/ExtractMethodResult.cs` | ソース | 結果構造 |
| SelectionResult.cs | `src/Features/Core/Portable/ExtractMethod/SelectionResult.cs` | ソース | 選択範囲分析 |
| AnalyzerResult.cs | `src/Features/Core/Portable/ExtractMethod/AnalyzerResult.cs` | ソース | 変数分析結果 |
| CodeGenerator.cs | `src/Features/Core/Portable/ExtractMethod/CodeGenerator.cs` | ソース | コード生成 |
| AbstractExtractMethodService.cs | `src/Features/Core/Portable/ExtractMethod/AbstractExtractMethodService.cs` | ソース | サービス基底クラス |
| AbstractExtractMethodCodeRefactoringProvider.cs | `src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs` | ソース | リファクタリングプロバイダー |
| TriviaResult.cs | `src/Features/Core/Portable/ExtractMethod/TriviaResult.cs` | ソース | トリビア処理 |
