# 帳票設計書 2-DUBビルド診断レポート

## 概要

本ドキュメントは、serve-dのDUBビルド診断レポート機能の設計を記述する。DUBビルド実行時のコンパイルエラー・警告・非推奨メッセージを診断情報（Diagnostics）としてLSPクライアントに出力する帳票である。

### 本帳票の処理概要

DUBビルド診断レポートは、DUBビルドシステムを介してD言語プロジェクトのコンパイルを実行し、発生したコンパイルエラー・警告・非推奨メッセージをエディタ上の診断情報として表示する帳票である。

**業務上の目的・背景**：D言語プロジェクトのビルドエラーをエディタ上でリアルタイムにフィードバックすることで、開発者がコンパイルコマンドを手動で実行することなくビルドエラーを認識できるようにする。テンプレートインスタンス化エラーの展開や、エラー箇所の範囲特定など、高度なエラー情報の提供により、デバッグ効率を大幅に向上させる。

**帳票の利用シーン**：エディタでD言語ソースファイルを保存した際にDUBビルドがバックグラウンドで実行され、コンパイルエラーがエディタの診断パネルやインラインマーカーとして表示される。複数ファイルにまたがるエラー（テンプレートインスタンス化など）も関連情報付きで報告される。

**主要な出力内容**：
1. コンパイルエラーメッセージ（エラー箇所のファイル・行・列情報付き）
2. コンパイル警告メッセージ
3. 非推奨使用の警告（deprecatedタグ付き）
4. テンプレートインスタンス化エラーの展開情報（relatedInformation）
5. エラー範囲の拡張情報（単語単位またはコンパイラメッセージ解析による範囲特定）

**帳票の出力タイミング**：エディタでD言語ファイルが保存された時にバックグラウンドでDUBビルドが実行され、完了後に診断情報が出力される。ビルド中に前回のビルドが長時間かかっていた場合は診断のクリアも行われる。

**帳票の利用者**：D言語開発者（DUBプロジェクトを使用するプログラマ）

## 帳票種別

診断レポート（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[] (複数ファイル) │
├─────────────────────────────────────────┤
│  [0] uri: DocumentUri (ファイルA)         │
│      diagnostics: Diagnostic[]           │
│        ├─ range: TextRange (拡張済み)     │
│        ├─ severity: error/warning/info   │
│        ├─ source: "DUB"                  │
│        ├─ message: string                │
│        ├─ tags: [deprecated]             │
│        └─ relatedInformation[]           │
│  [1] uri: DocumentUri (ファイルB)         │
│      diagnostics: Diagnostic[]           │
│        ...                               │
└─────────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | uri | 診断対象ドキュメントのURI | fixPath()で正規化されたファイルパスをURI変換 | URI文字列 |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | range | エラー箇所のテキスト範囲 | BuildIssue.line/column + extendErrorRange()で拡張 | Position(line,character)のペア | - |
| 2 | severity | 診断の重大度 | mapDubLintType(): Deprecation->info, Warning->warning, Error->error | DiagnosticSeverity列挙値 | - |
| 3 | source | 診断ソース識別子 | 固定値 "DUB" | 文字列 | - |
| 4 | message | エラーメッセージ | BuildIssue.text | コンパイラメッセージ文字列 | - |
| 5 | tags | 診断タグ | Deprecation時にdeprecated_タグ設定 | deprecated | - |
| 6 | relatedInformation | 関連情報（supplemental） | 後続のcont==trueなissue群をDiagnosticRelatedInformationに変換 | Location + message の配列 | - |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| - | N/A | 本帳票にフッター部は存在しない | - | - |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| リンティング有効 | config.d.enableLinting == true | Yes |
| DUBリンティング有効 | config.d.enableDubLinting == true | Yes |
| DUBコンポーネント利用可能 | backend.getBestInstance!DubComponentが有効であること | Yes |
| 有効なビルド構成 | DubComponent.isValidBuildConfigurationがtrueであること | Yes |
| ビルド非実行中 | dubLintRunningがfalseであること（実行中は再試行フラグを設定） | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | DUBビルドの出力順（コンパイラ出力順） | 昇順 |

### 改ページ条件

