# 通知設計書 31-ClangDiagnostics

## 概要

本ドキュメントは、Zigコンパイラにおける「ClangDiagnostics」通知の設計書である。Cコードのコンパイル時にClangコンパイラから発生する診断メッセージを処理・出力する仕組みを定義する。

### 本通知の処理概要

ClangDiagnostics通知は、ZigコンパイラがCソースファイルをコンパイルする際に、内部で使用するClangコンパイラから発生するエラー・警告・情報メッセージを収集し、ユーザーに適切な形式で提示するための機能である。

**業務上の目的・背景**：Zigは他言語（特にC言語）との相互運用性を重視しており、`@cImport`を通じてCヘッダーをインポートしたり、Cソースファイルを直接コンパイルしたりする機能を提供している。これらの処理でCコードに問題がある場合、開発者はClangからの診断メッセージを確認してデバッグを行う必要がある。本通知により、Clangの診断情報がZigのコンパイルエラー体系に統合され、一貫したエラー報告が実現される。

**通知の送信タイミング**：Cソースファイルのコンパイル時（`updateCObject`関数実行時）にClangプロセスがエラー終了した場合、およびCインポート処理（`cImport`関数実行時）でClangエラーが発生した場合に送信される。

**通知の受信者**：コンパイルを実行している開発者。stderrを通じて診断情報が出力され、コンパイルエラーとして報告される。

**通知内容の概要**：Clangの診断メッセージ、エラーコード、エラーが発生したソースファイルの位置情報（ファイル名、行番号、列番号）、およびコンテキスト情報が含まれる。

**期待されるアクション**：開発者は診断メッセージの内容に基づいて、Cソースコードの修正、インクルードパスの調整、マクロ定義の修正などを行う。

## 通知種別

標準エラー出力（stderr）への診断メッセージ出力

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（コンパイルプロセス内で処理） |
| 優先度 | 高（コンパイルをブロック） |
| リトライ | 無（エラー時はコンパイル失敗） |

### 送信先決定ロジック

診断メッセージは標準エラー出力に送信される。`clang_passthrough_mode`が有効な場合はClangの出力をそのまま継承し、無効な場合はZigコンパイラがClangのdiagnosticsファイルをパースして構造化エラーとして出力する。

## 通知テンプレート

### 診断出力形式

| 項目 | 内容 |
|-----|------|
| 出力先 | stderr |
| 形式 | テキスト/構造化診断 |

### 本文テンプレート

```
{ソースファイルパス}:{行番号}:{列番号}: {エラー種別}: {メッセージ}
  {ソースコード行}
  {キャレット位置指示}
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| {出力パス}.diag | バイナリ | clang_passthrough_mode無効時 | Clangシリアライズ診断ファイル |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| source_path | Cソースファイルパス | CObject.src | Yes |
| error_code | Clang終了コード | term.exited | Yes |
| stderr | 標準エラー出力内容 | child.stderr | No |
| diag_bundle | 構造化診断情報 | CObject.Diag.Bundle | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| Cソースコンパイル | updateCObject実行 | Clangが非ゼロ終了コードを返した場合 | Cオブジェクトファイルのコンパイル失敗時 |
| Cインポート | cImport実行 | Clangエラー発生時 | @cImportでのヘッダーインポート失敗時 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| Clang正常終了 | 終了コードが0の場合、診断は出力されない |
| clang_passthrough_mode有効時 | Clangの出力をそのまま継承するため、Zig独自の処理はスキップ |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[Cソースコンパイル開始] --> B[Clangプロセス起動]
    B --> C[Clangプロセス完了待機]
    C --> D{終了コード確認}
    D -->|0| E[コンパイル成功]
    D -->|非0| F{passthrough_mode?}
    F -->|Yes| G[Clang出力をそのまま表示]
    F -->|No| H{diagファイル存在?}
    H -->|Yes| I[diagファイルをパース]
    H -->|No| J[stderrをログ出力]
    I --> K[構造化エラーとして報告]
    J --> L[一般エラーとして報告]
    G --> M[プロセス終了]
    K --> M
    L --> M
    E --> N[次の処理へ]
```

## データベース参照・更新仕様

### 参照テーブル一覧

本通知はデータベースを使用しない。メモリ上のデータ構造を参照する。

