# 機能設計書 54-テスト参照分離

## 概要

本ドキュメントは、clojure-lspにおけるテスト参照分離機能の設計を記述する。この機能はCode Lens（参照数表示）において、通常のコード参照とテストコードからの参照を分離してカウント・表示する。

### 本機能の処理概要

**業務上の目的・背景**：
関数の参照数を把握する際、テストコードからの参照と本番コードからの参照を区別することは重要である。テストコードからの参照が多いシンボルは、テストによく使われるユーティリティである可能性が高い。一方、本番コードからの参照が少なくテストからの参照のみ多い場合、そのシンボルはテスト専用ヘルパーである可能性がある。この機能により、開発者はコードの使用状況をより詳細に把握できる。

**機能の利用シーン**：
1. リファクタリング時に本番コードへの影響範囲を特定する場面
2. テスト専用ヘルパーを識別する場面
3. 未使用コードの検出時にテスト参照を除外して判断する場面
4. コードカバレッジの傾向を把握する場面

**主要な処理内容**：
1. シンボルの全参照を検索
2. 各参照のURIを`test-locations-regex`パターンでマッチング
3. テスト参照と通常参照に分類
4. 分類結果を"N references | M tests"形式で表示

**関連システム・外部連携**：
- Code Lens機能（参照数表示）：この機能の基盤
- 設定システム：`segregate-test-references`と`test-locations-regex`設定

**権限による制御**：
特に権限による制御はない。設定で機能を有効/無効化可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| N/A | エディタ | 主画面 | 分離された参照数の表示 |

## 機能種別

情報表示処理 / データ分類処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| :segregate-test-references | boolean | No | テスト参照分離の有効/無効（デフォルト: true） | - |
| :test-locations-regex | vector<string> | No | テストファイルを識別する正規表現パターン | 有効な正規表現 |

### 入力データソース

- LSP設定（`.lsp/config.edn`または初期化オプション）
- 解析データから取得した参照一覧

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 分離有効時 | string | "N references \| M tests" |
| 分離無効時 | string | "N references" |
| テスト参照0時 | string | "N references" |

### 出力先

Code Lensのcommand.titleフィールド

## 処理フロー

### 処理シーケンス

```
1. 設定取得
   └─ segregate-test-referencesとtest-locations-regexを取得
2. 参照検索
   └─ find-references-from-cursorで全参照を取得
3. ソースパス解決
   └─ 対象URIからソースパスを計算
4. 参照分類
   └─ 各参照のURIがテストパターンにマッチするか判定
5. 結果生成
   └─ 分類結果に応じた表示文字列を生成
```

### フローチャート