N/A

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

### 参照テーブル一覧

本帳票はデータベースを使用しない。DUBビルドプロセスの出力を解析する。

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

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

N/A

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| severity | Deprecation -> information, Warning -> warning, Error -> error | - | mapDubLintType()関数（行70-81） |
| range | BuildIssue.line-1, column-1を起点にextendErrorRange()で拡張 | - | resolveDiagnosticRangeまたはwordRangeAtで範囲拡張 |
| fixPath | mixinインデックス処理 + cwd/workspaceRoot/stringImportPathsからの絶対パス解決 | - | fixPath関数（行29-68） |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[ファイル保存イベント] --> B[lint関数呼び出し]
    B --> C{DubComponent有効?}
    C -->|No| Z1[空の診断を設定]
    C -->|Yes| D{リンティング設定有効?}
    D -->|No| Z1
    D -->|Yes| E{ビルド実行中?}
    E -->|Yes| F[retryDubAtEnd=trueで終了]
    E -->|No| G[dubLintRunning=true]
    G --> H{有効なビルド構成?}
    H -->|No| Z1
    H -->|Yes| I[タイムアウト設定]
    I --> J[DubComponent.build実行]
    J --> K[issue一覧をループ処理]
    K --> L[supplemental情報の収集]
    L --> M[fixPathでファイルパス解決]
    M --> N[Diagnostic構造体生成]
    N --> O[extendErrorRangeで範囲拡張]
    O --> P{instantiated from here?}
    P -->|Yes| Q[追加の診断エントリ生成]
    P -->|No| R[pushErrorでresultに追加]
    Q --> R
    R --> K
    K --> S[diagnosticsスロット1に格納]
    S --> T[updateDiagnostics呼び出し]
    T --> U{retryDubAtEnd?}
    U -->|Yes| H
    U -->|No| Z[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| インスタンス未取得 | DubComponentのインスタンスが取得できない | なし | 空の診断を設定して終了 |
| 設定無効 | enableLintingまたはenableDubLintingがfalse | なし | 空の診断を設定して終了 |
| 無効なビルド構成 | isValidBuildConfigurationがfalse | traceログ出力 | 空の診断を設定して終了 |
| ビルド長時間化 | lastDubDuration + 100ms超過 | なし | setTimeoutにより診断をクリア |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | プロジェクト全体で0〜数百件のビルドissue |
| 目標出力時間 | DUBビルド完了後即時（ビルド自体は数秒〜数十秒） |
| 同時出力数上限 | dubLintRunningフラグにより1ビルドずつ逐次処理（再試行あり） |

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

- DUBビルドは外部プロセスとしてコンパイラを実行するため、ビルド構成に応じてシステムリソースを消費する
- fixPath関数でファイルパスを正規化しており、パストラバーサルのリスクを低減
- ビルド結果はローカル環境内で処理される

## 備考

- DiagnosticSlotは1番が割り当てられている（dub.d 行25）
- dubLintRunning/retryDubAtEndフラグによりビルドの排他制御と再試行を管理（行90-91）
- lastDubDurationで前回ビルド時間を記録し、タイムアウト判定に使用（行91, 141）
- currentBuildTokenでビルドの世代管理を行い、タイムアウトコールバックの有効性を判定（行92, 136）
- テンプレートインスタンス化エラー（"instantiated from here:"）はプロジェクト内のファイルのみ追加診断として展開（行205-225）

---

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

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

### 推奨読解順序

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

まず、ビルドエラー情報がどのように表現されるかを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | dub.d | `source/served/linters/dub.d` | BuildIssue型（workspaced.com.dubからインポート）とErrorType列挙の理解（行23） |
| 1-2 | diagnosticmanager.d | `source/served/linters/diagnosticmanager.d` | DiagnosticSlot 1の位置づけ（3プロバイダのうち2番目） |

**読解のコツ**: `BuildIssue`と`ErrorType`はworkspacedライブラリ側で定義されている。dub.dファイルのimport文（行23）を手がかりに外部定義を参照すること。

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

処理の起点となる`lint`関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | dub.d | `source/served/linters/dub.d` | lint関数（行94-232）: ビルド実行から診断配信までの全体フロー |

**主要処理フロー**:
1. **行102-104**: DubComponentの最適インスタンス取得
2. **行106-108**: リンティング設定チェック
3. **行110-114**: dubLintRunningフラグによる排他制御
4. **行120-231**: do-whileループによるビルド実行と再試行
5. **行124-129**: isValidBuildConfiguration確認
6. **行134-141**: lastDubDuration超過時の診断クリアタイムアウト設定
7. **行144-145**: stringImportsとbuild実行
8. **行165-226**: issue一覧のループ処理（supplemental収集、fixPath、Diagnostic生成）

#### Step 3: パス解決処理を理解する

ビルドエラーのファイルパスがどのように正規化されるかを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | dub.d | `source/served/linters/dub.d` | fixPath関数（行29-68）: mixinインデックス除去、cwd/workspaceRoot/stringImportPaths探索 |

**主要処理フロー**:
- **行31-33**: `-mixin-`インデックスの除去
- **行36-41**: 絶対パス化（cwd優先、workspaceRootフォールバック）
- **行43-44**: `.d`拡張子ファイルはそのまま使用
- **行50-63**: 相対パスの場合、stringImportPathsも含めて検索

#### Step 4: エラー範囲拡張処理を理解する

単一位置のエラーがどのように範囲に拡張されるかを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | dub.d | `source/served/linters/dub.d` | extendErrorRange関数（行234-256）: resolveDiagnosticRangeまたはwordRangeAtによる範囲拡張 |

**主要処理フロー**:
- **行241-252**: メッセージ付きの場合、DubComponentのresolveDiagnosticRangeで範囲解決
- **行255**: 解決できない場合、ドキュメントのwordRangeAtで単語範囲を使用

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

```
lint(Document document)                                [dub.d:94]
    |
    +-- backend.getBestInstance!DubComponent()          [dub.d:102]
    +-- config(document.uri)                            [dub.d:106]
    +-- DubComponent.isValidBuildConfiguration          [dub.d:124]
    +-- setTimeout({診断クリア})                         [dub.d:134]
    +-- DubComponent.stringImports                      [dub.d:144]
    +-- DubComponent.build()                            [dub.d:145]
    +-- [foreach issue]
    |       +-- fixPath()                               [dub.d:180-181]
    |       |       +-- buildNormalizedPath()
    |       |       +-- exists()
    |       +-- uriFromFile()                           [dub.d:180]
    |       +-- applyDubLintType()                      [dub.d:185]
    |       |       +-- mapDubLintType()                [dub.d:70]
    |       +-- extendErrorRange()                      [dub.d:200]
    |       |       +-- DubComponent.resolveDiagnosticRange() [dub.d:244]
    |       |       +-- doc.wordRangeAt()               [dub.d:255]
    |       +-- pushError()                             [dub.d:201]
    |
    +-- updateDiagnostics()                             [dub.d:229]
```

### データフロー図

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

DUBビルドプロセス --------> DubComponent.build()       ----> BuildIssue[]
(コンパイラ実行)

BuildIssue[] ------------> fixPath()                   ----> 正規化ファイルパス
                           uriFromFile()               ----> DocumentUri

BuildIssue.file/line ----> Diagnostic生成              ----> Diagnostic
BuildIssue.text            applyDubLintType()                (range, severity,
                           extendErrorRange()                 message, tags)

supplemental issues -----> relatedInformation変換      ----> DiagnosticRelatedInformation[]

Diagnostic[] ------------> diagnostics[1]に格納        ----> DiagnosticCollection
                           updateDiagnostics()
                           combineDiagnostics()

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

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| dub.d | `source/served/linters/dub.d` | ソース | DUBビルド診断の主処理（lint, fixPath, extendErrorRange） |
| diagnosticmanager.d | `source/served/linters/diagnosticmanager.d` | ソース | 診断情報の統合管理・配信 |
| types.d | `source/served/types.d` | ソース | 共通型定義、Configuration構造体 |
| protoext.d | `source/served/lsp/protoext.d` | ソース | LSP拡張プロトコル型定義 |
| extension.d | `source/served/extension.d` | ソース | LSPサーバー拡張機能の登録 |