| データ構造 | 用途 | 備考 |
|-----------|------|------|
| CObject | Cオブジェクトファイル情報 | src、diagなどを保持 |
| CObject.Diag.Bundle | 診断情報バンドル | パース済み診断メッセージ |
| Compilation | コンパイル設定 | verbose_cimportフラグなど |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| Clangプロセス起動失敗 | プロセス生成エラー | failCObj経由でエラー報告 |
| diagファイルパース失敗 | 診断ファイル読み取りエラー | stderrをログ出力し一般エラーとして報告 |
| シグナル終了 | Clangがシグナルで終了 | シグナル情報を含むエラーを報告 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（コンパイル時に即座に出力）

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

- 診断メッセージにはソースコードパスやソースコード断片が含まれるため、ログ出力時には機密情報の露出に注意が必要
- Clangプロセスはサブプロセスとして起動されるため、プロセス間のセキュリティ境界が存在

## 備考

- `--verbose-cimport`フラグを使用すると、Cインポート処理の詳細情報が`log.info`で出力される
- 診断ファイルは`.diag`拡張子でキャッシュディレクトリに一時保存され、処理後に削除される

---

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

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

### 推奨読解順序

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

CObject.Diagの構造と診断情報の表現方法を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Compilation.zig | `src/Compilation.zig` | CObject構造体の定義（154行目付近）、Diag.Bundle構造体 |

**読解のコツ**: CObjectはCソースファイルのコンパイル単位を表し、その中のDiagフィールドが診断情報を保持する。

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

Clang呼び出しの起点となる関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Compilation.zig | `src/Compilation.zig` | updateCObject関数（6300行目付近）がCコンパイルの起点 |

**主要処理フロー**:
1. **6367行**: out_diag_pathの決定（passthrough_modeとdiagnosticsサポートの判定）
2. **6440-6445行**: Clangプロセスの起動（stderrをパイプ接続）
3. **6447-6448行**: stderr読み取り
4. **6453-6472行**: 終了コードに基づく診断処理

#### Step 3: 診断ファイルのパース処理

Clangの診断ファイルをパースしてエラーバンドルに変換する処理。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Compilation.zig | `src/Compilation.zig` | CObject.Diag.Bundle.parse関数の呼び出し（6455行目） |

**主要処理フロー**:
- **6455行**: diagファイルのパース
- **6459行**: failCObjWithOwnedDiagBundleでエラー報告

#### Step 4: Cインポートでの診断処理

@cImportでの診断処理フロー。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Compilation.zig | `src/Compilation.zig` | cImport関数（5700行目付近）での診断処理 |

**主要処理フロー**:
- **5773行**: verbose_cimportフラグによるログ出力
- **5821行**: コマンドライン引数のダンプ
- **5828行**: 依存ファイル処理ログ

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

```
Compilation.update()
    │
    ├─ updateCObject()
    │      ├─ std.process.spawn() [Clangプロセス起動]
    │      │      └─ stderr読み取り
    │      │
    │      ├─ CObject.Diag.Bundle.parse() [diagファイルパース]
    │      │
    │      └─ failCObjWithOwnedDiagBundle() [エラー報告]
    │
    └─ cImport()
           ├─ log.info() [verbose_cimport有効時]
           │
           └─ translateC() [Clang呼び出し]
```

### データフロー図

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

Cソースファイル ───▶ Clangプロセス起動 ───▶ コンパイル実行
                            │
                            ▼
                    終了コード確認
                            │
        ┌───────────────────┴───────────────────┐
        ▼                                       ▼
    正常終了                              異常終了
        │                                       │
        ▼                                       ▼
    次の処理へ                         diagファイル確認
                                               │
                    ┌──────────────────────────┴────────────────┐
                    ▼                                          ▼
            diagファイルあり                            diagファイルなし
                    │                                          │
                    ▼                                          ▼
            Bundle.parse()                              stderrをログ出力
                    │                                          │
                    ▼                                          ▼
            構造化エラー報告                            一般エラー報告
                    │                                          │
                    └────────────────┬─────────────────────────┘
                                     ▼
                                stderr出力
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Compilation.zig | `src/Compilation.zig` | ソース | Cオブジェクトコンパイル、Cインポート処理の主実装 |
| main.zig | `src/main.zig` | ソース | verbose_cimportフラグの解析と設定 |
| Zcu.zig | `src/Zcu.zig` | ソース | cimport_errorsマップの管理 |
| zig_clang_cc1_main.cpp | `src/zig_clang_cc1_main.cpp` | ソース | Clang CC1メイン処理 |
| zig_clang_driver.cpp | `src/zig_clang_driver.cpp` | ソース | Clangドライバ処理 |
