# 機能設計書 46-タプルを構造体に変換

## 概要

本ドキュメントは、Roslyn IDEの「タプルを構造体に変換（Convert Tuple to Struct）」機能の設計を記述したものである。この機能は、タプル型または式を名前付き構造体（またはrecord struct）に変換するコードリファクタリング機能である。

### 本機能の処理概要

**業務上の目的・背景**：タプルは軽量なデータ構造として便利だが、要素名の意味が不明確になりやすく、再利用性も低い。この機能は、タプルを明示的な構造体に変換することで、コードの可読性と保守性を向上させる。また、Equals/GetHashCode/Deconstructメソッドやタプルとの相互変換演算子も自動生成される。

**機能の利用シーン**：開発者がタプル式`(a, b, c)`やタプル型`(int X, string Y)`にカーソルを置き、コードアクションメニューから「Convert to struct」または「Convert to record struct」を選択する場面で利用される。

**主要な処理内容**：
1. カーソル位置のタプル式または型を取得
2. タプル型の情報（要素名、型）を収集
3. 変換スコープの選択（メンバー内/型内/プロジェクト内/依存プロジェクト）
4. 構造体を生成（フィールド、コンストラクタ、Equals/GetHashCode、Deconstruct、変換演算子）
5. タプルの使用箇所を新しい構造体に置換

**関連システム・外部連携**：IRemoteConvertTupleToStructCodeRefactoringServiceを使用してOOP（Out-of-Process）での処理をサポートする。IGenerateEqualsAndGetHashCodeServiceを使用してEquals/GetHashCodeメソッドを生成する。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能には専用の関連画面はない |

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| document | Document | Yes | 対象ドキュメント | null不可 |
| span | TextSpan | Yes | カーソル位置 | 有効な範囲内 |
| tupleExprOrTypeNode | SyntaxNode | Yes | タプル式またはタプル型ノード | null不可 |
| tupleType | INamedTypeSymbol | Yes | タプル型のシンボル | IsTupleType=true |
| scope | Scope | Yes | 変換スコープ | 有効なスコープ |
| isRecord | bool | Yes | record structとして生成するか | - |

### 入力データソース

- ソースコードのカーソル位置からタプル式/型を取得
- セマンティックモデルから型情報を取得

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 構造体定義 | INamedTypeSymbol | 生成された構造体 |
| コンストラクタ | IMethodSymbol | プロパティ初期化コンストラクタ |
| Equalsメソッド | IMethodSymbol | 等価性判定メソッド |
| GetHashCodeメソッド | IMethodSymbol | ハッシュコード生成メソッド |
| Deconstructメソッド | IMethodSymbol | 分解メソッド |
| 変換演算子 | IMethodSymbol[] | タプルとの相互変換 |

### 出力先

- 構造体定義：現在の名前空間または最上位
- タプル使用箇所：新しい構造体への置換

## 処理フロー

### 処理シーケンス

