# 機能設計書 32-メンバーの引き上げ

## 概要

本ドキュメントは、Roslynの「メンバーの引き上げ（Pull Member Up）」機能の設計仕様を記述する。この機能は、派生クラスのメンバー（メソッド、プロパティ、フィールド、イベント）を基底クラスまたはインターフェースに移動するリファクタリング機能である。

### 本機能の処理概要

**業務上の目的・背景**：オブジェクト指向設計において、共通の機能を基底クラスやインターフェースに集約することは重要な設計パターンである。この機能は、派生クラスで実装されたメンバーを上位の型に移動することで、コードの再利用性を高め、継承階層の適切な設計を促進する。また、インターフェースの事後的な拡張や、Template Methodパターンの実装にも活用できる。

**機能の利用シーン**：開発者が複数の派生クラスで共通する機能を発見し、それを基底クラスに抽出したい場合に使用する。例えば、`Dog`クラスと`Cat`クラスで共通する`Eat()`メソッドを`Animal`基底クラスに引き上げる場面で活用される。

**主要な処理内容**：
1. 選択されたメンバーの検証（有効な引き上げ対象かどうかの判定）
2. 有効な移動先（基底クラス、インターフェース）の特定
3. メンバーの引き上げ処理（インターフェースの場合はシグネチャのみ）
4. 必要に応じてメンバーの修飾子変更（public化、非static化）
5. 抽象メンバーの場合は派生クラスにoverride追加

**関連システム・外部連携**：Visual Studioのダイアログサービスと連携してユーザーインターフェースを提供する。コード生成サービス（ICodeGenerationService）を使用してメンバーを生成する。

**権限による制御**：特になし。ソースコードがあるファイルに対してのみ操作可能であり、生成コードファイルは対象外となる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 7 | メンバー引き上げダイアログ | 主機能 | 基底クラス・インターフェースへのメンバー移動設定 |
| 8 | メンバー引き上げ警告ダイアログ | 補助機能 | メンバー引き上げ操作の問題点表示と確認 |
| 13 | メンバー選択コントロール | 補助機能 | 引き上げ対象メンバーの選択操作 |

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| document | Document | Yes | 操作対象のドキュメント | null不可 |
| selectedMembers | ImmutableArray<ISymbol> | Yes | 選択されたメンバーシンボル | 空配列不可、有効なメンバー種別のみ |
| destination | INamedTypeSymbol | Yes | 引き上げ先の型（基底クラスまたはインターフェース） | クラスまたはインターフェースのみ |
| makeAbstract | bool | No | 抽象メンバーとして引き上げるか | クラスへの引き上げ時のみ有効 |

### 入力データソース

- エディタで選択されたメンバー宣言
- IPullMemberUpOptionsServiceによるダイアログ入力

## 出力仕様

### 出力データ

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

### 出力先

- 派生クラスドキュメント（メンバー削除またはoverride追加）
- 基底クラス/インターフェースドキュメント（メンバー追加）

## 処理フロー

### 処理シーケンス

