# 機能設計書 29-フィールドのカプセル化

## 概要

本ドキュメントは、Roslynにおける「フィールドのカプセル化」機能の設計を記述するものである。フィールドのカプセル化機能は、パブリックフィールドをプライベートフィールドとプロパティに変換し、すべての参照をプロパティ経由のアクセスに更新するリファクタリング機能である。

### 本機能の処理概要

フィールドのカプセル化機能は、クラスの公開フィールドをカプセル化し、プロパティ経由でアクセスするように変更する。フィールドはプライベートに変更され、新しいプロパティがそのフィールドへのアクセスを提供する。すべての参照はプロパティ経由に自動更新される。

**業務上の目的・背景**：オブジェクト指向プログラミングにおいて、フィールドの直接公開は推奨されない。フィールドをプロパティでラップすることで、将来的な検証ロジックの追加や、変更通知の実装が可能になる。また、APIの安定性を維持しながら内部実装を変更できるようになる。

**機能の利用シーン**：
1. パブリックフィールドをプロパティに変換する
2. フィールドにアクセス制御を追加する
3. 将来的なバリデーション追加の準備
4. コード品質改善のためのリファクタリング

**主要な処理内容**：
1. フィールドの選択
2. プロパティ名の生成(フィールド名からPascalCase)
3. フィールドをプライベートに変更
4. プロパティの生成(getter/setter)
5. すべての参照をプロパティへ更新

**関連システム・外部連携**：
- CodeRefactoringProvider経由でエディタに統合
- Rename機能との連携(参照の更新)
- OOP(Out of Process)サービスとの連携

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | ライトバルブメニュー | 主画面 | カプセル化アクションの選択 |
| 20 | プレビューペイン | 補助画面 | 変更箇所のプレビュー |

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| document | Document | Yes | 対象のドキュメント | 有効なドキュメントであること |
| span | TextSpan | Yes | 選択範囲 | フィールド宣言を含むこと |
| updateReferences | bool | Yes | 参照を更新するか | - |

### 入力データソース

- ドキュメントの構文ツリー(SyntaxTree)
- セマンティックモデル(SemanticModel)

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| EncapsulateFieldResult | EncapsulateFieldResult | カプセル化結果 |
| Solution | Solution | 更新後のソリューション |

### 出力先

- カプセル化されたソリューションとして返却

## 処理フロー

### 処理シーケンス

```
1. フィールドの取得(GetFieldsAsync)
   └─ 選択範囲内のフィールドを取得
2. フィールド名・プロパティ名の生成
   └─ GenerateFieldAndPropertyNamesでフィールド名とプロパティ名を決定
3. OOP実行試行
   └─ IRemoteEncapsulateFieldService経由でリモート実行を試みる
4. ローカル実行
   └─ EncapsulateFieldsInCurrentProcessAsyncでローカル実行
5. 参照更新(updateReferences=trueの場合)
   └─ Renamerを使用してフィールド参照をプロパティに更新
6. フィールド書き換え
   └─ RewriteFieldNameAndAccessibilityAsyncでフィールドをプライベートに変更
7. プロパティ追加
   └─ AddPropertyAsyncで新しいプロパティを追加
8. 整形
   └─ Formatter, Simplifierで整形
```

### フローチャート

