# 機能設計書 23-参照検索 (textDocument/references)

## 概要

本ドキュメントは、serve-d LSPサーバーにおける参照検索機能（textDocument/references）の設計を記述する。カーソル位置のシンボルの全参照箇所をワークスペース横断で非同期検索し返却する機能である。

### 本機能の処理概要

**業務上の目的・背景**：リファクタリングや影響範囲調査において、シンボルがプロジェクト全体でどこから参照されているかを知ることは不可欠である。本機能は、エディタの「Find All References」コマンドに対応し、シンボルの全参照箇所を一覧表示する。

**機能の利用シーン**：開発者がエディタ上でシンボルを選択して「全ての参照を検索」コマンドを実行した際に呼び出される。宣言箇所を含めるかどうかはコンテキストパラメータで制御される。

**主要な処理内容**：
1. カーソル位置のバイトオフセットを計算し、DCDComponentの存在を確認する
2. 非同期でReferencesComponentのfindReferences APIを呼び出す
3. 各参照箇所について、ファイルとオフセットからLocationオブジェクトに変換する
4. AsyncReceiverパターンにより結果を逐次的にクライアントへストリーミング返却する

**関連システム・外部連携**：DCDComponent、ReferencesComponent、AsyncReceiver（非同期結果受信クラス）

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 27 | 参照検索（textDocument/references） | 主画面 | カーソル位置のシンボルの全参照箇所を非同期で検索し返却する |

## 機能種別

データ検索（ワークスペース横断のシンボル参照検索、非同期ストリーミング）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| textDocument.uri | DocumentUri | Yes | 対象ドキュメントのURI | 有効なドキュメントURIであること |
| position | Position | Yes | カーソル位置（行・列） | ドキュメント範囲内であること |
| context.includeDeclaration | bool | Yes | 宣言箇所を結果に含めるか | - |

### 入力データソース

- LSPクライアントからのtextDocument/referencesリクエストのReferenceParams
- ドキュメントマネージャに保持されたドキュメントのテキストデータ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| uri | DocumentUri | 参照箇所のファイルURI |
| range | TextRange | 参照箇所の位置範囲（単語範囲） |

### 出力先

LSPクライアント（JSON-RPCレスポンスとして返却。AsyncReceiverによる非同期ストリーミング）

## 処理フロー

### 処理シーケンス

```
1. textDocument/referencesリクエスト受信
   └─ ReferenceParamsからURI・位置・includeDeclarationを取得
2. AsyncReceiver<Location>オブジェクトの生成
   └─ 非同期結果受信用のコンテナを初期化
3. カーソル位置をバイトオフセットに変換
   └─ document.positionToBytes
4. DCDComponentの存在確認
   └─ 存在しない場合はreceiver.end()で即時終了
5. setImmediateで非同期タスクを登録
   └─ ファイバーベースの即時非同期実行
6. ReferencesComponent.findReferences API呼び出し
   └─ コールバック関数で結果を逐次受信
7. 各参照箇所のLocation変換
   └─ resolveLocation関数でファイル・オフセットからLocationに変換
   7-1. uriFromFileでファイルパスをURIに変換
   7-2. documents.getOrFromFilesystemでドキュメント取得
   7-3. bytesToPositionでバイトオフセットを位置に変換
   7-4. wordRangeAtで単語範囲を取得
8. includeDeclaration判定
   └─ 宣言箇所と一致する参照は、includeDeclaration=false時にスキップ
9. receiver.putで結果を蓄積
10. receiver.end()で完了通知
```

### フローチャート

