# 機能設計書 42-Equals/GetHashCode生成

## 概要

本ドキュメントは、Roslyn IDEの「Equals/GetHashCode生成」機能の設計を記述したものである。この機能は、選択されたフィールド・プロパティに基づいてEquals()メソッドとGetHashCode()メソッドを自動生成するコードリファクタリング機能である。

### 本機能の処理概要

**業務上の目的・背景**：オブジェクトの等価性判定は、コレクション操作やキャッシュ処理など多くの場面で必要となる基本的な機能である。しかし、Equals()とGetHashCode()を正しく実装するには、すべてのフィールドを考慮し、一貫性のある実装を行う必要があり、手動実装ではミスが発生しやすい。この機能は、選択されたメンバーから適切なEquals()およびGetHashCode()メソッドを自動生成することで、正確で一貫性のある等価性判定の実装を支援する。

**機能の利用シーン**：値オブジェクトやエンティティクラスを作成する際に、開発者がクラスまたは構造体の宣言部にカーソルを置き、またはメンバーを選択してコードアクションメニューから「Generate Equals and GetHashCode」を選択する場面で利用される。

**主要な処理内容**：
1. カーソル位置の検証または選択されたメンバーの抽出
2. 対象型の既存Equals/GetHashCodeメソッドの有無を確認
3. 利用可能なオプション（IEquatable<T>実装、演算子生成）を判定
4. メンバー選択ダイアログの表示（必要な場合）
5. Equals()メソッドの生成（object.Equals(object)のオーバーライド）
6. GetHashCode()メソッドの生成（System.HashCode対応含む）
7. オプションに応じてIEquatable<T>実装と演算子生成

**関連システム・外部連携**：IGenerateEqualsAndGetHashCodeServiceを使用してメソッド生成を行う。System.HashCodeが利用可能な場合は、それを活用した効率的なGetHashCode実装を生成する。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 9 | メンバー選択ダイアログ | 主画面 | 等価性判定に使用するメンバーの選択 |
| 13 | メンバー選択コントロール | 補助機能 | メンバー選択の共通UIコンポーネント |

## 機能種別

コード生成 / リファクタリング

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| document | Document | Yes | 対象ドキュメント | null不可 |
| textSpan | TextSpan | Yes | カーソル位置または選択範囲 | 有効な範囲内 |
| containingType | INamedTypeSymbol | Yes | 対象の型 | クラスまたは構造体 |
| selectedMembers | ImmutableArray<ISymbol> | Yes | 選択されたフィールド/プロパティ | 読み取り可能なインスタンスメンバー |

### 入力データソース

- ソースコードのカーソル位置または選択範囲から取得
- セマンティックモデルを介して型情報とメンバー情報を収集

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Equalsメソッド | IMethodSymbol | object.Equals(object)のオーバーライド |
| GetHashCodeメソッド | IMethodSymbol | object.GetHashCode()のオーバーライド |
| IEquatable<T>.Equalsメソッド | IMethodSymbol | 型固有のEquals実装（オプション） |
| 演算子 | IMethodSymbol[] | ==と!=演算子（オプション） |

### 出力先

ソースコードのクラス/構造体宣言内に挿入

## 処理フロー

### 処理シーケンス

