# 通知設計書 1-PublishDiagnostics

## 概要

本ドキュメントは、clangd Language Serverが実装するLSP標準メソッド `textDocument/publishDiagnostics` の通知仕様を定義する。この通知は、ソースコードの解析結果として検出されたエラー、警告、情報メッセージなどの診断情報をクライアント（エディタ/IDE）に送信するために使用される。

### 本通知の処理概要

PublishDiagnostics通知は、C/C++ソースコードの静的解析・コンパイル時に検出された問題をリアルタイムでエディタに表示するための中核機能である。

**業務上の目的・背景**：開発者がコードを編集する際、コンパイルエラーや警告、スタイル違反などの問題を即座に把握できることは、開発効率の向上に不可欠である。この通知により、開発者はビルド実行前に問題を特定・修正でき、イテレーション時間を大幅に短縮できる。clangdはClangコンパイラの解析エンジンを活用し、高精度な診断情報を提供する。

**通知の送信タイミング**：診断情報は以下のイベントで送信される。(1) ドキュメントを開いた時（didOpen）、(2) ドキュメントの内容が変更された時（didChange）、(3) ドキュメントを閉じた時（didClose、空の診断リストを送信して表示をクリア）。ClangdServerの`onDiagnosticsReady`コールバックが診断準備完了時に呼び出され、`PublishDiagnostics`通知がクライアントに送信される。

**通知の受信者**：LSPクライアント（VSCode、Vim、Emacs等のエディタ/IDE）が受信者となる。通知は対象ドキュメントのURIに関連付けられ、そのドキュメントを開いているすべてのクライアントに配信される。

**通知内容の概要**：診断情報には、問題の位置（行・列）、重大度（エラー/警告/情報/ヒント）、メッセージ、ソース（clang/clang-tidy等）、エラーコード、関連情報、修正候補（CodeAction）が含まれる。clangd拡張として、診断カテゴリやインラインCodeActionもサポートされる。

**期待されるアクション**：クライアントは受信した診断情報をエディタUI上に表示する。通常、エラーは赤い波線、警告は黄色い波線などで該当箇所をハイライトし、問題パネルに一覧表示する。開発者はこれらの情報を元にコードを修正し、修正候補が提供されている場合はQuick Fixとして適用できる。

## 通知種別

LSP Notification（サーバーからクライアントへの一方向通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期 |
| 優先度 | 高 |
| リトライ | なし（通知は一方向のため） |

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

対象ドキュメントを開いているLSPクライアントに送信される。送信先は接続中のクライアントセッションに基づき、特定のユーザー/ロール指定は行わない。

## 通知テンプレート

### LSP Notification形式

| 項目 | 内容 |
|-----|------|
| メソッド名 | `textDocument/publishDiagnostics` |
| 形式 | JSON-RPC 2.0 Notification |

### 本文テンプレート

```json
{
  "jsonrpc": "2.0",
  "method": "textDocument/publishDiagnostics",
  "params": {
    "uri": "file:///path/to/source.cpp",
    "version": 1,
    "diagnostics": [
      {
        "range": {
          "start": { "line": 10, "character": 5 },
          "end": { "line": 10, "character": 15 }
        },
        "severity": 1,
        "code": "err_undeclared_var_use",
        "source": "clang",
        "message": "use of undeclared identifier 'foo'",
        "relatedInformation": [],
        "codeActions": []
      }
    ]
  }
}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| uri | 診断対象ドキュメントのURI | URIForFile::canonicalize() | Yes |
| version | ドキュメントのバージョン番号 | TextDocumentIdentifier.version | No |
| diagnostics | 診断情報の配列 | Diag構造体から変換 | Yes |
| range | 問題箇所の範囲 | Diag.Range | Yes |
| severity | 重大度（1:Error, 2:Warning, 3:Info, 4:Hint） | Diag.Severity | Yes |
| code | エラーコード | Diag.Code | No |
| source | 診断ソース（clang, clang-tidy等） | Diag.Source | No |
| message | 診断メッセージ | Diag.Message | Yes |
| relatedInformation | 関連情報 | Diag.RelatedInformation | No |
| category | 診断カテゴリ（clangd拡張） | Diag.Category | No |
| codeActions | インラインCodeAction（clangd拡張） | Fix構造体から変換 | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | textDocument/didOpen | ドキュメントが開かれた | 新規ドキュメントの初期診断 |
| 画面操作 | textDocument/didChange | ドキュメント内容が変更された | 変更に伴う再診断 |
| 画面操作 | textDocument/didClose | ドキュメントが閉じられた | 診断をクリア（空配列送信） |
| 内部処理 | AST構築完了 | TUSchedulerによるAST更新完了 | バックグラウンドでの診断更新 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| wantDiagnostics=false | didChangeでwantDiagnosticsがfalseの場合、診断は送信されない |
| サーバー未初期化 | initializeリクエスト完了前は送信されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ドキュメント変更イベント] --> B[ClangdServer::addDocument]
    B --> C[TUScheduler::update]
    C --> D[AST構築/更新]
    D --> E[診断情報収集]
    E --> F[onDiagnosticsReady コールバック]
    F --> G[toLSPDiags 変換]
    G --> H[PublishDiagnosticsParams 構築]
    H --> I[PublishDiagnostics 通知送信]
    I --> J[クライアントで表示]
```

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