```mermaid
flowchart TD
    A[references リクエスト受信] --> B[AsyncReceiver生成]
    B --> C[カーソル位置をバイトオフセットに変換]
    C --> D{DCDComponent存在?}
    D -->|No| E[receiver.end で即時終了]
    D -->|Yes| F[setImmediateで非同期タスク登録]
    F --> G[ReferencesComponent.findReferences呼び出し]
    G --> H[コールバックで参照結果受信]
    H --> I{includeDeclaration判定}
    I -->|宣言箇所 and !includeDeclaration| J[スキップ]
    I -->|それ以外| K[resolveLocation でLocation変換]
    K --> L[receiver.put で結果蓄積]
    J --> H
    L --> H
    H --> M[全参照走査完了]
    M --> N[receiver.end で完了通知]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-23-01 | 宣言箇所除外 | includeDeclaration=falseの場合、宣言箇所を結果から除外する | 各参照のフィルタ時 |
| BR-23-02 | 宣言箇所判定 | definitionFileとdefinitionLocationが参照のfile/locationと一致する場合を宣言箇所とする | フィルタ条件の評価 |
| BR-23-03 | DCDComponent必須 | DCDComponentが存在しない場合は空の結果を返す | 処理開始時 |
| BR-23-04 | 非同期実行 | setImmediateにより非同期タスクとして実行される | 常に |
| BR-23-05 | ファイルシステムフォールバック | 参照先ファイルがドキュメントマネージャに無い場合、ファイルシステムから読み込む | resolveLocation時 |

### 計算ロジック

特になし。

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

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

データベース操作は行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 空結果 | DCDComponentが存在しない場合 | receiver.end()で空結果を返却 |
| - | 例外 | ReferencesComponent.findReferencesが例外をスローした場合 | receiver.errorに例外を設定、クライアントにエラーを伝搬 |

### リトライ仕様

リトライは不要。

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

トランザクションは使用しない（読み取り専用操作）。

## パフォーマンス要件

- AsyncReceiverパターンにより、全結果の収集を待たずに逐次的に結果をクライアントに返す
- Fiber.yieldによる協調的マルチタスクでブロッキングを回避
- 大規模プロジェクトでは参照箇所が多数になる可能性があるため、ストリーミング返却が重要

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

特になし。

## 備考

- AsyncReceiverクラスは本モジュール内に定義されたジェネリック非同期結果受信クラスで、Mutexによるスレッドセーフティとファイバーベースの待機を実現している
- resolveLocation関数はdocuments.getOrFromFilesystemを使用しており、まだ開かれていないファイルもファイルシステムから読み込んで位置解決する
- getYield()はファイバーベースの非同期待機を行うAPIで、バックグラウンドワーカースレッドでの処理完了を待つ

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | references.d | `source/served/commands/references.d` | AsyncReceiver<T>クラス（65-141行目）の構造を理解する。Mutex, Fiber.yield, ended/notifiedフラグの仕組み |

**読解のコツ**: AsyncReceiverはInputRange風のインターフェース（front, popFront, empty）を提供し、Fiber.yieldで協調的に待機する。notifiedフラグとMutexによりプロデューサー（非同期タスク）とコンシューマー（LSPレスポンス構築）間のデータ受け渡しを安全に行う。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | references.d | `source/served/commands/references.d` | findReferences関数（13-55行目）がLSPプロトコルメソッドのエントリーポイント |

**主要処理フロー**:
1. **16行目**: `new AsyncReceiver!Location()` 非同期受信オブジェクト生成
2. **18行目**: `document.positionToBytes` カーソル位置のバイトオフセット変換
3. **22-26行目**: DCDComponent存在チェック、存在しなければ即終了
4. **28行目**: `params.context.includeDeclaration` 宣言含有フラグ取得
5. **29行目**: `setImmediate` で非同期タスク登録
6. **35-46行目**: `ReferencesComponent.findReferences` の呼び出しとコールバック処理
7. **41行目**: includeDeclaration判定による宣言箇所スキップ
8. **43行目**: `resolveLocation` でLocation変換

#### Step 3: 位置解決を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | references.d | `source/served/commands/references.d` | resolveLocation関数（57-63行目）でファイル・オフセットからLocationに変換する処理 |

**主要処理フロー**:
- **59行目**: `file.uriFromFile` ファイルパスからURIに変換
- **60行目**: `documents.getOrFromFilesystem(uri)` ドキュメント取得（未開封ファイルはFS読込）
- **61行目**: `doc.bytesToPosition(location)` バイトオフセットから位置変換
- **62行目**: `doc.wordRangeAt(pos)` 単語範囲の取得

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

```
findReferences (references.d:14)
    |
    +-- AsyncReceiver!Location (references.d:65)
    |
    +-- setImmediate (非同期タスク登録)
    |       |
    |       +-- ReferencesComponent.findReferences (workspaced/com/references.d)
    |       |       |
    |       |       +-- コールバック: resolveLocation (references.d:57)
    |       |               |
    |       |               +-- uriFromFile
    |       |               +-- documents.getOrFromFilesystem
    |       |               +-- Document.bytesToPosition
    |       |               +-- Document.wordRangeAt
    |       |
    |       +-- receiver.put (結果蓄積)
    |       +-- receiver.end (完了通知)
    |
    +-- receiver返却 (クライアントへのストリーミング)
```

### データフロー図

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

ReferenceParams -----------> findReferences ------------------> Location[]
  (uri, position,                  |                          (AsyncReceiver経由)
   includeDeclaration)             v
                            ReferencesComponent.findReferences
                                   |
                                   v
                            コールバック受信 (file, location)
                                   |
                                   v
                            resolveLocation
                              (file -> URI, offset -> Position)
                                   |
                                   v
                            receiver.put -> クライアントへストリーミング
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| references.d | `source/served/commands/references.d` | ソース | 参照検索のメイン実装（findReferences, resolveLocation, AsyncReceiver） |
| types.d | `source/served/types.d` | ソース | LSP型定義（Location, Position, TextRange等） |
| async.d | `source/served/utils/async.d` | ソース | setImmediate等の非同期ユーティリティ |
| references.d (workspaced) | `workspace-d/source/workspaced/com/references.d` | ソース | ReferencesComponent.findReferences APIの実装 |
| dcd.d (workspaced) | `workspace-d/source/workspaced/com/dcd.d` | ソース | DCDComponentの定義 |
