# 機能設計書 33-メソッドのインライン化

## 概要

本ドキュメントは、Roslynの「メソッドのインライン化（Inline Method）」機能の設計仕様を記述する。この機能は、メソッド呼び出しをそのメソッドの本体で直接置換するリファクタリング機能である。

### 本機能の処理概要

**業務上の目的・背景**：小さなヘルパーメソッドや、単一の式のみを返すメソッドは、インライン化することでコードの可読性が向上する場合がある。また、リファクタリングの過程で不要になったメソッドを削除する際に、その呼び出し箇所を本体で置換する必要がある。この機能は、そのような場面でメソッドの呼び出しを安全に本体に展開する。

**機能の利用シーン**：開発者が単純なメソッドを削除したい場合や、メソッド呼び出しのオーバーヘッドを避けたい場合に使用する。例えば、`int GetValue() => 42;`のようなメソッドの呼び出しを`42`で直接置換する場面で活用される。

**主要な処理内容**：
1. 選択されたメソッド呼び出しの検証（インライン化可能かどうかの判定）
2. メソッド本体（インライン式）の抽出
3. パラメータの置換テーブル作成と適用
4. 必要な変数宣言の生成
5. 呼び出し箇所の置換
6. オプションでメソッド定義の削除

**関連システム・外部連携**：シンボル検索サービス（SymbolFinder）を使用して参照を検索する。コード生成サービスを使用して変数宣言やキャスト式を生成する。

**権限による制御**：privateメソッドのみがインライン化の対象となる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| N/A | N/A | N/A | コードエディタ上のコンテキストメニューから直接実行 |

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| document | Document | Yes | 操作対象のドキュメント | null不可 |
| calleeInvocationNode | TInvocationSyntax | Yes | インライン化するメソッド呼び出しノード | 有効な呼び出し式 |
| removeCalleeDeclarationNode | bool | No | メソッド定義を削除するか | デフォルトfalse |

### 入力データソース

- エディタで選択されたメソッド呼び出し式

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| modifiedSolution | Solution | 変更が適用されたソリューション |

### 出力先

- 呼び出し元ドキュメント（インライン式で置換）
- メソッド定義ドキュメント（削除時のみ）

## 処理フロー

### 処理シーケンス

