# 機能設計書 37-dfmtリント

## 概要

本ドキュメントは、dfmtのフォーマットルールに基づく診断（冗長な `//dfmt on`/`//dfmt off` コメント、不正なdfmtコマンドコメント）を提供するdfmtリント機能の設計を記述する。

### 本機能の処理概要

**業務上の目的・背景**：D言語のフォーマッタであるdfmtは、`//dfmt off` と `//dfmt on` のコメント指示でフォーマット対象の制御を行う。これらの指示が冗長（既にon/offの状態と同じ指示を出す）であったり、スペルミスによりdfmtに認識されないコメントが存在する場合がある。本機能はこのような問題を検出し、開発者に警告する。

**機能の利用シーン**：テキストドキュメントの変更時（textDocument/didChange）にデバウンス付きで自動実行される。エディタ上に診断結果として冗長な指示やスペルミスを表示する。

**主要な処理内容**：
1. フォーマット機能が有効か設定を確認する
2. DfmtComponentが利用可能か確認する
3. DfmtComponent.findDfmtInstructions でdfmt指示コメントを検出する
4. 各指示について冗長性チェック・不正コマンドチェックを行う
5. 診断結果を生成し、診断マネージャ経由でクライアントに配信する

**関連システム・外部連携**：DfmtComponent（workspace-dサブパッケージ）がdfmt指示の解析を担当する。

**権限による制御**：設定項目 `d.enableFormatting`（デフォルトtrue）がtrueの場合のみ実行される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 35 | dfmt リント | 主画面 | dfmtのフォーマットルールに基づく診断を提供 |

## 機能種別

静的解析処理（コメントパターン解析・診断生成）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| document | Document | Yes | 解析対象のテキストドキュメント | - |

### 入力データソース

DocumentManagerから取得したドキュメントオブジェクト。テキストドキュメントの変更イベントからデバウンス付きでトリガーされる。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Diagnostic.range | TextRange | dfmt指示コメントのテキスト範囲 |
| Diagnostic.severity | DiagnosticSeverity | 冗長な場合はhint、不正コマンドの場合はwarning |
| Diagnostic.source | string | "dfmt" |
| Diagnostic.message | string | 診断メッセージ |
| Diagnostic.code | JsonValue | 診断コード（"redundant-on", "redundant-off", "unknown-comment"） |
| Diagnostic.tags | DiagnosticTag[] | 冗長な場合はunnecessaryタグ |

### 出力先

診断マネージャ（DiagnosticSlot=2）経由で `textDocument/publishDiagnostics` 通知としてクライアントに送信。

## 処理フロー

### 処理シーケンス

```
1. 設定チェック
   └─ config.d.enableFormatting がtrueか確認
   └─ falseの場合は処理終了
2. DfmtComponent利用可能性チェック
   └─ backend.has!DfmtComponent で確認
   └─ 利用不可の場合は処理終了
3. dfmt指示コメント検出
   └─ dfmt.findDfmtInstructions(document.rawText) で指示一覧を取得
4. 各指示の診断生成
   └─ fmtOn状態を追跡しながら各指示を処理:
     └─ dfmtOn/dfmtOff指示:
       └─ 現在の状態と同じ場合: "Redundant `dfmt on/off`" (hint, unnecessaryタグ)
       └─ 状態を更新
     └─ unknown指示:
       └─ "Not a valid dfmt command" (warning)
5. 診断マネージャに配信
   └─ createDiagnosticsFor!DiagnosticSlot(document.uri) に結果を格納
   └─ updateDiagnostics(document.uri)
```

### フローチャート

```mermaid
flowchart TD
    A[lint呼び出し] --> B{フォーマット有効?}
    B -->|No| Z[処理終了]
    B -->|Yes| C{DfmtComponent利用可能?}
    C -->|No| Z
    C -->|Yes| D[findDfmtInstructions実行]
    D --> E[各指示を処理]
    E --> F{指示種別?}
    F -->|dfmtOn/Off| G{現在の状態と同じ?}
    G -->|Yes| H[冗長診断 hint生成]
    G -->|No| I[状態更新]
    F -->|unknown| J[不正コマンド warning生成]
    H --> K[次の指示]
    I --> K
    J --> K
    K --> E
    K --> L[診断マネージャに配信]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-37-01 | 設定依存 | enableFormattingがtrueの場合のみ実行 | 常時 |
| BR-37-02 | 冗長検出 | 既にon(off)の状態でon(off)指示がある場合は冗長と判定 | 初期状態はon |
| BR-37-03 | 不正コマンド | `//dfmt` で始まるが on/off でないコメントは不正と判定 | 常時 |
| BR-37-04 | 重大度区分 | 冗長=hint+unnecessaryタグ、不正コマンド=warning | 常時 |