```
1. 選択されたノードの取得とシンボル解決
   └─ GetSelectedNodesAsync()で選択範囲のノードを取得
   └─ セマンティックモデルからシンボル情報を取得

2. メンバーの検証
   └─ MemberAndDestinationValidator.IsMemberValidで有効性チェック
   └─ 暗黙的に宣言されたメンバーは対象外
   └─ メソッド、プロパティ、イベント、フィールドのみ対象

3. 有効な移動先の検索
   └─ FindAllValidDestinations()で基底クラスとインターフェースを列挙
   └─ フィールドの場合は基底クラスのみ
   └─ ソースコード内の型のみ対象

4. クイックアクションの提供
   └─ 各移動先に対してCodeActionを生成
   └─ ダイアログを使用した詳細設定用アクションも提供

5. メンバーの引き上げ実行
   └─ インターフェースへの場合: PullMembersIntoInterfaceAsync
   └─ クラスへの場合: PullMembersIntoClassAsync

6. メンバーの変換処理
   └─ 静的メンバーを非静的に変換
   └─ 非publicメンバーをpublic化
   └─ インターフェースの場合はシグネチャのみ抽出

7. 元のメンバーの処理
   └─ インターフェースへの引き上げ: 元を削除（インターフェース間）または修飾子変更
   └─ 抽象として引き上げ: 元にoverride追加
   └─ 通常の引き上げ: 元を削除

8. import文の移動と整理
   └─ 必要なusingディレクティブを移動先に追加
   └─ 不要なimportを削除
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[選択ノードの取得]
    B --> C{メンバーは有効か?}
    C -->|No| Z[終了]
    C -->|Yes| D{すべて同一型か?}
    D -->|No| Z
    D -->|Yes| E[有効な移動先を検索]
    E --> F{移動先あり?}
    F -->|No| Z
    F -->|Yes| G[CodeAction生成]
    G --> H{ユーザー選択}
    H -->|キャンセル| Z
    H -->|移動先選択| I{移動先の型?}
    I -->|インターフェース| J[PullMembersIntoInterfaceAsync]
    I -->|クラス| K[PullMembersIntoClassAsync]
    J --> L[メンバーシグネチャ追加]
    K --> M{抽象化?}
    M -->|Yes| N[抽象メンバー追加 + override]
    M -->|No| O[メンバー移動]
    L --> P[元メンバー処理]
    N --> P
    O --> P
    P --> Q[import整理]
    Q --> R[ソリューション更新]
    R --> Z[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-32-01 | 有効メンバー種別 | メソッド（Ordinary）、プロパティ、イベント、フィールドのみ対象 | 常に適用 |
| BR-32-02 | 暗黙宣言除外 | 暗黙的に宣言されたメンバーは対象外 | 常に適用 |
| BR-32-03 | フィールド制約 | フィールドは基底クラスにのみ引き上げ可能（インターフェース不可） | フィールド選択時 |
| BR-32-04 | ソース内型限定 | 引き上げ先はソースコード内の型のみ | 常に適用 |
| BR-32-05 | 生成コード除外 | 生成コードファイルは対象外 | 常に適用 |
| BR-32-06 | 静的インターフェース | 静的メンバーのインターフェース引き上げ時は非静的に変換 | インターフェースへの引き上げ時 |
| BR-32-07 | アクセシビリティ変更 | インターフェースへの引き上げ時は非publicをpublic化 | インターフェースへの引き上げ時 |

### 計算ロジック

有効な移動先の判定：
```
if (すべてのメンバーがフィールド) {
    移動先候補 = 基底クラスのみ
} else {
    移動先候補 = 基底クラス + 実装インターフェース
}
移動先候補 = 移動先候補.Where(IsDestinationValid)
```

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| N/A | 検証エラー | コンストラクタ、演算子、ファイナライザの選択 | リファクタリングを提供しない |
| N/A | 検証エラー | 暗黙的に宣言されたメンバーの選択 | リファクタリングを提供しない |
| N/A | 検証エラー | 有効な移動先が存在しない | リファクタリングを提供しない |
| N/A | 競合エラー | 移動先に同名メンバーが存在 | クイックアクションを非表示 |

### リトライ仕様

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

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

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

## パフォーマンス要件

- 複数のメンバー宣言（partial method等）に対応
- UIのレスポンシブ性を維持するため、キャンセル可能な操作として実装

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

- ソースコードへの書き込み権限が必要
- 生成コードファイルは保護のため対象外

## 備考

- インターフェース間のメンバー引き上げでは、元のメンバーを削除
- クラスへの抽象メンバー引き上げでは、元のクラスを抽象クラスに変更する必要がある場合がある
- プロパティのgetter/setterで異なるアクセシビリティを持つ場合、publicなものだけがインターフェースに追加される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | PullMembersUpOptions.cs | `src/Features/Core/Portable/PullMemberUp/PullMembersUpOptions.cs` | 引き上げオプションの構造。Destination、MemberAnalysisResults、PullUpOperationNeedsToDoExtraChangesを理解する |
| 1-2 | MemberAnalysisResult.cs | `src/Features/Core/Portable/PullMemberUp/MemberAnalysisResult.cs` | 各メンバーの分析結果（変更が必要かどうか等） |

**読解のコツ**: PullMembersUpOptionsは移動先とメンバー分析結果の集約。MemberAnalysisResultは個々のメンバーに対する変換要件を保持する。

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

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

**主要処理フロー**:
1. **24-76行目**: ComputeRefactoringsAsyncメソッド - 選択されたノードの取得とメンバー検証
2. **34-44行目**: メンバーの検証 - IsMemberValidによる有効性チェック
3. **53-58行目**: FindAllValidDestinations - 有効な移動先の検索
4. **61-75行目**: CodeActionの登録 - 各移動先に対するアクションとダイアログアクション

#### Step 3: 検証ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | MemberAndDestinationValidator.cs | `src/Features/Core/Portable/PullMemberUp/MemberAndDestinationValidator.cs` | メンバーと移動先の検証ロジック |

**主要処理フロー**:
- **14-27行目**: IsDestinationValid - 移動先の検証（クラス/インターフェースかつソース内）
- **29-51行目**: IsMemberValid - メンバーの検証（暗黙宣言除外、対象種別チェック）

#### Step 4: メイン処理ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | MembersPuller.cs | `src/Features/Core/Portable/PullMemberUp/MembersPuller.cs` | 実際の引き上げ処理を行うクラス |

**主要処理フロー**:
- **38-57行目**: TryComputeCodeAction - クイックアクション用のCodeAction生成
- **59-71行目**: PullMembersUpAsync - メイン処理の振り分け（インターフェース/クラス）
- **91-147行目**: PullMembersIntoInterfaceAsync - インターフェースへの引き上げ
- **266-397行目**: PullMembersIntoClassAsync - クラスへの引き上げ
- **442-466行目**: MakeAbstractVersion - 抽象メンバーの生成

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

```
AbstractPullMemberUpRefactoringProvider.ComputeRefactoringsAsync
    │
    ├─ GetSelectedNodesAsync (abstract)
    │      └─ 言語固有の実装（C#/VB）
    │
    ├─ MemberAndDestinationValidator.IsMemberValid
    │
    ├─ FindAllValidDestinations
    │      └─ MemberAndDestinationValidator.IsDestinationValid
    │
    └─ CodeAction登録
           │
           ├─ MembersPuller.TryComputeCodeAction (各移動先)
           │      └─ PullMembersUpOptionsBuilder.BuildPullMembersUpOptions
           │
           └─ PullMemberUpWithDialogCodeAction (ダイアログ)
                  │
                  └─ IPullMemberUpOptionsService
                         │
                         └─ MembersPuller.PullMembersUpAsync
                                │
                                ├─ [インターフェースの場合] PullMembersIntoInterfaceAsync
                                │      ├─ GetSymbolsToPullUp
                                │      ├─ ICodeGenerationService.AddMembers
                                │      └─ ChangeMemberToPublicAndNonStatic
                                │
                                └─ [クラスの場合] PullMembersIntoClassAsync
                                       ├─ MakeAbstractVersion (抽象化時)
                                       ├─ ICodeGenerationService.AddMembers
                                       ├─ IAddImportsService.AddImports
                                       └─ IRemoveUnnecessaryImportsService