```
1. 入力検証とメンバー抽出
   └─ メンバー選択またはカーソル位置からの推論
2. 既存メソッドチェック
   └─ Equals/GetHashCodeの既存実装有無を確認
3. オプション判定
   └─ IEquatable<T>実装可否、演算子生成可否を判定
4. コードアクション登録
   └─ 「Generate Equals」「Generate Equals and GetHashCode」等
5. メソッド生成
   └─ IGenerateEqualsAndGetHashCodeServiceを使用
6. ドキュメント更新
   └─ 生成されたメソッドを挿入
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{メンバー選択あり?}
    B -->|Yes| C[選択メンバーを使用]
    B -->|No| D{型ヘッダー上?}
    D -->|No| E[終了:リファクタリング不可]
    D -->|Yes| F[ダイアログでメンバー選択]
    C --> G[既存メソッドチェック]
    F --> G
    G --> H{Equalsなし?}
    H -->|Yes| I[Generate Equalsを登録]
    H -->|No| J{GetHashCodeなし?}
    I --> J
    J -->|Yes| K[GetHashCodeのみ生成を登録]
    J -->|No| L[終了]
    K --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 対象メンバー条件 | 読み取り可能なインスタンスフィールド/プロパティのみ対象 | メンバー収集時 |
| BR-02 | 既存メソッド考慮 | 既存のEquals/GetHashCodeがある場合は該当メソッドの生成をスキップ | コードアクション登録時 |
| BR-03 | IEquatable実装条件 | ref structでない場合のみIEquatable<T>を実装可能 | オプション判定時 |
| BR-04 | 演算子生成条件 | ==と!=演算子が未定義の場合のみ生成可能 | オプション判定時 |
| BR-05 | 構造体の自動オプション | 構造体の場合は自動的にIEquatableと演算子を生成 | 構造体処理時 |

### 計算ロジック

**GetHashCodeの生成アルゴリズム**：
1. System.HashCodeが利用可能な場合：`HashCode.Combine()`を使用
2. そうでない場合：乗算と加算による従来のハッシュ計算
3. オーバーフロー対策：uncheckedブロックまたは64ビット演算を使用

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| E-01 | 位置エラー | MiscellaneousFilesワークスペース | リファクタリングを提供しない |
| E-02 | 型エラー | インターフェースまたは静的クラス | リファクタリングを提供しない |
| E-03 | メンバー不在 | 対象メンバーがない | リファクタリングを提供しない |

### リトライ仕様

なし

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

ドキュメント変更は単一のCodeActionでアトミックに適用される

## パフォーマンス要件

- メンバー収集とコード生成は非同期で実行
- System.HashCodeの利用可否判定はコンパイル時に確認

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

特になし

## 備考

- C#とVisual Basicの両言語をサポート
- 実行順序はGenerateConstructorFromMembersの後、AddConstructorParametersFromMembersの前

---

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

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

### 推奨読解順序

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

メソッド生成に必要なインターフェースとサービスを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | IGenerateEqualsAndGetHashCodeService.cs | `src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/` | サービスインターフェースの理解 |

**読解のコツ**: このインターフェースはGenerateEqualsMethod、GenerateGetHashCodeMethod等のメソッドを定義する。

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

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

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

**主要処理フロー**:
1. **53-68行目**: メンバー選択パターンとヘッダー位置パターンの判定
2. **70-120行目**: HandleNonSelectionAsyncでダイアログモードの処理
3. **157-166行目**: GetExistingMemberInfoで既存メソッドの有無を確認
4. **199-236行目**: CreateActionsAsyncでコードアクションを生成

#### Step 3: メソッド生成ロジックを理解する

実際のEquals/GetHashCode生成ロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AbstractGenerateEqualsAndGetHashCodeService.cs | `src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/` | メソッド生成の実装 |

**主要処理フロー**:
- **38-48行目**: GenerateEqualsMethodAsyncでEqualsメソッド生成
- **116-124行目**: GenerateGetHashCodeMethodAsyncでGetHashCode生成
- **146-201行目**: CreateGetHashCodeStatementsでハッシュ計算ロジック選択
  - System.HashCode利用可能時：158-161行目
  - 従来のハッシュ計算：165-166行目
  - オーバーフロー対策：171-200行目

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

```
GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.ComputeRefactoringsAsync
    │
    ├─ GenerateEqualsAndGetHashCodeFromMembersAsync (メンバー選択パターン)
    │      └─ GetSelectedMemberInfoAsync
    │             └─ 選択されたメンバーの抽出
    │
    ├─ HandleNonSelectionAsync (ヘッダー位置パターン)
    │      ├─ IsOnTypeHeader / IsBetweenTypeMembers
    │      └─ CreateActionsAsync
    │
    └─ CreateActionsAsync
           │
           ├─ GetExistingMemberInfo
           │      └─ 既存Equals/GetHashCodeの確認
           │
           ├─ CanImplementIEquatable
           │      └─ IEquatable<T>実装可否判定
           │
           ├─ HasOperators
           │      └─ 演算子存在確認
           │
           └─ GenerateEqualsAndGetHashCodeAction / WithDialogCodeAction
                  │
                  ├─ IGenerateEqualsAndGetHashCodeService.GenerateEqualsMethodAsync
                  │
                  └─ IGenerateEqualsAndGetHashCodeService.GenerateGetHashCodeMethodAsync
                         │
                         └─ CreateGetHashCodeStatements
                                ├─ System.HashCode使用パターン
                                └─ 従来ハッシュ計算パターン
```

### データフロー図

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

カーソル位置/選択 ───▶ 入力検証 ───▶ (検証結果)
      │
      ▼
型シンボル ───▶ 既存メソッドチェック ───▶ 生成対象決定
      │
      ▼
選択メンバー ───▶ オプション判定 ───▶ IEquatable/演算子フラグ
      │
      ▼
生成パラメータ ───▶ メソッド生成 ───▶ Equals/GetHashCode実装
      │
      ▼
生成コード ───▶ ドキュメント挿入 ───▶ 更新ドキュメント
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs | `src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/` | ソース | リファクタリングプロバイダー本体 |
| AbstractGenerateEqualsAndGetHashCodeService.cs | `src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/` | ソース | メソッド生成サービス実装 |
| IGenerateEqualsAndGetHashCodeService.cs | `src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/` | ソース | サービスインターフェース |
| GenerateEqualsAndGetHashCodeAction.cs | `src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/` | ソース | ダイアログなしコードアクション |
| GenerateEqualsAndHashWithDialogCodeAction.cs | `src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/` | ソース | ダイアログ付きコードアクション |
| FormatLargeBinaryExpressionRule.cs | `src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/` | ソース | 大きな二項式のフォーマットルール |