### 計算ロジック

特になし。fmtOnフラグの状態遷移のみ（初期値true）。

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

### 操作別データベース影響一覧

本機能にデータベース操作は存在しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | コンポーネント未初期化 | DfmtComponentが利用不可 | 処理終了（診断なし） |

### リトライ仕様

リトライは行わない。

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

トランザクション管理は不要。

## パフォーマンス要件

dfmt指示コメントの検出は軽量な処理。テキスト変更時のデバウンス遅延はファイルサイズ50KB未満で50ms、50KB以上で500ms（extension.d 1157行目）。

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

特になし。

## 備考

- DiagnosticSlotは2（dfmt用）。DScanner静的解析はSlot 0、DUBビルド診断はSlot 1を使用する。
- fmtOnの初期状態はtrue（dfmtはデフォルトでフォーマット有効）。
- DfmtInstruction.Typeはdfmt指示コメントの種類を表す列挙型で、dfmtOn, dfmtOff, unknownの3値を持つ。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | dfmt.d (linters) | `source/served/linters/dfmt.d` | DiagnosticSlot=2（22行目）、DfmtDiagnosticSource（20行目）を確認 |

**読解のコツ**: DfmtInstruction型はworkspace-dのDfmtComponentで定義されており、type（dfmtOn/dfmtOff/unknown）、index（バイトオフセット）、length（長さ）のフィールドを持つ。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | dfmt.d (linters) | `source/served/linters/dfmt.d` | `lint` 関数（24-36行目）がメインのリント処理 |
| 2-2 | dfmt.d (linters) | `source/served/linters/dfmt.d` | `lintDfmt` 関数（38-91行目）が実際の診断ロジック |

**主要処理フロー**:
1. **26-28行目**: enableFormatting設定チェック
2. **30-31行目**: DfmtComponent利用可能性チェック
3. **34行目**: lintDfmt呼び出し、結果を診断マネージャに格納
4. **40行目**: findDfmtInstructionsで指示コメント一覧取得
5. **56-87行目**: 各指示の診断生成ロジック（switch文）
6. **60-61行目**: movePositionBytesでバイトオフセット→Position変換

#### Step 3: トリガー元を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | extension.d | `source/served/extension.d` | `onDidChangeDocument`（1148-1165行目）でsetTimeout経由でdfmt.lintが呼ばれる |

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

```
onDidChangeDocument (extension.d:1148)
    └─ setTimeout (デバウンス: 50ms/500ms)
           └─ dfmt.lint (dfmt.d:24)
                  |
                  +-- config.d.enableFormatting チェック
                  +-- backend.has!DfmtComponent チェック
                  +-- lintDfmt (dfmt.d:38)
                  |       |
                  |       +-- DfmtComponent.findDfmtInstructions()
                  |       +-- fmtOn状態追跡
                  |       +-- 冗長/不正コマンド診断生成
                  |       +-- movePositionBytes (バイト→Position変換)
                  |
                  +-- createDiagnosticsFor!2 (diagnosticmanager.d)
                  +-- updateDiagnostics (diagnosticmanager.d)
```

### データフロー図

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

Document            ──▶  dfmt.lint()                   ──▶  textDocument/publishDiagnostics
  .rawText                |                                    (RPC通知)
                          +-- DfmtComponent
                          |     .findDfmtInstructions()
                          |     (DfmtInstruction[])
                          +-- 冗長性チェック
                          +-- 不正コマンドチェック
                          +-- Diagnostic[]生成
                          +-- diagnosticmanager
                                (DiagnosticSlot=2)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| dfmt.d (linters) | `source/served/linters/dfmt.d` | ソース | dfmtリントメイン処理 |
| diagnosticmanager.d | `source/served/linters/diagnosticmanager.d` | ソース | 複数診断プロバイダの統合・配信 |
| extension.d | `source/served/extension.d` | ソース | onDidChangeDocumentからデバウンス付きトリガー |
| types.d | `source/served/types.d` | ソース | 設定項目（enableFormatting） |
| dfmt.d (workspace-d) | `workspace-d/source/workspaced/com/dfmt.d` | ソース | DfmtComponent実装（findDfmtInstructions） |