```

### データフロー図

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

選択されたメンバー ───────▶ AbstractPullMemberUpRefactoringProvider
                                 │
                                 ▼
                        MemberAndDestinationValidator ───▶ 有効メンバー/移動先
                                 │
                                 ▼
ダイアログ選択 ──────────▶ MembersPuller.PullMembersUpAsync ───▶ 変更後Solution
                                 │
                        ┌────────┴────────┐
                        ▼                 ▼
            [インターフェースへ]     [クラスへ]
                        │                 │
                        ▼                 ▼
            PullMembersIntoInterface  PullMembersIntoClass
                        │                 │
                        ▼                 ▼
            シグネチャのみ追加      メンバー全体を追加
                        │                 │
                        └────────┬────────┘
                                 ▼
                    SolutionEditor.GetChangedSolution
                                 │
                                 ▼
                    更新されたソリューション
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AbstractPullMemberUpRefactoringProvider.cs | `src/Features/Core/Portable/PullMemberUp/` | ソース | リファクタリングプロバイダーの基底クラス |
| MembersPuller.cs | `src/Features/Core/Portable/PullMemberUp/` | ソース | メンバー引き上げの実行処理 |
| PullMembersUpOptions.cs | `src/Features/Core/Portable/PullMemberUp/` | ソース | 引き上げオプションのデータ構造 |
| MemberAnalysisResult.cs | `src/Features/Core/Portable/PullMemberUp/` | ソース | メンバー分析結果のデータ構造 |
| MemberAndDestinationValidator.cs | `src/Features/Core/Portable/PullMemberUp/` | ソース | メンバーと移動先の検証 |
| PullMembersUpOptionsBuilder.cs | `src/Features/Core/Portable/PullMemberUp/` | ソース | オプションの構築ヘルパー |
| PullMemberUpWithDialogCodeAction.cs | `src/Features/Core/Portable/PullMemberUp/Dialog/` | ソース | ダイアログ付きCodeAction |
| IPullMemberUpOptionsService.cs | `src/Features/Core/Portable/PullMemberUp/Dialog/` | ソース | ダイアログサービスインターフェース |
