# 帳票設計書 3-dfmt診断レポート

## 概要

本ドキュメントは、serve-dのdfmt診断レポート機能の設計を記述する。dfmtフォーマッタのon/offコメントに関する診断情報を出力し、冗長なdfmt on/off指定や不正なdfmtコマンドを検出する帳票である。

### 本帳票の処理概要

dfmt診断レポートは、D言語ソースコード中のdfmtフォーマッタ制御コメント（`//dfmt on`、`//dfmt off`）を解析し、冗長な指定や不正なコマンドをエディタ上に報告する帳票である。

**業務上の目的・背景**：D言語開発者がdfmtフォーマッタの制御コメントを正しく使用できるよう支援する。冗長な`//dfmt on`（既にオンの状態で再度オン指定）や`//dfmt off`（既にオフの状態で再度オフ指定）、およびタイプミスによる不正なdfmtコメント（例：`//dfmt offs`）を検出し、コードの保守性と可読性を向上させる。

**帳票の利用シーン**：エディタでD言語ソースファイルを編集した際に、dfmt制御コメントの妥当性がリアルタイムにチェックされ、問題があればエディタの診断パネルやインライン表示として報告される。コードフォーマッティングルールの適用範囲制御を正確に行うために利用される。

**主要な出力内容**：
1. 冗長な`dfmt on`の検出（hint + unnecessaryタグ付き）
2. 冗長な`dfmt off`の検出（hint + unnecessaryタグ付き）
3. 不正なdfmtコマンドの検出（warning）

**帳票の出力タイミング**：エディタでD言語ファイルが編集された際にリアルタイムで自動出力される。LSP `textDocument/publishDiagnostics` 通知として送信される。

**帳票の利用者**：D言語開発者（dfmtフォーマッタを使用するプログラマ）

## 帳票種別

診断レポート（LSP Diagnostics通知）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | エディタ診断パネル | LSP `textDocument/publishDiagnostics` | ファイル編集時に自動出力 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | JSON-RPC（LSPプロトコル） |
| 用紙サイズ | N/A（デジタル出力） |
| 向き | N/A |
| ファイル名 | N/A（ストリーム出力） |
| 出力方法 | LSP textDocument/publishDiagnostics通知 |
| 文字コード | UTF-8 |

### PDF固有設定

N/A

### Excel固有設定

N/A

## 帳票レイアウト

### レイアウト概要

LSP PublishDiagnosticsParams構造体として出力する。

