# 機能設計書 71-ProfileGCコードレンズ

## 概要

本ドキュメントは、serve-dにおけるProfileGCコードレンズ機能の設計を記述する。profilegc.logファイルの解析結果をエディタ上のコードレンズとして表示し、D言語プログラムのGCアロケーション情報を開発者に可視化する機能である。

### 本機能の処理概要

**業務上の目的・背景**：D言語プログラムの実行時にGC（ガベージコレクタ）によるメモリ割り当ての詳細情報を、ソースコード上の該当行に直接表示することで、パフォーマンスボトルネックの特定とメモリ最適化を支援する。profilegc.logはD言語ランタイムが生成するプロファイリングデータであり、各ソース行でのバイト割り当て量と割り当て回数を記録している。

**機能の利用シーン**：開発者がD言語プログラムのメモリ使用効率を改善したい場合、エディタ上でソースコードを開くと、各行のGCアロケーション情報がコードレンズとして自動表示される。設定 `d.enableGCProfilerDecorations` を有効にすることで利用可能になる。

**主要な処理内容**：
1. profilegc.logファイルの監視（ファイルシステムウォッチャーによる動的登録）
2. profilegc.logの解析とProfileGCEntryへのパース
3. 各ソースファイルに対応するGCエントリのフィルタリングとCodeLensへの変換
4. エディタへのコードレンズとしての表示（バイト割り当て量/割り当て回数）

**関連システム・外部連携**：D言語ランタイムが生成するprofilegc.logファイルを入力源とし、LSPのtextDocument/codeLensプロトコルを通じてエディタに情報を提供する。

**権限による制御**：設定 `d.enableGCProfilerDecorations` がtrueの場合のみコードレンズを返却する。falseの場合はnullを返す。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 20 | コードレンズ（textDocument/codeLens） | 主画面 | ProfileGCアロケーション情報をコードレンズとして表示する |

## 機能種別

データ連携 / 表示処理（プロファイルデータの解析とコードレンズ表示）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| params.textDocument.uri | DocumentUri | Yes | コードレンズを要求するドキュメントのURI | 有効なファイルURIであること |

### 入力データソース

- LSPクライアントからのtextDocument/codeLensリクエスト
- profilegc.logファイル（D言語ランタイムが生成するGCプロファイルデータ）
- 設定値 `d.enableGCProfilerDecorations`

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| CodeLens[] | CodeLens[] | 各GCアロケーション行に対応するコードレンズの配列 |
| CodeLens.range | TextRange | アロケーションが発生した行の範囲（行頭から1文字） |
| CodeLens.command | Command | "{bytes} bytes allocated / {count} allocations" 形式のテキスト |

### 出力先

LSPクライアント（エディタ）へのtextDocument/codeLensレスポンス

## 処理フロー

### 処理シーケンス

```
1. コードレンズリクエスト受信
   └─ provideProfileGCCodeLens関数が呼び出される
2. 設定確認
   └─ d.enableGCProfilerDecorationsがfalseならnullを返却
3. キャッシュからエントリ取得
   └─ profileGCCache.cachesの全エントリを走査
4. URIフィルタリング
   └─ エントリのURIがリクエストのドキュメントURIと一致するもののみ抽出
5. CodeLens構築
   └─ 各エントリからTextRangeとCommandを構築してCodeLensを生成
6. レスポンス返却
   └─ CodeLens配列をクライアントに返却
```

### フローチャート