### 参照テーブル一覧

該当なし（LSPサーバーはインメモリで動作）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| URI解決失敗 | ファイルパスからURIへの変換失敗 | エラーログ出力、未解決パスを使用 |
| AST構築失敗 | コンパイルエラー等でAST構築不可 | 構築可能な範囲で診断を生成 |
| Transport失敗 | クライアントとの接続断 | ログ出力、再接続待機 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし（イベント駆動） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（リアルタイム配信）

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

- 診断情報にはソースコードの一部（変数名、関数名等）が含まれる可能性がある
- ファイルパスがURIとして送信されるため、ローカルファイルシステム構造が露出する
- LSP通信はローカルプロセス間通信が基本であり、外部ネットワークへの送信は想定していない

## 備考

- clangd拡張として `category` フィールド（診断カテゴリ）と `codeActions` フィールド（インラインCodeAction）をサポート
- クライアントがこれらの拡張をサポートしているかは、initialize時のcapabilitiesで判断
- 診断の重大度マッピング：1=Error, 2=Warning, 3=Information, 4=Hint

---

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

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

### 推奨読解順序

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

まず、診断情報のデータ構造とLSPプロトコル定義を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Protocol.h | `clang-tools-extra/clangd/Protocol.h` | PublishDiagnosticsParams, Diagnostic構造体の定義（行982-990） |
| 1-2 | Protocol.cpp | `clang-tools-extra/clangd/Protocol.cpp` | toJSON(PublishDiagnosticsParams)の実装（行773-781） |

**読解のコツ**: LSP仕様に準拠した構造体定義。`llvm::json::Value toJSON()`関数でJSON変換ロジックを確認できる。

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

診断通知の送信起点となるコールバック処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ClangdLSPServer.h | `clang-tools-extra/clangd/ClangdLSPServer.h` | PublishDiagnostics通知のバインド宣言（行195） |
| 2-2 | ClangdLSPServer.cpp | `clang-tools-extra/clangd/ClangdLSPServer.cpp` | onDiagnosticsReadyコールバック（行1809-1841） |

**主要処理フロー**:
1. **行1809**: `onDiagnosticsReady`コールバック開始
2. **行1811-1813**: PublishDiagnosticsParamsの初期化、URI設定
3. **行1815-1830**: 各Diagに対してtoLSPDiagsで変換
4. **行1840**: PublishDiagnostics通知送信

#### Step 3: バインディング処理を理解する

LSPメソッドのバインディングとTransport層への接続を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ClangdLSPServer.cpp | `clang-tools-extra/clangd/ClangdLSPServer.cpp` | bindMethods内でのPublishDiagnosticsバインド（行1734） |
| 3-2 | ClangdLSPServer.cpp | `clang-tools-extra/clangd/ClangdLSPServer.cpp` | notify関数の実装（行469-474） |

**主要処理フロー**:
- **行1734**: `Bind.outgoingNotification("textDocument/publishDiagnostics")`
- **行469-474**: `notify`関数がTransport層へJSON-RPC通知を送信

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

```
ClangdServer::addDocument()
    │
    ├─ TUScheduler::update()
    │      └─ AST構築・診断収集
    │             └─ ClangdServer::Callbacks::onDiagnosticsReady()
    │
    └─ ClangdLSPServer::onDiagnosticsReady()
           ├─ toLSPDiags() [Diagnostics.cpp]
           ├─ toCodeAction() [CodeAction変換]
           └─ PublishDiagnostics() [LSPBinder経由]
                  └─ ClangdLSPServer::notify()
                         └─ Transport::notify()
```

### データフロー図

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

Diag (内部診断)  ───▶ toLSPDiags() ───▶ clangd::Diagnostic
                           │
                           ▼
                  PublishDiagnosticsParams
                           │
                           ▼
                  toJSON() シリアライズ
                           │
                           ▼
                  Transport::notify() ───▶ JSON-RPC通知
                                                 │
                                                 ▼
                                           [LSPクライアント]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Protocol.h | `clang-tools-extra/clangd/Protocol.h` | ヘッダ | LSPプロトコル構造体定義 |
| Protocol.cpp | `clang-tools-extra/clangd/Protocol.cpp` | ソース | JSON変換実装 |
| ClangdLSPServer.h | `clang-tools-extra/clangd/ClangdLSPServer.h` | ヘッダ | LSPサーバークラス定義 |
| ClangdLSPServer.cpp | `clang-tools-extra/clangd/ClangdLSPServer.cpp` | ソース | 診断通知のコールバック実装 |
| Diagnostics.h | `clang-tools-extra/clangd/Diagnostics.h` | ヘッダ | 診断関連の型定義 |
| Diagnostics.cpp | `clang-tools-extra/clangd/Diagnostics.cpp` | ソース | toLSPDiags変換実装 |
| LSPBinder.h | `clang-tools-extra/clangd/LSPBinder.h` | ヘッダ | LSPメソッドバインディング |
| Transport.h | `clang-tools-extra/clangd/Transport.h` | ヘッダ | 通信層インターフェース |
