# 機能設計書 33-未使用関数 (unused-function)

## 概要

本ドキュメントは、Lua Language Serverにおける「未使用関数検出機能」の設計詳細を記載したものである。定義されたが呼び出されていない関数を検出し、デッドコードの識別とコードベースの整理を支援する診断機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：
ソフトウェア開発の過程で、使用されなくなった関数が残存することがある。これらのデッドコードはコードベースの肥大化、メンテナンス負荷の増加、セキュリティリスクの原因となる。本機能は、呼び出されていない関数を検出し、開発者に警告することで、コードベースの健全性維持を支援する。

**機能の利用シーン**：
- リファクタリング時に削除可能な関数を特定する
- コードレビュー時に不要な関数定義を発見する
- 技術的負債の可視化と削減

**主要な処理内容**：
1. 対象ファイルのASTを取得する
2. AST内の全`function`ノードを収集し、white（潜在的に未使用）リストに追加する
3. 関数の参照関係を分析し、ルート関数（外部から呼ばれる関数）を特定する
4. ルート関数から到達可能な関数をblack（使用済み）リストに移動する
5. whiteリストに残った関数を未使用として報告する

**関連システム・外部連携**：
- LSP (Language Server Protocol)クライアント（VSCode等のエディタ）との連携
- 診断結果はLSPの`textDocument/publishDiagnostics`通知で送信される

**権限による制御**：
- 設定`Lua.diagnostics.disable`で本診断を無効化可能
- メタファイル内の関数は診断対象外

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 26 | 診断情報 | 補助機能 | 未使用の関数を検出 |

## 機能種別

バリデーション / 静的解析 / 診断

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| uri | string | Yes | 診断対象ファイルのURI | 有効なファイルURIであること |
| callback | function | Yes | 診断結果を受け取るコールバック関数 | - |

### 入力データソース

- ファイルシステムから読み込まれたLuaソースコード
- `files.getState(uri)`から取得されるAST情報

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| start | integer | エラー位置の開始オフセット |
| finish | integer | エラー位置の終了オフセット |
| tags | table | DiagnosticTag.Unnecessaryを含む配列 |
| message | string | 診断メッセージ（「未使用の関数」） |

### 出力先

- LSPクライアントへの診断通知（`textDocument/publishDiagnostics`）
- エディタ上でのインライン警告表示（淡色表示またはfunctionキーワードのハイライト）

## 処理フロー

### 処理シーケンス

```
1. ファイル状態の取得
   └─ files.getState(uri)でAST付きの状態を取得
2. メタファイル判定
   └─ vm.isMetaFile(uri)でメタファイルの場合は処理終了
3. 関数の収集と分類
   └─ collect(ast, white, roots, links)で関数を収集
4. ルート関数の特定
   └─ 外部参照される関数をrootsに追加
5. 到達可能性分析
   └─ turnBlack(source, black, white, links)で使用済みをマーク
6. 未使用関数の報告
   └─ whiteリストに残った関数を診断として報告
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[ファイル状態を取得]
    B --> C{状態が存在するか?}
    C -->|No| D[終了]
    C -->|Yes| E{メタファイルか?}
    E -->|Yes| D
    E -->|No| F[関数を収集]
    F --> G[white/roots/linksを構築]
    G --> H[roots関数からturnBlack]
    H --> I{whiteリストに関数あり?}
    I -->|No| D
    I -->|Yes| J[未使用関数を報告]
    J --> K{Unnecessaryタグ対応?}
    K -->|Yes| L[関数全体をマーク]
    K -->|No| M[keywordのみマーク]
    L --> D
    M --> D
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-33-01 | 有効な関数判定 | main関数、親なし、local/setlocal以外の親は対象外 | isValidFunction |
| BR-33-02 | to-be-closed除外 | `<close>`属性を持つ関数は除外 | isToBeClosed |
| BR-33-03 | ルート関数判定 | 親関数がないか、rootsに含まれる関数から参照される場合はルート | collect関数 |
| BR-33-04 | 到達可能性伝播 | ルート関数から呼び出される関数は全て使用済みとマーク | turnBlack関数 |
| BR-33-05 | メタファイル除外 | メタファイル内の関数は全て診断対象外 | vm.isMetaFile |
| BR-33-06 | クライアント能力対応 | Unnecessaryタグ非対応時はkeywordのみハイライト | client.getAbility |

### 計算ロジック

#### 到達可能性分析（グラフ探索）

```lua
-- links[func] = { 呼び出す関数のリスト }
-- roots = { 外部から呼ばれる関数 }
-- white = { 潜在的に未使用の関数 }
-- black = { 使用済みの関数 }

