# 機能設計書 65-診断アナライザ

## 概要

本ドキュメントは、Visual Studio統合におけるF#の診断アナライザ機能の設計について記述する。この機能は、コンパイルエラー・警告、未使用のopen文、未使用の宣言、不要な括弧などのコード品質問題を検出し、エディタ上に表示する。

### 本機能の処理概要

**業務上の目的・背景**：
コードの品質を維持し、潜在的な問題を早期に発見することは、ソフトウェア開発において重要である。本機能により、開発者はコーディング中にリアルタイムで問題を把握でき、コードレビュー前に多くの問題を解決できる。

**機能の利用シーン**：
- コード入力中にエラーや警告を即座に確認したい場合
- 未使用のopen文を検出してコードを整理したい場合
- 未使用の変数や関数を特定したい場合
- 不要な括弧を検出してコードを簡潔にしたい場合

**主要な処理内容**：
1. ドキュメントの解析結果から診断情報を収集
2. 構文診断（パースエラー）の検出
3. セマンティック診断（型エラー等）の検出
4. 追加アナライザ（未使用open、未使用宣言、不要括弧）の実行
5. 診断結果をRoslynのDiagnostic形式に変換
6. エディタ上に波線やエラーリストとして表示

**関連システム・外部連携**：
- Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics: Roslyn診断インターフェース
- FSharp.Compiler.Diagnostics: F#コンパイラの診断情報
- FSharp.Compiler.EditorServices: 未使用open検出API

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 3 | Code Fixes オプション設定画面 | 設定画面 | 未使用open、未使用宣言、括弧削除の有効/無効設定 |

## 機能種別

コード解析・品質チェック機能

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| document | Document | Yes | 解析対象のドキュメント | null不可 |
| cancellationToken | CancellationToken | Yes | キャンセルトークン | - |

### 入力データソース

- F#コンパイラの解析結果（パース結果、型チェック結果）
- プロジェクト設定（診断の有効/無効）
- エディタオプション（不要括弧検出の有効/無効）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Diagnostics | ImmutableArray<Diagnostic> | 検出された診断情報のコレクション |

### 出力先

- Visual Studio エディタ（波線表示）
- エラーリストウィンドウ
- ソリューションエクスプローラー（ファイルアイコン）

## 処理フロー

### 処理シーケンス

```
1. 診断種別の判定
   └─ Syntax（構文）かSemantic（意味論）かを判定

2. 解析結果の取得
   └─ GetFSharpParseResultsAsync / GetFSharpParseAndCheckResultsAsync

3. コンパイラ診断の収集
   └─ parseResults.Diagnostics / checkResults.Diagnostics

4. 追加アナライザの実行
   └─ 不要括弧アナライザ（Syntax時のみ）

5. 診断情報の変換
   └─ FSharpDiagnosticをRoslyn Diagnosticに変換

6. 位置情報の補正
   └─ ファイル末尾エラーの位置補正

7. 結果の返却
   └─ ImmutableArray<Diagnostic>として返却
```

### フローチャート

```mermaid
flowchart TD
    A[診断リクエスト] --> B{診断種別?}
    B -->|Syntax| C[GetFSharpParseResultsAsync]
    B -->|Semantic| D[GetFSharpParseAndCheckResultsAsync]
    C --> E[parseResults.Diagnostics収集]
    D --> F[checkResults.Diagnostics収集]
    E --> G{不要括弧有効?}
    F --> G
    G -->|Yes| H[UnnecessaryParenthesesDiagnosticAnalyzer]
    G -->|No| I[診断変換]
    H --> I
    I --> J[位置補正]
    J --> K[ImmutableArray生成]
    K --> L[返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-65-01 | メタデータ除外 | メタデータファイル（参照アセンブリ）は診断対象外 | ドキュメント判定時 |
| BR-65-02 | Miscellaneous除外 | MiscellaneousFilesプロジェクトのF#ファイルはセマンティック診断対象外 | Semantic診断時 |
| BR-65-03 | スクリプト例外 | .fsxファイルはMiscellaneousでもセマンティック診断を実行 | Semantic診断時 |
| BR-65-04 | 重複排除 | 同一診断は重複排除（HashSetで管理） | 診断収集時 |
| BR-65-05 | 位置補正 | ファイル末尾を超える診断位置は末尾に補正 | 変換時 |

### 計算ロジック

位置補正ロジック（136-142行目）：
```fsharp
let correctedTextSpan =
    if textSpan.End <= sourceText.Length then
        textSpan
    else
        let start = min textSpan.Start (sourceText.Length - 1) |> max 0
        TextSpan.FromBounds(start, sourceText.Length)