```
1. タプル情報取得
   └─ TryGetTupleInfoAsyncでタプル式/型と型情報を取得
2. 変換可否チェック
   └─ 匿名型を含むタプルは変換不可
3. スコープ選択肢生成
   └─ メンバー/型/プロジェクト/依存プロジェクトのスコープ
4. 構造体生成
   └─ GenerateFinalNamedTypeAsyncで完全な構造体を生成
5. タプル置換
   └─ ReplaceExpressionAndTypesInScopeAsyncでスコープ内の使用箇所を置換
6. ドキュメント更新
   └─ ApplyChangesAsyncで変更を適用
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{タプル式/型あり?}
    B -->|No| C[終了:リファクタリング不可]
    B -->|Yes| D[タプル型情報取得]
    D --> E{匿名型を含む?}
    E -->|Yes| C
    E -->|No| F[変換スコープ選択肢生成]
    F --> G{record structサポート?}
    G -->|Yes| H[record struct選択肢追加]
    G -->|No| I[struct選択肢のみ]
    H --> J[構造体生成]
    I --> J
    J --> K[タプル使用箇所置換]
    K --> L[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 匿名型禁止 | タプル要素に匿名型を含む場合は変換不可 | タプル検証時 |
| BR-02 | スコープ制限（メソッド型パラメータ） | メソッド型パラメータを参照する場合はメンバー内スコープのみ | スコープ生成時 |
| BR-03 | スコープ制限（型パラメータ） | 型パラメータを参照する場合は型内スコープまで | スコープ生成時 |
| BR-04 | 全要素名前付き条件 | プロジェクト/依存プロジェクトスコープは全要素に名前が必要 | スコープ生成時 |
| BR-05 | record struct条件 | SupportsRecordStructがtrueの場合のみ選択可能 | アクション生成時 |
| BR-06 | アクセシビリティ | 依存プロジェクトスコープではPublic、それ以外はInternal | 構造体生成時 |

### 計算ロジック

**生成される構造体のメンバー**：
- recordでない場合：フィールド、コンストラクタ、Equals、GetHashCode、Deconstruct
- recordの場合：コンストラクタのみ（他は自動合成）
- 共通：タプルとの相互変換演算子

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

該当なし（ソースコード操作のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| E-01 | タプル不在 | タプル式/型が見つからない | リファクタリングを提供しない |
| E-02 | 匿名型含有 | タプル要素に匿名型を含む | リファクタリングを提供しない |

### リトライ仕様

なし

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

ソリューション変更は単一のApplyChangesAsyncでアトミックに適用される

## パフォーマンス要件

- OOPサポートによりリモート処理が可能
- プロジェクト/依存プロジェクトスコープでは複数ドキュメントを並列処理

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

特になし

## 備考

- C#とVisual Basicの両言語をサポート
- リモートホストが利用可能な場合はOOPで処理

---

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

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

### 推奨読解順序

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

Scope列挙型とDocumentToUpdateの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Scope.cs | `src/Features/Core/Portable/ConvertTupleToStruct/` | スコープ列挙型 |
| 1-2 | DocumentToUpdate.cs | `src/Features/Core/Portable/ConvertTupleToStruct/` | 更新対象ドキュメント情報 |

**読解のコツ**: Scopeは ContainingMember, ContainingType, ContainingProject, DependentProjects の4種類。

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

リファクタリングプロバイダーが処理の起点となる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AbstractConvertTupleToStructCodeRefactoringProvider.cs | `src/Features/Core/Portable/ConvertTupleToStruct/` | ComputeRefactoringsAsyncが開始点 |

**主要処理フロー**:
1. **61-116行目**: ComputeRefactoringsAsyncでタプル取得とアクション登録
2. **183-214行目**: TryGetTupleInfoAsyncでタプル情報取得
3. **216-247行目**: ConvertToStructAsyncでOOP/ローカル処理分岐
4. **262-322行目**: ConvertToStructInCurrentProcessAsyncでローカル処理

#### Step 3: 構造体生成ロジックを理解する

構造体の生成ロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AbstractConvertTupleToStructCodeRefactoringProvider.cs | `src/Features/Core/Portable/ConvertTupleToStruct/` | GenerateFinalNamedTypeAsyncメソッド |

**主要処理フロー**:
- **798-851行目**: GenerateFinalNamedTypeAsyncで構造体生成
- **853-877行目**: GenerateDeconstructMethodでDeconstructメソッド生成
- **879-906行目**: AddConversionsで変換演算子生成
- **908-919行目**: CreateNamedTypeで最終的な型を生成

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

```
AbstractConvertTupleToStructCodeRefactoringProvider.ComputeRefactoringsAsync
    │
    ├─ TryGetTupleInfoAsync
    │      └─ タプル式/型と型情報の取得
    │
    ├─ CreateChildActions
    │      └─ スコープ別のアクション生成
    │
    └─ ConvertToStructAsync
           │
           ├─ RemoteHostClient.TryGetClientAsync
           │      └─ OOP処理（利用可能な場合）
           │
           └─ ConvertToStructInCurrentProcessAsync
                  │
                  ├─ GenerateFinalNamedTypeAsync
                  │      │
                  │      ├─ CreateNamedType（空の型）
                  │      │
                  │      ├─ CreateConstructor
                  │      │
                  │      ├─ GenerateEqualsMethodAsync
                  │      │
                  │      ├─ GenerateGetHashCodeMethodAsync
                  │      │
                  │      ├─ GenerateDeconstructMethod
                  │      │
                  │      └─ AddConversions
                  │
                  ├─ ReplaceExpressionAndTypesInScopeAsync
                  │      └─ タプル使用箇所の置換
                  │
                  └─ GenerateStructIntoContainingNamespaceAsync
                         └─ 構造体定義の挿入
```

### データフロー図

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

カーソル位置 ───▶ タプル取得 ───▶ タプルノード
      │
      ▼
タプルノード ───▶ 型情報取得 ───▶ タプル型シンボル
      │
      ▼
スコープ選択 ───▶ 対象ドキュメント収集 ───▶ DocumentToUpdate一覧
      │
      ▼
タプル型 ───▶ 構造体生成 ───▶ 構造体シンボル
      │
      ▼
スコープ内タプル ───▶ 置換処理 ───▶ 更新ドキュメント群
      │
      ▼
構造体 ───▶ 名前空間挿入 ───▶ 最終ソリューション
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AbstractConvertTupleToStructCodeRefactoringProvider.cs | `src/Features/Core/Portable/ConvertTupleToStruct/` | ソース | リファクタリングプロバイダー本体 |
| Scope.cs | `src/Features/Core/Portable/ConvertTupleToStruct/` | ソース | スコープ列挙型 |
| DocumentToUpdate.cs | `src/Features/Core/Portable/ConvertTupleToStruct/` | ソース | 更新対象情報 |
| IRemoteConvertTupleToStructCodeRefactoringService.cs | `src/Features/Core/Portable/ConvertTupleToStruct/` | ソース | OOPサービスインターフェース |
| IConvertTupleToStructCodeRefactoringProvider.cs | `src/Features/Core/Portable/ConvertTupleToStruct/` | ソース | プロバイダーインターフェース |