-- turnBlack: ルートから到達可能な全関数をblackに移動
function turnBlack(source, black, white, links)
    if black[source] then return end
    black[source] = true
    white[source] = nil
    for _, link in ipairs(links[source] or {}) do
        turnBlack(link, black, white, links)
    end
end
```

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

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ファイル状態なし | files.getState(uri)がnilを返す場合 | 処理を中断して正常終了 |

### リトライ仕様

リトライは行わない。ファイルが再度編集された際に自動的に再診断される。

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

該当なし（読み取り専用処理）

## パフォーマンス要件

- 単一ファイルの診断は通常0.5秒以内に完了すること
- `await.delay()`により非同期処理のブロッキングを防止

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

- ユーザーコードの読み取りのみを行い、ファイルシステムへの書き込みは行わない
- 外部ネットワークへのアクセスは行わない

## 備考

- グラフ探索アルゴリズムにより、関数間の呼び出し関係を正確に分析
- クライアントのタグサポート状況に応じて、ハイライト範囲を調整

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | define.lua | `script/proto/define.lua` | DiagnosticTag.Unnecessaryの定義 |

**読解のコツ**: この診断では4つのテーブル（white, black, roots, links）を使用したグラフ探索を行う。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | unused-function.lua | `script/core/diagnostics/unused-function.lua` | メイン診断関数 |

**主要処理フロー**:
1. **88-96行目**: ファイル状態取得とメタファイルチェック
2. **98-101行目**: 4つの管理テーブルを初期化
3. **103行目**: collect関数で関数を収集・分類
4. **105-107行目**: ルート関数からturnBlackを実行
5. **112-128行目**: whiteリストの関数を診断として報告

#### Step 3: 収集ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | unused-function.lua | `script/core/diagnostics/unused-function.lua` | collect関数 |

**主要処理フロー**:
- **10-20行目**: `isToBeClosed`関数 - close属性チェック
- **24-43行目**: `isValidFunction`関数 - 有効な関数かを判定
- **46-74行目**: `collect`関数 - 関数を収集してwhite/roots/linksに分類

#### Step 4: 到達可能性分析を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | unused-function.lua | `script/core/diagnostics/unused-function.lua` | turnBlack関数 |

**主要処理フロー**:
- **76-85行目**: `turnBlack`関数 - 再帰的に到達可能な関数をマーク

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

```
script/core/diagnostics/init.lua (診断エントリー)
    │
    ├─ require('core.diagnostics.unused-function')
    │      │
    │      ├─ files.getState(uri)
    │      │
    │      ├─ vm.isMetaFile(uri)
    │      │
    │      ├─ collect(ast, white, roots, links)
    │      │      │
    │      │      ├─ guide.eachSourceType(ast, 'function', callback)
    │      │      ├─ isValidFunction(src)
    │      │      ├─ isToBeClosed(parent)
    │      │      └─ guide.getParentFunction(ref)
    │      │
    │      ├─ turnBlack(source, black, white, links)
    │      │      └─ 再帰呼び出し
    │      │
    │      └─ client.getAbility('textDocument.completion...')
    │
    └─ callback(result)
```

### データフロー図

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

Luaソースコード ───▶ パーサー(AST生成) ───▶ AST
                                              │
                                              ▼
                         collect ───▶ white（潜在的未使用）
                                  ───▶ roots（ルート関数）
                                  ───▶ links（呼び出し関係）
                                              │
                                              ▼
                         turnBlack ───▶ black（使用済み）
                                              │
                                              ▼
                         white - black ───▶ 未使用関数
                                              │
                                              ▼
                         診断メッセージ生成 ───▶ LSP診断通知
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| unused-function.lua | `script/core/diagnostics/unused-function.lua` | ソース | 未使用関数診断のメインロジック |
| init.lua | `script/core/diagnostics/init.lua` | ソース | 診断処理のエントリーポイント |
| define.lua | `script/proto/define.lua` | ソース | DiagnosticTag定義 |
| vm.lua | `script/vm/vm.lua` | ソース | isMetaFile判定 |
| guide.lua | `script/parser/guide.lua` | ソース | AST操作、getParentFunction |
| files.lua | `script/files.lua` | ソース | ファイル状態管理 |
| client.lua | `script/client.lua` | ソース | クライアント能力取得 |
| await.lua | `script/await.lua` | ソース | 非同期処理ユーティリティ |
| utility.lua | `script/utility.lua` | ソース | arrayHasなどのユーティリティ |
