# 機能設計書 36-DUBビルド診断

## 概要

本ドキュメントは、DUBビルドを実行しコンパイルエラー・警告を診断結果として返却するDUBビルド診断機能の設計を記述する。

### 本機能の処理概要

**業務上の目的・背景**：D言語プロジェクトではDUBがビルドシステムとして使用される。ファイル保存時にバックグラウンドでDUBビルドを実行し、コンパイルエラー・警告・非推奨警告をリアルタイムにエディタ上に表示することで、開発者が素早く問題を認識・修正できるようにする。

**機能の利用シーン**：テキストドキュメントの保存時（textDocument/didSave）に自動的にトリガーされる。DUBプロジェクトのビルドを実行し、コンパイラから出力されるエラー・警告をパースして診断結果としてクライアントに配信する。

**主要な処理内容**：
1. DubComponentが利用可能か確認する
2. 設定でDUBリンティングが有効か確認する（enableLinting, enableDubLinting）
3. 排他制御により同時実行を防止する（dubLintRunning フラグ）
4. DubComponent.build() でDUBビルドを実行する
5. ビルドイシューをパースし、ファイルパスを解決し、エラー範囲を拡張する
6. 補足情報（instantiated from here等）を関連情報として付加する
7. 診断マネージャ経由でクライアントに配信する

**関連システム・外部連携**：DubComponent（workspace-dサブパッケージ）がDUBビルドの実行を担当する。実際のビルドはDUBコマンドラインツールを内部的に呼び出す。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 36 | DUB ビルドリント | 主画面 | ファイル保存時にDUBビルドを実行しコンパイルエラー・警告を診断結果として返却 |

## 機能種別

ビルド実行・診断生成処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| document | Document | Yes | 保存されたテキストドキュメント | - |

### 入力データソース

テキストドキュメント保存イベントからトリガーされる。DUBビルドの出力がBuildIssueとして取得される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Diagnostic.range | TextRange | エラー箇所のテキスト範囲（拡張済み） |
| Diagnostic.severity | DiagnosticSeverity | 重大度（error/warning/information） |
| Diagnostic.source | string | "DUB" |
| Diagnostic.message | string | コンパイラのエラー・警告メッセージ |
| Diagnostic.tags | DiagnosticTag[] | 非推奨の場合はdeprecated_タグ付与 |
| Diagnostic.relatedInformation | DiagnosticRelatedInformation[] | 補足的なエラー位置情報 |

### 出力先

診断マネージャ（DiagnosticSlot=1）経由で `textDocument/publishDiagnostics` 通知としてクライアントに送信。ビルドイシューは複数ファイルにまたがる可能性があり、PublishDiagnosticsParams[] 形式でファイルごとにグループ化される。

## 処理フロー

### 処理シーケンス

```
1. DubComponentインスタンス取得
   └─ backend.getBestInstance!DubComponent で取得
   └─ 取得できない場合は診断クリアして終了
2. 設定チェック
   └─ config.d.enableLinting && config.d.enableDubLinting の両方がtrueか確認
3. 排他制御
   └─ dubLintRunning == true の場合は retryDubAtEnd フラグを立てて終了
   └─ dubLintRunning = true に設定
4. ビルド設定チェック
   └─ isValidBuildConfiguration でビルド可能なパッケージか確認
5. DUBビルド実行
   └─ DubComponent.build() を呼び出し（非同期）
   └─ lastDubDuration + 100ms経過後に前回の診断をクリアするタイマーを設定
6. ビルドイシュー処理
   └─ 各イシューについて:
     └─ fixPath でファイルパスを解決（-mixin-対応、相対パス解決）
     └─ 重大度マッピング（Deprecation→information, Warning→warning, Error→error）
     └─ 補足イシュー（cont=true）を relatedInformation として付加
     └─ extendErrorRange でエラー範囲を拡張（単語境界まで）
     └─ "instantiated from here" の補足を別ファイルの診断としても追加
7. 診断マネージャに配信
   └─ diagnostics[DiagnosticSlot] にPublishDiagnosticsParams[]を格納
   └─ updateDiagnostics() で全プロバイダの結果を統合・送信
8. リトライチェック
   └─ retryDubAtEnd == true の場合はループの先頭に戻る
```

### フローチャート