```
1. メソッド呼び出しノードの取得
   └─ TryGetRelevantNodeAsync()で呼び出し式を取得

2. 呼び出し先メソッドの検証
   └─ privateメソッドのみ対象
   └─ Ordinaryメソッドまたは拡張メソッドのみ
   └─ 可変長引数（vararg）は対象外
   └─ 単一の宣言を持つメソッドのみ

3. インライン式の抽出
   └─ GetRawInlineExpression()でメソッド本体から式を取得
   └─ await式の特殊処理（内部の式を使用）
   └─ throw文/throw式の特殊処理

4. パラメータ情報の構築
   └─ GetMethodParametersInfoAsync()
   └─ リテラル引数、識別子引数、変数宣言引数の分類

5. インラインコンテキストの構築
   └─ GetInlineMethodContextAsync()
   └─ 名前衝突の回避（リネームテーブル生成）
   └─ 置換テーブルの生成（型引数、パラメータ）
   └─ 必要なローカル変数宣言の生成

6. 呼び出し元の変更
   └─ GetChangedCallerAsync()
   └─ async修飾子の追加（必要に応じて）
   └─ 前挿入ステートメントの追加
   └─ インライン式の挿入

7. メソッド定義の削除（オプション）
   └─ removeCalleeDeclarationNodeがtrueの場合

8. ソリューションの更新
   └─ SolutionEditorで変更を適用
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[メソッド呼び出し取得]
    B --> C{privateメソッド?}
    C -->|No| Z[終了]
    C -->|Yes| D{Ordinaryまたは拡張?}
    D -->|No| Z
    D -->|Yes| E{単一宣言?}
    E -->|No| Z
    E -->|Yes| F[インライン式抽出]
    F --> G{式あり?}
    G -->|No| Z
    G -->|Yes| H[パラメータ情報構築]
    H --> I[インラインコンテキスト構築]
    I --> J[リネームテーブル生成]
    J --> K[置換テーブル生成]
    K --> L[呼び出し元変更]
    L --> M{削除オプション?}
    M -->|Yes| N[メソッド定義削除]
    M -->|No| O[ソリューション更新]
    N --> O
    O --> Z[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-33-01 | privateメソッド限定 | インライン化はprivateメソッドのみ対象 | 常に適用 |
| BR-33-02 | 単一宣言要件 | メソッドは単一の宣言のみを持つこと | 常に適用 |
| BR-33-03 | vararg除外 | 可変長引数メソッドは対象外 | 常に適用 |
| BR-33-04 | await式処理 | await式の場合は内部の式を使用 | await式の場合 |
| BR-33-05 | throw式変換 | throw文はthrow式に、throw式はthrow文に変換可能 | 適切なコンテキストの場合 |
| BR-33-06 | 再帰呼び出し | 再帰呼び出しの場合は削除オプション不可 | 呼び出し元と呼び出し先が同一の場合 |

### 計算ロジック

リネームテーブル生成ロジック：
```
for each (変数宣言引数のパラメータ + インライン式内のローカル変数) {
    新しい名前 = GenerateUniqueLocalName(元の名前, 呼び出し位置のコンテキスト)
    リネームテーブル[シンボル] = 新しい名前
}
```

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

該当なし（メモリ上のシンボルとソースコードの操作のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| N/A | 検証エラー | 非privateメソッドの呼び出し | リファクタリングを提供しない |
| N/A | 検証エラー | 複数宣言を持つメソッド | リファクタリングを提供しない |
| N/A | 検証エラー | varargメソッドの呼び出し | リファクタリングを提供しない |
| N/A | 検証エラー | インライン式が抽出できない | リファクタリングを提供しない |

### リトライ仕様

該当なし（インタラクティブな操作のため）

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

SolutionEditorを使用してソリューション全体の変更を管理する。すべての変更が成功するか、すべて適用されないかのいずれかとなる。

## パフォーマンス要件

- シンボル参照の検索は非同期で実行
- UIのレスポンシブ性を維持するため、キャンセル可能な操作として実装

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

- ソースコードへの書き込み権限が必要
- privateメソッドのみを対象とすることで意図しない公開APIの変更を防止

## 備考

- 拡張メソッドの呼び出しもインライン化可能
- 型キャストと括弧が必要に応じて自動的に追加される
- 呼び出し元がasyncでない場合にawaitを含むメソッドをインライン化すると、呼び出し元がasync化される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | AbstractInlineMethodRefactoringProvider.InlineContext.cs | `src/Features/Core/Portable/InlineMethod/` | InlineMethodContext構造体。StatementsToInsertBeforeInvocationOfCallee、InlineExpression、ContainsAwaitExpressionを理解する |
| 1-2 | AbstractInlineMethodRefactoringProvider.MethodParametersInfo.cs | `src/Features/Core/Portable/InlineMethod/` | メソッドパラメータ情報の構造 |

**読解のコツ**: InlineMethodContextは3つの主要な情報を保持する。前挿入ステートメント、インライン式、await式の有無。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AbstractInlineMethodRefactoringProvider.cs | `src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.cs` | CodeRefactoringProviderの実装。ComputeRefactoringsAsyncがエントリーポイント |

**主要処理フロー**:
1. **79-201行目**: ComputeRefactoringsAsyncメソッド - メソッド呼び出しの取得と検証
2. **82-105行目**: 呼び出し先メソッドの検証 - private、Ordinary/拡張、vararg除外、単一宣言
3. **107-136行目**: インライン式の抽出 - await式とthrow式の特殊処理
4. **197-201行目**: CodeActionの登録

#### Step 3: インライン処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AbstractInlineMethodRefactoringProvider.InlineContext.cs | `src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.InlineContext.cs` | インラインコンテキストの構築処理 |

**主要処理フロー**:
- **42-245行目**: GetInlineMethodContextAsync - コンテキスト構築のメイン処理
- **105-112行目**: ComputeRenameTable - 名前衝突回避のリネームテーブル
- **224-229行目**: ComputeReplacementTable - 置換テーブルの生成
- **247-263行目**: GetLocalDeclarationStatementsNeedInsert - 必要なローカル変数宣言

#### Step 4: 呼び出し元の変更を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | AbstractInlineMethodRefactoringProvider.cs | `src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.cs` | 呼び出し元の変更処理（後半部分） |

**主要処理フロー**:
- **229-289行目**: InlineMethodAsync - インライン処理のメイン
- **291-331行目**: GetChangedCallerAsync - 呼び出し元の変更適用
- **333-478行目**: GetInlineNode - インライン後のノード決定（throw変換、変数宣言生成含む）

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

```
AbstractInlineMethodRefactoringProvider.ComputeRefactoringsAsync
    │
    ├─ TryGetRelevantNodeAsync<TInvocationSyntax>
    │
    ├─ SemanticModel.GetSymbolInfo (メソッドシンボル取得)
    │
    ├─ GetRawInlineExpression (abstract)
    │      └─ 言語固有の実装（C#/VB）
    │
    └─ CodeAction.Create
           │
           └─ InlineMethodAsync
                  │
                  ├─ GetMethodParametersInfoAsync
                  │      └─ パラメータの分類と処理
                  │
                  ├─ GetInlineMethodContextAsync
                  │      ├─ ComputeRenameTable
                  │      ├─ GetLocalDeclarationStatementsNeedInsert
                  │      ├─ ComputeReplacementTable
                  │      └─ ReplaceAllSyntaxNodesForSymbolAsync
                  │
                  ├─ GetChangedCallerAsync
                  │      ├─ SyntaxEditor.SetModifiers (async追加)
                  │      ├─ SyntaxEditor.InsertBefore (前挿入)
                  │      └─ GetInlineNode
                  │
                  └─ SolutionEditor.GetChangedSolution