```
┌─────────────────────────────────────┐
│     PublishDiagnosticsParams         │
├─────────────────────────────────────┤
│  uri: DocumentUri                    │
│  diagnostics: Diagnostic[]           │
│    ├─ range: TextRange               │
│    ├─ severity: hint / warning       │
│    ├─ code: string                   │
│    ├─ source: "dfmt"                 │
│    ├─ message: string                │
│    └─ tags: [unnecessary]            │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | uri | 診断対象ドキュメントのURI | lint関数の引数document.uri | URI文字列 |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | range | dfmtコメントのテキスト範囲 | DfmtInstruction.index/length -> movePositionBytes() | Position(line,character)のペア | - |
| 2 | severity | 診断の重大度 | 冗長指定: hint、不正コマンド: warning | DiagnosticSeverity列挙値 | - |
| 3 | code | 診断コード | "redundant-on" / "redundant-off" / "unknown-comment" | 文字列 | - |
| 4 | source | 診断ソース識別子 | 固定値 "dfmt" | 文字列 | - |
| 5 | message | 診断メッセージ | 冗長: "Redundant `dfmt on/off`"、不正: "Not a valid dfmt command..." | 人間可読な説明文 | - |
| 6 | tags | 診断タグ | 冗長指定の場合のみunnecessaryタグ | unnecessary | - |

### フッター部

N/A

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| フォーマッティング有効 | config.d.enableFormatting == true | Yes |
| DfmtComponent利用可能 | backend.has!DfmtComponentがtrueであること | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | DfmtInstruction出現順（ソースコード上の位置順） | 昇順 |

### 改ページ条件

N/A

## データベース参照仕様

### 参照テーブル一覧

本帳票はデータベースを使用しない。

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| N/A | - | - |

### テーブル別参照項目詳細

N/A

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| severity | dfmtOn/dfmtOffで冗長 -> hint、unknown -> warning | - | lintDfmt関数内のswitch文（行66-87） |
| 冗長判定 | 現在のfmtOn状態と命令タイプが一致する場合に冗長 | - | `on == fmtOn`の場合に冗長判定（行71） |
| range | DfmtInstruction.indexからmovePositionBytesで開始/終了位置を算出 | - | 行60-64 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[ファイル編集イベント] --> B[lint関数呼び出し]
    B --> C{enableFormatting?}
    C -->|No| Z[終了]
    C -->|Yes| D{DfmtComponent有効?}
    D -->|No| Z
    D -->|Yes| E[findDfmtInstructions実行]
    E --> F[instruction一覧をループ処理]
    F --> G{instructionタイプ?}
    G -->|dfmtOn/dfmtOff| H{現状態と同じ?}
    H -->|Yes| I[冗長診断生成: hint + unnecessary]
    H -->|No| J[fmtOn状態を更新]
    G -->|unknown| K[不正コマンド診断生成: warning]
    I --> F
    J --> F
    K --> F
    F --> L[diagnosticsスロット2に格納]
    L --> M[updateDiagnostics呼び出し]
    M --> Z
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 設定無効 | enableFormattingがfalse | なし（静かに終了） | lint関数がreturnで終了 |
| コンポーネント未登録 | DfmtComponentがbackendに存在しない | なし（静かに終了） | lint関数がreturnで終了 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 1ファイルあたり0〜数件のdfmtコメント |
| 目標出力時間 | ファイル編集後数十ミリ秒以内 |
| 同時出力数上限 | 1ファイルずつ逐次処理 |

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

- ソースコード中のコメントのみを解析しており、外部リソースへのアクセスは行わない
- 個人情報を含まない

## 備考

- DiagnosticSlotは2番が割り当てられている（dfmt.d 行22）
- 3つの診断コード: "redundant-on", "redundant-off", "unknown-comment"（行74, 82）
- fmtOnフラグは初期値trueで、dfmtOnとdfmtOffの命令に応じて切り替わる（行43, 79）
- DfmtComponentのfindDfmtInstructions関数がdfmtコメントの解析を実施

---

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

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

### 推奨読解順序

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

dfmt命令がどのように表現されるかを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | dfmt.d | `source/served/linters/dfmt.d` | DfmtInstruction型の構造（workspaced.com.dfmtからインポート）: type, index, length |
| 1-2 | dfmt.d | `source/served/linters/dfmt.d` | DfmtInstruction.Type列挙: dfmtOn, dfmtOff, unknown（行68-81） |

**読解のコツ**: `DfmtInstruction`はworkspacedライブラリのDfmtComponentで定義される。`findDfmtInstructions`がソースコード内のdfmtコメントを解析して命令リストを返す。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | dfmt.d | `source/served/linters/dfmt.d` | lint関数（行24-36）: 設定チェック後にlintDfmtを呼び出す |

**主要処理フロー**:
1. **行26-28**: enableFormatting設定チェック
2. **行30-32**: DfmtComponentの存在確認
3. **行34**: lintDfmt関数の呼び出しとDiagnosticSlot 2への格納
4. **行35**: updateDiagnosticsの呼び出し

#### Step 3: 診断生成処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | dfmt.d | `source/served/linters/dfmt.d` | lintDfmt関数（行38-91）: dfmt命令を走査して診断を生成する中核ロジック |

**主要処理フロー**:
- **行40**: findDfmtInstructionsでdfmtコメント一覧取得
- **行43**: fmtOnフラグ初期化（true = フォーマッティング有効）
- **行56-88**: 各instructionについてswitch文で分岐
  - **行68-79**: dfmtOn/dfmtOff: 冗長判定（on == fmtOn）で診断生成
  - **行81-86**: unknown: 不正コマンドとしてwarning診断生成
- **行60-64**: movePositionBytesでバイトオフセットからTextRangeを算出

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

```
lint(Document document)                           [dfmt.d:24]
    |
    +-- config(document.uri)                       [dfmt.d:26]
    +-- backend.has!DfmtComponent                  [dfmt.d:30]
    +-- backend.get!DfmtComponent                  [dfmt.d:32]
    +-- lintDfmt(dfmt, document)                   [dfmt.d:34]
    |       +-- dfmt.findDfmtInstructions()        [dfmt.d:40]
    |       +-- document.movePositionBytes()        [dfmt.d:60-61]
    |       +-- [switch instruction.type]
    |           +-- dfmtOn/dfmtOff -> 冗長判定     [dfmt.d:68-79]
    |           +-- unknown -> 不正コマンド診断    [dfmt.d:81-86]
    +-- createDiagnosticsFor!2(uri)                [dfmt.d:34]
    +-- updateDiagnostics(uri)                     [dfmt.d:35]
```

### データフロー図

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

D言語ソースコード -------> findDfmtInstructions() ----> DfmtInstruction[]
(document.rawText)         (dfmtコメント解析)

DfmtInstruction[] -------> lintDfmt()              ----> Diagnostic[]
                           (冗長/不正判定)
                           movePositionBytes()
                           (範囲算出)

Diagnostic[] ------------> createDiagnosticsFor!2() ----> DiagnosticCollection
                           updateDiagnostics()

DiagnosticCollection ----> rpc.send()               ----> LSP publishDiagnostics通知
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| dfmt.d | `source/served/linters/dfmt.d` | ソース | dfmt診断の主処理（lint, lintDfmt関数） |
| diagnosticmanager.d | `source/served/linters/diagnosticmanager.d` | ソース | 診断情報の統合管理・配信 |
| types.d | `source/served/types.d` | ソース | 共通型定義、Configuration構造体 |
| extension.d | `source/served/extension.d` | ソース | LSPサーバー拡張機能の登録 |