```mermaid
flowchart TD
    A[textDocument/codeLens リクエスト受信] --> B{enableGCProfilerDecorations?}
    B -->|false| C[null を返却]
    B -->|true| D[profileGCCache を走査]
    D --> E{entry.uri == 要求URI?}
    E -->|Yes| F[CodeLens を構築]
    E -->|No| G[スキップ]
    F --> H[次のエントリへ]
    G --> H
    H --> I{全エントリ処理済み?}
    I -->|No| E
    I -->|Yes| J[CodeLens配列を返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-71-01 | GCプロファイラ表示制御 | enableGCProfilerDecorationsがfalseの場合、コードレンズを返さない | 常時 |
| BR-71-02 | URIマッチング | エントリのURIとリクエストのドキュメントURIが完全一致するもののみ表示 | コードレンズ生成時 |
| BR-71-03 | 行番号変換 | profilegc.logの行番号は1ベースだが、LSPは0ベースのため1を減算する | CodeLens生成時 |
| BR-71-04 | ファイルウォッチャー登録 | クライアントがdidChangeWatchedFilesの動的登録をサポートする場合、**/profilegc.logパターンで監視登録する | コンポーネント登録時 |

### 計算ロジック

profilegc.logの各行を空白で分割し、以下の形式でパースする：
- 第1カラム: バイト割り当て量(bytesAllocated)
- 第2カラム: 割り当て回数(allocationCount)
- 第3カラム以降（最後のファイル:行番号の前まで）: 型名(type)
- 最後のフィールド: ファイル名:行番号

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

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

本機能ではデータベース操作は行わない。profileGCCacheというインメモリキャッシュ（連想配列）を使用する。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | FileException | profilegc.logファイルが見つからない・読み込めない場合 | キャッシュからエントリを削除し、traceログ出力 |
| - | Exception | profilegc.logの解析中に予期しないエラーが発生した場合 | キャッシュからエントリを削除し、traceログ出力 |
| - | 動的登録失敗 | ファイルウォッチャーの動的登録が失敗した場合 | errorログ出力 |

### リトライ仕様

リトライは行わない。ファイル変更時に再度update処理が走る。

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

トランザクション管理は不要（インメモリ処理のみ）。

## パフォーマンス要件

profilegc.logの解析はキャッシュ機構を使用しており、ファイル変更時のみ再解析する。コードレンズ要求時はキャッシュ済みデータをフィルタリングするのみのため、低レイテンシで応答する。

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

profilegc.logはローカルファイルシステム上のプロファイルデータであり、特別なセキュリティ考慮は不要。ファイルパスのURI変換時にuriBuildNormalizedが使用される。

## 備考

- profilegc.logはD言語ランタイムの`--DRT-gcopt=profile:1`オプションで生成される
- ファイルウォッチャーによりログファイルの作成・変更・削除がリアルタイムに反映される
- プロジェクト追加時にも自動的にprofilegc.logの読み込みが試行される

---

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

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

### 推奨読解順序

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

まず、ProfileGCのデータモデルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | profilegc.d | `source/served/workers/profilegc.d` | ProfileGCEntry構造体（15-22行目）とProfileGCCache構造体（24-95行目）の定義 |

**読解のコツ**: `ProfileGCEntry`はprofilegc.logの1行に対応し、バイト割り当て量・割り当て回数・型名・ファイルURI・行番号を保持する。`ProfileGCCache`はドキュメントURI単位でエントリをキャッシュする仕組みで、内部に`PerDocumentCache`を持つ。

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

LSPリクエストハンドラとイベントフックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | profilegc.d | `source/served/workers/profilegc.d` | `provideProfileGCCodeLens`関数（99-120行目）がtextDocument/codeLensの処理を担当 |

**主要処理フロー**:
1. **99行目**: `@protocolMethod("textDocument/codeLens")`アノテーションでLSPメソッドとして登録
2. **102-103行目**: `config(params.textDocument.uri).d.enableGCProfilerDecorations`の設定確認。falseならnull返却
3. **106-118行目**: `profileGCCache.caches`を二重ループで走査し、URIが一致するエントリからCodeLensを構築
4. **112-114行目**: `TextRange(entry.line - 1, 0, entry.line - 1, 1)`で行番号を0ベースに変換し、コマンドにバイト数/回数を表示

#### Step 3: キャッシュ管理を理解する

profilegc.logの読み込みとキャッシュの更新ライフサイクルを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | profilegc.d | `source/served/workers/profilegc.d` | `PerDocumentCache.process`メソッド（30-62行目）でログファイルの各行をパース |
| 3-2 | profilegc.d | `source/served/workers/profilegc.d` | `ProfileGCCache.update`メソッド（67-88行目）でドキュメントの読み込みと解析を実行 |

**主要処理フロー**:
- **30-62行目**: `process`メソッドでログの各行を空白で分割し、ファイル名:行番号を抽出してProfileGCEntryを構築
- **73行目**: `documents.getOrFromFilesystem(uri)`でファイル内容をドキュメントマネージャまたはファイルシステムから取得
- **75行目**: `caches.require(uri).process(uri.uriDirName, profileGC.rawText)`でパース結果をキャッシュに格納

#### Step 4: イベントフックを理解する

ファイルウォッチャー登録とプロジェクト追加時の初期化。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | profilegc.d | `source/served/workers/profilegc.d` | `setupProfileGCWatchers`関数（131-150行目）でファイルウォッチャーを動的登録 |
| 4-2 | profilegc.d | `source/served/workers/profilegc.d` | `onProfileGCProjectAvailable`関数（152-156行目）でプロジェクト追加時にキャッシュ更新 |
| 4-3 | profilegc.d | `source/served/workers/profilegc.d` | `onChangeProfileGC`関数（158-172行目）でファイル変更通知時にキャッシュ更新/クリア |

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

```
textDocument/codeLens リクエスト
    │
    ├─ provideProfileGCCodeLens (99行目)
    │      ├─ config().d.enableGCProfilerDecorations (102行目)
    │      └─ profileGCCache.caches 走査 (106-118行目)
    │
workspace/didChangeWatchedFiles 通知
    │
    ├─ onChangeProfileGC (158行目)
    │      ├─ profileGCCache.update (168行目)
    │      │      ├─ documents.getOrFromFilesystem (73行目)
    │      │      └─ PerDocumentCache.process (75行目)
    │      └─ profileGCCache.clear (170行目)
    │
@onRegisteredComponents
    │
    └─ setupProfileGCWatchers (131行目)
           └─ rpc.registerCapabilitySync (139行目)
```

### データフロー図

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

profilegc.log ─────────▶ PerDocumentCache.process ──▶ ProfileGCEntry[]
                            (行パース・構造化)            (キャッシュ格納)

textDocument/codeLens ──▶ provideProfileGCCodeLens ──▶ CodeLens[]
  リクエスト                (キャッシュ照会・                (エディタ表示)
                            URIフィルタ)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| profilegc.d | `source/served/workers/profilegc.d` | ソース | ProfileGCコードレンズの主実装（キャッシュ管理・コードレンズ提供・ファイル監視） |
| types.d | `source/served/types.d` | ソース | DocumentUri型、config関数、documents等の共通型定義 |
| protocol.d | `protocol/source/served/lsp/protocol.d` | ソース | CodeLens、TextRange、Command等のLSPプロトコル型定義 |
| uri.d | `protocol/source/served/lsp/uri.d` | ソース | uriBuildNormalized等のURI操作ユーティリティ |