```

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

該当なし（メモリ内解析のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 解析失敗 | F#コンパイラサービスが解析に失敗 | 空の診断リストを返却 |
| - | 位置不正 | 診断位置がファイル範囲外 | 位置を補正 |

### リトライ仕様

リトライなし。解析失敗時は空のリストを返却。

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

該当なし（読み取り専用操作）

## パフォーマンス要件

- バックグラウンドで非同期実行
- ユーザー入力に応じてインクリメンタルに更新
- テレメトリでパフォーマンスを監視

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

該当なし

## 備考

- DocumentDiagnosticAnalyzerがメインのアナライザ
- UnusedOpensDiagnosticAnalyzer、UnusedDeclarationsAnalyzer、SimplifyNameDiagnosticAnalyzer、UnnecessaryParenthesesDiagnosticAnalyzerが追加アナライザ
- 診断IDはFSharpIDEDiagnosticIdsで管理

---

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

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

### 推奨読解順序

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

診断アナライザで使用される主要なデータ型を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | DocumentDiagnosticAnalyzer.fs | `vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs` | DiagnosticsType、FSharpDiagnostic型 |

**読解のコツ**:
- DiagnosticsType（19-22行目）: Syntax/Semanticの判別共用体
- FSharpDiagnostic: F#コンパイラの診断情報型（Compiler.Diagnostics）

#### Step 2: メインアナライザを理解する

FSharpDocumentDiagnosticAnalyzerがエントリーポイント。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | DocumentDiagnosticAnalyzer.fs | `vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs` | FSharpDocumentDiagnosticAnalyzerクラス |

**主要処理フロー**:
1. **24-25行目**: クラス定義とExportアトリビュート
2. **151-171行目**: IFSharpDocumentDiagnosticAnalyzerインターフェース実装
3. **153-161行目**: AnalyzeSyntaxAsyncメソッド
4. **163-171行目**: AnalyzeSemanticsAsyncメソッド

#### Step 3: 診断取得ロジックを理解する

GetDiagnostics静的メソッドが診断を収集。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | DocumentDiagnosticAnalyzer.fs | `vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs` | GetDiagnosticsメソッド |

**主要処理フロー**:
- **57-149行目**: GetDiagnostics静的メソッド
- **60-68行目**: テレメトリ用プロパティ設定
- **78行目**: HashSetで診断の重複排除
- **80行目**: パース結果取得
- **99-112行目**: Syntax/Semanticに応じた診断収集
- **114-118行目**: 不要括弧アナライザの実行
- **125-145行目**: F#診断からRoslyn診断への変換

#### Step 4: 未使用openアナライザを理解する

UnusedOpensDiagnosticAnalyzerが未使用open文を検出。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | UnusedOpensDiagnosticAnalyzer.fs | `vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs` | UnusedOpensDiagnosticAnalyzerクラス |

**主要処理フロー**:
- **19-20行目**: クラス定義
- **22-36行目**: GetUnusedOpenRanges静的メソッド
- **33行目**: UnusedOpens.getUnusedOpensでコンパイラAPI呼び出し
- **40-56行目**: AnalyzeSemanticsAsync実装

#### Step 5: 診断設定を理解する

プロジェクト設定による診断の有効/無効制御。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | DocumentDiagnosticAnalyzer.fs | `vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs` | shouldProduceDiagnostics関数 |

**主要処理フロー**:
- **27-28行目**: shouldProduceDiagnostics関数
- **154-157行目**: メタデータファイル・設定による除外判定
- **164-167行目**: MiscellaneousFiles除外とスクリプト例外

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

```
IFSharpDocumentDiagnosticAnalyzer
    │
    ├─ AnalyzeSyntaxAsync
    │      └─ GetDiagnostics (DiagnosticsType.Syntax)
    │             │
    │             ├─ document.GetFSharpParseResultsAsync
    │             │
    │             ├─ parseResults.Diagnostics収集
    │             │
    │             ├─ UnnecessaryParenthesesDiagnosticAnalyzer.GetDiagnostics
    │             │
    │             └─ RoslynHelpers.ConvertError
    │
    └─ AnalyzeSemanticsAsync
           └─ GetDiagnostics (DiagnosticsType.Semantic)
                  │
                  ├─ document.GetFSharpParseAndCheckResultsAsync
                  │
                  ├─ checkResults.Diagnostics収集
                  │
                  └─ RoslynHelpers.ConvertError

IFSharpUnusedOpensDiagnosticAnalyzer (別アナライザ)
    │
    └─ AnalyzeSemanticsAsync
           │
           └─ GetUnusedOpenRanges
                  │
                  └─ UnusedOpens.getUnusedOpens
```

### データフロー図

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

Document ─────────────▶ GetFSharpParseResultsAsync ──┐
                              │                      │
                              ▼                      │
                        parseResults.Diagnostics     │
                              │                      │
                              ▼                      │
Document ─────────────▶ GetFSharpParseAndCheckResultsAsync
                              │                      │
                              ▼                      │
                        checkResults.Diagnostics     │
                              │                      │
                              ▼                      │
                        UnnecessaryParentheses ──────┤
                              │                      │
                              ▼                      │
                        RoslynHelpers.ConvertError ──┤
                              │                      │
                              ▼                      ▼
                        ImmutableArray<Diagnostic> ──▶ VS エラーリスト
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| DocumentDiagnosticAnalyzer.fs | `vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs` | ソース | メイン診断アナライザ |
| UnusedOpensDiagnosticAnalyzer.fs | `vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs` | ソース | 未使用open検出 |
| UnusedDeclarationsAnalyzer.fs | `vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs` | ソース | 未使用宣言検出 |
| SimplifyNameDiagnosticAnalyzer.fs | `vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs` | ソース | 名前簡略化提案 |
| UnnecessaryParenthesesDiagnosticAnalyzer.fs | `vsintegration/src/FSharp.Editor/Diagnostics/UnnecessaryParenthesesDiagnosticAnalyzer.fs` | ソース | 不要括弧検出 |
| RoslynHelpers.fs | `vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs` | ソース | Roslyn Diagnostic変換 |
