# 機能設計書 31-未定義グローバル (undefined-global)

## 概要

本ドキュメントは、Lua Language Serverにおける「未定義グローバル変数検出機能」の設計詳細を記載したものである。コード中で定義されていないグローバル変数の使用を検出し、潜在的なバグや誤字を早期発見するための診断機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：
Luaは動的型付け言語であり、変数の宣言が不要で任意の名前のグローバル変数にアクセスできる。この特性により、変数名のタイプミスや未定義変数への参照がランタイムエラーとなり、デバッグが困難になる場合がある。本機能は、コード記述時点で未定義のグローバル変数使用を検出し、開発者に警告することで、ランタイムエラーを未然に防止する。

**機能の利用シーン**：
- コードエディタでLuaファイルを編集中にリアルタイムで診断結果が表示される
- ワークスペース全体の診断実行時に一括でチェックされる
- CI/CDパイプラインでのコードチェック時に使用される

**主要な処理内容**：
1. 対象ファイルのASTを取得する
2. AST内の`getglobal`タイプのノードを走査する
3. 各グローバル変数参照に対して`vm.isUndefinedGlobal`で未定義判定を行う
4. 未定義の場合、`require`/`include`/`import`/`load`に類似した名前かどうかを追加チェックする
5. 診断結果をコールバック関数経由で報告する

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

**権限による制御**：
- 設定`Lua.diagnostics.disable`で本診断を無効化可能
- 設定`Lua.diagnostics.globals`で特定のグローバル変数を許可リストに追加可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 26 | 診断情報 | 補助機能 | 未定義のグローバル変数を検出 |
| 38 | 診断チェック | 補助機能 | 未定義グローバル変数の検出 |

## 機能種別

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

## 入力仕様

### 入力パラメータ

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

### 入力データソース

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

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| start | integer | エラー位置の開始オフセット |
| finish | integer | エラー位置の終了オフセット |
| message | string | 診断メッセージ（例：「未定義のグローバル `xxx`」） |
| undefinedGlobal | string | 未定義と判定されたグローバル変数名 |

### 出力先

- LSPクライアントへの診断通知（`textDocument/publishDiagnostics`）
- エディタ上でのインライン警告表示

## 処理フロー

### 処理シーケンス

```
1. ファイル状態の取得
   └─ files.getState(uri)でAST付きの状態を取得
2. AST走査の開始
   └─ guide.eachSourceType(state.ast, 'getglobal', callback)
3. 各グローバル変数参照の評価
   └─ vm.isUndefinedGlobal(src)で未定義判定
4. 未定義時のメッセージ生成
   └─ requireLike変数の場合は追加情報を付与
5. 診断結果のコールバック
   └─ callback({ start, finish, message, undefinedGlobal })
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[ファイル状態を取得]
    B --> C{状態が存在するか?}
    C -->|No| D[終了]
    C -->|Yes| E[getglobalノードを走査]
    E --> F{未定義グローバルか?}
    F -->|No| G[次のノードへ]
    F -->|Yes| H{requireLike名か?}
    H -->|Yes| I[追加メッセージを付与]
    H -->|No| J[基本メッセージを生成]
    I --> K[診断結果をコールバック]
    J --> K
    K --> G
    G --> L{全ノード処理完了?}
    L -->|No| E
    L -->|Yes| D
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-31-01 | 未定義判定 | setモードが一度も存在しないグローバル変数は未定義と判定 | getglobalノードに対して |
| BR-31-02 | requireLike判定 | include/import/require/loadに類似した名前の場合、追加ヒントを表示 | 未定義グローバルの名前が対象 |
| BR-31-03 | 大文字小文字無視 | requireLike判定は大文字小文字を無視して比較 | 名前の比較時 |

### 計算ロジック

なし

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

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

## エラー処理

### エラーケース一覧

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

### リトライ仕様

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

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

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

## パフォーマンス要件

- 単一ファイルの診断は通常0.5秒以内に完了すること
- 診断時間が0.5秒を超えた場合はログに警告を出力する

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

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

## 備考

- `Lua.diagnostics.globals`設定で特定のグローバル変数を許可リストに追加することで、警告を抑制できる
- メタファイル内では診断が異なる挙動をする場合がある

---

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

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

### 推奨読解順序

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

まず、診断機能で使用される基本的なデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | define.lua | `script/proto/define.lua` | DiagnosticSeverity、DiagnosticTagなどの診断関連定数を定義 |
| 1-2 | guide.lua | `script/parser/guide.lua` | parser.objectの型定義、AST操作のユーティリティ |

**読解のコツ**: Luaではクラスの代わりにテーブルとメタテーブルを使用する。`---@class`アノテーションで型情報が定義されている。

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

診断処理の起点となるファイルを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | init.lua | `script/core/diagnostics/init.lua` | 診断処理のメインループ、各診断モジュールの呼び出し |

**主要処理フロー**:
1. **119行目**: `require('core.diagnostics.' .. name)(uri, function (result) ...)`で個別診断モジュールを動的ロード・実行
2. **120-128行目**: 診断無効化チェック（`vm.isDiagDisabledAt`）とマーク重複チェック
3. **131-133行目**: 結果にレベルとコードを付与してレスポンス

#### Step 3: 診断ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | undefined-global.lua | `script/core/diagnostics/undefined-global.lua` | 未定義グローバル検出のメインロジック |

**主要処理フロー**:
- **6-11行目**: requireLikeテーブルで類似関数名を定義
- **14-18行目**: ファイル状態の取得と存在チェック
- **21行目**: `guide.eachSourceType`でgetglobalノードを走査
- **22行目**: `vm.isUndefinedGlobal(src)`で未定義判定
- **25-26行目**: requireLike判定と追加メッセージ生成
- **29-34行目**: 診断結果をコールバック

#### Step 4: VM層の判定ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | vm.lua | `script/vm/vm.lua` | `isUndefinedGlobal`関数の実装箇所 |

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

```
script/core/diagnostics/init.lua (診断エントリー)
    │
    ├─ require('core.diagnostics.undefined-global')
    │      │
    │      ├─ files.getState(uri)
    │      │      └─ AST情報を取得
    │      │
    │      ├─ guide.eachSourceType(state.ast, 'getglobal', callback)
    │      │      └─ ASTを走査してgetglobalノードを抽出
    │      │
    │      └─ vm.isUndefinedGlobal(src)
    │             └─ グローバル変数が未定義かどうかを判定
    │
    └─ callback(result)
           └─ 診断結果をLSPクライアントへ送信
```

### データフロー図

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

Luaソースコード ───▶ パーサー(AST生成) ───▶ AST
                                              │
                                              ▼
                            guide.eachSourceType('getglobal')
                                              │
                                              ▼
                            vm.isUndefinedGlobal(src)
                                              │
                                              ▼
                            診断メッセージ生成 ───▶ LSP診断通知
                                              │
                                              ▼
                                        エディタ表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| undefined-global.lua | `script/core/diagnostics/undefined-global.lua` | ソース | 未定義グローバル診断のメインロジック |
| init.lua | `script/core/diagnostics/init.lua` | ソース | 診断処理のエントリーポイント |
| define.lua | `script/proto/define.lua` | ソース | 診断関連の定数定義 |
| vm.lua | `script/vm/vm.lua` | ソース | 未定義判定ロジック |
| guide.lua | `script/parser/guide.lua` | ソース | AST操作ユーティリティ |
| files.lua | `script/files.lua` | ソース | ファイル状態管理 |
| language.lua | `script/language.lua` | ソース | 多言語メッセージ定義 |