```mermaid
flowchart TD
    A[開始: EncapsulateFieldsAsync] --> B[GetFieldsAsync]
    B --> C{フィールドあり?}
    C -->|No| D[null返却]
    C -->|Yes| E{OOPクライアント利用可能?}
    E -->|Yes| F[IRemoteEncapsulateFieldService]
    E -->|No| G[EncapsulateFieldsInCurrentProcessAsync]
    F --> H{成功?}
    H -->|No| G
    H -->|Yes| I[結果返却]
    G --> J[各フィールドを順次処理]
    J --> K[GenerateFieldAndPropertyNames]
    K --> L[UpdateReferencesAsync]
    L --> M{readonly?}
    M -->|Yes| N[コンストラクタ内外で分離更新]
    M -->|No| O[全参照を更新]
    N --> P[RewriteFieldNameAndAccessibilityAsync]
    O --> P
    P --> Q[GenerateProperty]
    Q --> R[AddPropertyAsync]
    R --> S[Formatter/Simplifier]
    S --> I
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | プロパティ名生成 | アンダースコアやm_プレフィックスを除去してPascalCase化 | 常時 |
| BR-02 | readonlyフィールド | setterを生成しない | field.IsReadOnly時 |
| BR-03 | constフィールド | setterを生成しない | field.IsConst時 |
| BR-04 | コンストラクタ内参照 | readonlyフィールドの場合、コンストラクタ内の参照はフィールド名を維持 | field.IsReadOnly時 |
| BR-05 | アクセシビリティ | プロパティは元のフィールドのアクセシビリティを継承(privateはpublicに) | 常時 |

### 計算ロジック

プロパティ名生成ロジック:
1. 先頭のアンダースコアを除去
2. "m_"プレフィックスを除去
3. 結果が空の場合は元のフィールド名を使用
4. 先頭を大文字化(en-USカルチャを使用)

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | フィールドなし | 選択範囲にフィールドがない | null返却 |
| - | シンボル解決失敗 | フィールドシンボルが解決できない | 該当フィールドをスキップ |

### リトライ仕様

なし(OOP失敗時はローカルにフォールバック)

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

該当なし

## パフォーマンス要件

- Logger.LogBlockでロギング
- OOP実行でUIスレッドをブロックしない
- 複数フィールドは順次処理(並列ではない)

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

- 特になし

## 備考

- Renamer.FindRenameLocationsAsyncを使用して参照を検索
- リンクされたドキュメントは自動的に除外(手動で更新は不要)
- staticフィールドはthis.を使用せずにアクセス

---

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

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

### 推奨読解順序

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

まず、フィールドカプセル化で使用される主要なデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | EncapsulateFieldResult.cs | `src/Features/Core/Portable/EncapsulateField/EncapsulateFieldResult.cs` | 結果構造 |
| 1-2 | IEncapsulateFieldService.cs | `src/Features/Core/Portable/EncapsulateField/IEncapsulateFieldService.cs` | サービスインターフェース |

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

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

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

**主要処理フロー**:
1. **45-56行目**: EncapsulateFieldsInSpanAsync - 範囲内のフィールドを取得
2. **58-80行目**: GetEncapsulateFieldCodeActionsAsync - CodeAction取得
3. **110-139行目**: EncapsulateFieldsAsync - OOP試行とフォールバック
4. **141-165行目**: EncapsulateFieldsInCurrentProcessAsync - ローカル実行
5. **167-228行目**: EncapsulateFieldAsync - 単一フィールドのカプセル化

#### Step 3: 参照更新を理解する

Renamerを使用した参照更新ロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AbstractEncapsulateFieldService.cs | `src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs` | 230-273行目: UpdateReferencesAsync |

**読解ポイント**:
- **240-264行目**: readonlyフィールドのコンストラクタ内/外での分離処理
- **275-295行目**: RenameAsync - Renamerを使用した参照更新

#### Step 4: プロパティ生成を理解する

プロパティのシンボル生成ロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | AbstractEncapsulateFieldService.cs | `src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs` | 337-361行目: GenerateProperty |
| 4-2 | AbstractEncapsulateFieldService.cs | `src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs` | 416-433行目: GeneratePropertyName |

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

```
AbstractEncapsulateFieldService.EncapsulateFieldsAsync
    │
    ├─ RemoteHostClient.TryGetClientAsync
    │      └─ IRemoteEncapsulateFieldService.EncapsulateFieldsAsync (OOP)
    │
    └─ EncapsulateFieldsInCurrentProcessAsync
           │
           └─ EncapsulateFieldAsync (各フィールドごと)
                  │
                  ├─ GenerateFieldAndPropertyNames
                  │
                  ├─ UpdateReferencesAsync
                  │      ├─ GetConstructorLocations
                  │      └─ RenameAsync
                  │             └─ Renamer.FindRenameLocationsAsync
                  │
                  ├─ RewriteFieldNameAndAccessibilityAsync
                  │
                  ├─ GenerateProperty
                  │      ├─ CreateGet
                  │      └─ CreateSet
                  │
                  └─ AddPropertyAsync
                         └─ ICodeGenerationService.AddPropertyAsync
```

### データフロー図

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

TextSpan ───▶ GetFieldsAsync ───▶ ImmutableArray<IFieldSymbol>
                      │
                      ▼
IFieldSymbol ───▶ GenerateFieldAndPropertyNames ───▶ (fieldName, propertyName)
                      │
                      ▼
FieldSymbol ───▶ UpdateReferencesAsync ───▶ Solution (参照更新済み)
                      │
                      ▼
Solution ───▶ RewriteFieldNameAndAccessibilityAsync ───▶ SyntaxNode
                      │
                      ▼
Field ───▶ GenerateProperty ───▶ IPropertySymbol
                      │
                      ▼
Property ───▶ AddPropertyAsync ───▶ Solution (プロパティ追加済み)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AbstractEncapsulateFieldService.cs | `src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs` | ソース | メイン処理 |
| IEncapsulateFieldService.cs | `src/Features/Core/Portable/EncapsulateField/IEncapsulateFieldService.cs` | ソース | サービスインターフェース |
| EncapsulateFieldResult.cs | `src/Features/Core/Portable/EncapsulateField/EncapsulateFieldResult.cs` | ソース | 結果構造 |
| EncapsulateFieldCodeRefactoringProvider.cs | `src/Features/Core/Portable/EncapsulateField/EncapsulateFieldCodeRefactoringProvider.cs` | ソース | CodeRefactoringProvider |
| IRemoteEncapsulateFieldService.cs | `src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs` | ソース | OOPサービスインターフェース |