```

### データフロー図

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

メソッド呼び出し ─────────▶ AbstractInlineMethodRefactoringProvider
                                 │
                                 ▼
                        GetRawInlineExpression ───▶ インライン式
                                 │
                                 ▼
                        GetMethodParametersInfoAsync ───▶ パラメータ情報
                                 │
                                 ▼
                        GetInlineMethodContextAsync
                                 │
                        ┌────────┴────────┐
                        ▼                 ▼
              ComputeRenameTable  ComputeReplacementTable
                        │                 │
                        └────────┬────────┘
                                 ▼
                        ReplaceAllSyntaxNodesForSymbol ───▶ 変換後インライン式
                                 │
                                 ▼
                        GetChangedCallerAsync ───▶ 変更後呼び出し元
                                 │
                                 ▼
                        SolutionEditor ───▶ 更新されたソリューション
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AbstractInlineMethodRefactoringProvider.cs | `src/Features/Core/Portable/InlineMethod/` | ソース | リファクタリングプロバイダーの基底クラス |
| AbstractInlineMethodRefactoringProvider.InlineContext.cs | `src/Features/Core/Portable/InlineMethod/` | ソース | インラインコンテキストの構築 |
| AbstractInlineMethodRefactoringProvider.MethodParametersInfo.cs | `src/Features/Core/Portable/InlineMethod/` | ソース | メソッドパラメータ情報の処理 |
| CSharpInlineMethodRefactoringProvider.cs | `src/Features/CSharp/Portable/InlineMethod/` | ソース | C#固有の実装 |
| VisualBasicInlineMethodRefactoringProvider.vb | `src/Features/VisualBasic/Portable/InlineMethod/` | ソース | VB固有の実装 |