```mermaid
flowchart TD
    A[codeLens/resolve受信] --> B{segregate-lens?}
    B -->|No| C[全参照カウント]
    C --> D["N references"を返却]
    B -->|Yes| E[source-uri計算]
    E --> F[各参照を分類]
    F --> G{参照URIがテストパターンにマッチ?}
    G -->|Yes| H[テスト参照に分類]
    G -->|No| I[通常参照に分類]
    H --> J{テスト参照あり?}
    I --> J
    J -->|Yes| K["N refs | M tests"を返却]
    J -->|No| L["N references"を返却]
    D --> M[終了]
    K --> M
    L --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-54-01 | デフォルト有効 | segregate-test-referencesはデフォルトでtrue | 設定なしの場合 |
| BR-54-02 | 自己テスト除外 | テストファイル内のシンボルはテスト内参照をテストカウントしない | 常時 |
| BR-54-03 | パターンマッチング | test-locations-regexの全パターンでマッチングを実行 | 常時 |
| BR-54-04 | デフォルトパターン | デフォルトは`["test"]`（パスに"test"を含む） | 設定なしの場合 |
| BR-54-05 | ソースパス基準 | ソースパスが特定できない場合はテスト分離しない | source-pathsに含まれない場合 |

### 計算ロジック

テスト参照判定ロジック:
```clojure
(defn test-reference? [test-locations-regex source-uri reference-uri]
  (and source-uri
       ;; テストファイル内からの参照はテスト参照としてカウントしない
       (not (string/starts-with? reference-uri source-uri))
       ;; テストパターンにマッチするか
       (some #(re-find % reference-uri) test-locations-regex)))
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 参照検索 | db.analysis | SELECT | var-usagesから参照元を検索 |
| 設定取得 | db.settings | SELECT | テスト関連設定の取得 |

### テーブル別操作詳細

#### db.analysis

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | var-usages.uri | 参照検索結果 | テスト判定に使用 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 正規表現エラー | 不正なパターン | エラーログ出力、パターンを無視 |

### リトライ仕様

リトライは行わない。

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

読み取り専用のため、トランザクション管理は不要。

## パフォーマンス要件

- 参照分類は参照検索後に実行されるため、追加のオーバーヘッドは最小限
- 正規表現コンパイルは設定読み込み時に1回のみ

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

- ユーザー提供の正規表現パターンによるReDoS攻撃に注意

## 備考

- `shared/test-locations-regex-default`にデフォルトパターン`["test"]`が定義
- テストファイル内のシンボルについては、同一テストファイル内からの参照をテスト参照としてカウントしない（ヘルパー関数の使用をテスト参照としないため）

---

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

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

### 推奨読解順序

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

テスト参照分離に関連する設定とデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | shared.clj | `lib/src/clojure_lsp/shared.clj` | `test-locations-regex-default`定義 |
| 1-2 | code_lens.clj | `lib/src/clojure_lsp/feature/code_lens.clj` | 設定値の取得方法（40-45行目） |

**読解のコツ**: `test-locations-regex`は文字列の配列だが、使用時に`re-pattern`で正規表現オブジェクトに変換される。

#### Step 2: テスト参照判定ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | code_lens.clj | `lib/src/clojure_lsp/feature/code_lens.clj` | **33-37行目**: `test-reference?`関数 |

**主要処理フロー**:
- **34行目**: `source-uri`が存在することを確認
- **35-36行目**: 参照URIがソースURIで始まらないことを確認（自己参照除外）
- **37行目**: テストパターンのいずれかにマッチするか確認

#### Step 3: 参照分類処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | code_lens.clj | `lib/src/clojure_lsp/feature/code_lens.clj` | **39-67行目**: `resolve-code-lens`関数 |

**主要処理フロー**:
- **40行目**: `segregate-lens?`設定を取得（デフォルト: true）
- **41-45行目**: `test-locations-regex`を取得してパターンに変換
- **46行目**: 全参照を検索
- **47行目**: `segregate-lens?`に応じて分岐
- **48-50行目**: ソースURIを計算
- **51行目**: 通常参照をフィルタ（テスト参照でないもの）
- **52行目**: テスト参照をフィルタ
- **53-62行目**: テスト参照の有無で表示形式を決定

#### Step 4: 表示文字列生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | code_lens.clj | `lib/src/clojure_lsp/feature/code_lens.clj` | **10-21行目**: 表示文字列生成関数 |

**主要処理フロー**:
- **10-15行目**: `references->string`で複数形処理
- **17-18行目**: `main-references->string`で"N reference(s)"形式
- **20-21行目**: `test-references->string`で"N test(s)"形式

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

```
resolve-code-lens (code_lens.clj:39-67)
    │
    ├─ settings/get :segregate-test-references (40行目)
    │
    ├─ settings/get :test-locations-regex (42-45行目)
    │
    ├─ q/find-references-from-cursor (46行目)
    │
    ├─ shared/uri->source-path (49行目)
    │
    ├─ shared/filename->uri (50行目)
    │
    ├─ test-reference? (code_lens.clj:33-37)
    │      │
    │      ├─ string/starts-with? (自己参照チェック)
    │      │
    │      └─ re-find (パターンマッチ)
    │
    ├─ main-references->string (code_lens.clj:17-18)
    │      └─ references->string (code_lens.clj:10-15)
    │
    └─ test-references->string (code_lens.clj:20-21)
           └─ references->string (code_lens.clj:10-15)
```

### データフロー図

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

codeLens/resolve            ┌────────────────────────────────────┐
Request                     │                                    │
  └─ data [uri,row,col] ───►│  resolve-code-lens                 │
                            │                                    │
settings                    │    ├─ segregate-test-references?   │
  ├─ segregate-test-refs ──►│    │                               │
  └─ test-locations-regex ─►│    ├─ test-locations-regex         │
                            │    │                               │
db.analysis                 │    └─ find-references-from-cursor  │
  └─ var-usages ───────────►│         │                          │
                            │         ▼                          │
                            │    各参照を分類                     │
                            │         │                          │
                            │    ┌────┴────┐                     │
                            │    │         │                     │
                            │    ▼         ▼                     │
                            │  通常参照   テスト参照              │         CodeLens
                            │    │         │                     │           │
                            │    └────┬────┘                     │────────► command.title
                            │         │                          │           "N refs | M tests"
                            │    表示文字列生成                   │
                            │                                    │
                            └────────────────────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| code_lens.clj | `lib/src/clojure_lsp/feature/code_lens.clj` | ソース | テスト参照分離の実装 |
| shared.clj | `lib/src/clojure_lsp/shared.clj` | ソース | デフォルトパターン定義 |
| settings.clj | `lib/src/clojure_lsp/settings.clj` | ソース | 設定管理 |
| code_lens_test.clj | `lib/test/clojure_lsp/feature/code_lens_test.clj` | テスト | テスト参照分離のテスト |