```mermaid
flowchart TD
    A[lint呼び出し] --> B{DubComponent利用可能?}
    B -->|No| C[診断クリア]
    B -->|Yes| D{リンティング有効?}
    D -->|No| C
    D -->|Yes| E{dubLintRunning?}
    E -->|Yes| F[retryDubAtEnd = true]
    E -->|No| G[dubLintRunning = true]
    G --> H{ビルド可能?}
    H -->|No| C
    H -->|Yes| I[DUBビルド実行]
    I --> J[ビルドイシュー処理]
    J --> K[診断マネージャに配信]
    K --> L{retryDubAtEnd?}
    L -->|Yes| H
    L -->|No| M[dubLintRunning = false]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-36-01 | 設定依存 | enableLintingとenableDubLintingの両方がtrueの場合のみ実行 | 常時 |
| BR-36-02 | 排他制御 | 同時に1つのDUBビルドのみ実行。実行中にトリガーされた場合はretryフラグで再実行 | 常時 |
| BR-36-03 | 重大度マッピング | Deprecation→information(+deprecated_タグ), Warning→warning, Error→error | 常時 |
| BR-36-04 | パス解決 | -mixin-サフィックスの除去、CWD/ワークスペースルートからの相対パス解決 | 常時 |
| BR-36-05 | エラー範囲拡張 | DUBの単一位置エラーを単語境界まで拡張、resolveDiagnosticRange利用 | 常時 |
| BR-36-06 | タイムアウト診断クリア | 前回ビルド時間+100ms経過後に実行中の診断をクリア | 常時 |

### 計算ロジック

特になし。

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | コンポーネント未初期化 | DubComponentが利用不可 | 診断をクリアして終了 |
| - | ビルド不可 | isValidBuildConfigurationがfalse | 診断をクリアして終了 |

### リトライ仕様

排他制御によるリトライ: dubLintRunning中にトリガーされた場合はretryDubAtEndフラグが設定され、現在のビルド完了後に再度ビルドが実行される。

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

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

## パフォーマンス要件

DUBビルドの実行時間はプロジェクトサイズに依存する。前回のビルド時間をlastDubDurationとして記録し、その時間+100ms経過後に診断をクリアすることで、長時間ビルド中のUX劣化を防ぐ。

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

DUBビルドはローカルのDUBコマンドを実行するため、プロジェクトのbuild hookやpre/postビルドコマンドが実行される可能性がある。

## 備考

- DiagnosticSlotは1（DUBビルド用）。DScanner静的解析はSlot 0、dfmtリントはSlot 2を使用する。
- "instantiated from here" エラーは、テンプレートのインスタンス化チェーンを追跡するため、複数ファイルに跨る診断として処理される。
- currentBuildTokenによるタイマー管理で、古いタイマーが新しいビルドの診断をクリアしないよう制御している。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | dub.d (linters) | `source/served/linters/dub.d` | DiagnosticSlot=1（25行目）、DubDiagnosticSource（27行目）、排他制御変数（90-92行目）を確認 |

**読解のコツ**: dubLintRunning, retryDubAtEnd, lastDubDuration, currentBuildToken の4つの状態変数が排他制御とタイマー管理の核となる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | dub.d (linters) | `source/served/linters/dub.d` | `lint` 関数（94-232行目）がメインのリント処理 |

**主要処理フロー**:
1. **102行目**: DubComponentインスタンス取得
2. **107行目**: 設定チェック
3. **110-114行目**: 排他制御（dubLintRunning）
4. **124-128行目**: ビルド設定チェック
5. **134-141行目**: タイムアウト診断クリアタイマー設定
6. **145行目**: DubComponent.build()実行
7. **165-226行目**: ビルドイシュー処理ループ
8. **228-229行目**: 診断マネージャ配信

#### Step 3: 補助関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | dub.d (linters) | `source/served/linters/dub.d` | `fixPath`（29-68行目）、`mapDubLintType`（70-81行目）、`applyDubLintType`（83-88行目）、`extendErrorRange`（234-256行目） |

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

```
onDidSaveDocument (extension.d:1316)
    └─ dub.lint (dub.d:94)
           |
           +-- dubLintRunning チェック/設定
           +-- DubComponent.isValidBuildConfiguration
           +-- setTimeout (診断クリアタイマー)
           +-- DubComponent.build() (ビルド実行)
           +-- fixPath (パス解決)
           +-- mapDubLintType/applyDubLintType (重大度変換)
           +-- extendErrorRange (範囲拡張)
           |       └─ DubComponent.resolveDiagnosticRange
           +-- diagnostics[1] = result (診断マネージャ配信)
           +-- updateDiagnostics()
```

### データフロー図

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

Document            ──▶  dub.lint()                    ──▶  textDocument/publishDiagnostics
  (保存イベント)           |                                    (RPC通知、ファイル別)
                          +-- DubComponent.build()
                          |     (BuildIssue[])
                          +-- fixPath() (パス解決)
                          +-- mapDubLintType() (重大度)
                          +-- extendErrorRange() (範囲拡張)
                          +-- PublishDiagnosticsParams[]
                          +-- diagnosticmanager
                                (DiagnosticSlot=1)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| dub.d (linters) | `source/served/linters/dub.d` | ソース | DUBビルド診断メイン処理 |
| diagnosticmanager.d | `source/served/linters/diagnosticmanager.d` | ソース | 複数診断プロバイダの統合・配信 |
| extension.d | `source/served/extension.d` | ソース | onDidSaveDocumentからのトリガー |
| types.d | `source/served/types.d` | ソース | 設定項目（enableLinting, enableDubLinting等） |
| dub.d (workspace-d) | `workspace-d/source/workspaced/com/dub.d` | ソース | DubComponent実装（DUBビルド実行） |
