# 機能設計書 26-コードアクション (textDocument/codeAction)

## 概要

本ドキュメントは、serve-d LSPサーバーにおけるコードアクション機能（textDocument/codeAction）の設計を記述する。インターフェース実装・インポート追加・未定義識別子の修正提案・DScannerクイックフィックス等の多様なコードアクションを提供する機能である。

### 本機能の処理概要

**業務上の目的・背景**：コーディング中に発生する定型的な修正作業（インポート追加、インターフェース実装、構文エラー修正等）を自動化することで、開発効率を向上させる。エディタの「クイックフィックス」や「ソースアクション」メニューに表示されるアクションを提供する。

**機能の利用シーン**：開発者がエディタ上で電球アイコン（コードアクション）を表示させた際、または診断メッセージ上でクイックフィックスを実行した際に呼び出される。カーソル位置や診断情報に応じた適切なアクション候補を返す。

**主要な処理内容**：
1. インターフェース/抽象クラスの自動実装アクション（DCDExtComponentを使用）
2. インポートのソート（Organize Imports）アクション（ImporterComponentを使用）
3. DUBビルド診断に基づく修正提案（未定義識別子の自動インポート、コード置換）
4. DScanner診断に基づくクイックフィックス（自動修正、警告の抑制）
5. 構文診断に基づくクイックフィックス（foreachのauto除去等）
6. codeAction/resolveによる遅延解決（sortImports, implementMethods）

**関連システム・外部連携**：DCDExtComponent、ImporterComponent、IndexComponent、DscannerComponent、DfmtComponent

**権限による制御**：コードアクションのフィルタリングはparams.context.onlyで指定されたCodeActionKindにより制御される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 19 | コードアクション（textDocument/codeAction） | 主画面 | インターフェース実装・インポート追加・未定義識別子修正等のコードアクションを提供する |
| 19 | コードアクション（textDocument/codeAction） | 補助機能 | DScannerの診断結果に基づくクイックフィックスアクションを提供する |
| 19 | コードアクション（textDocument/codeAction） | 補助機能 | DUBビルドのエラー診断に基づくインポート追加アクションを提供する |

## 機能種別

リファクタリング / クイックフィックス（複合アクション提供）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| textDocument.uri | DocumentUri | Yes | 対象ドキュメントのURI | 有効なドキュメントURIであること |
| range | TextRange | Yes | コードアクション対象の範囲 | - |
| context.diagnostics | Diagnostic[] | Yes | 現在の診断情報 | - |
| context.only | CodeActionKind[] | No | フィルタするアクション種別 | - |

### 入力データソース

- LSPクライアントからのtextDocument/codeActionリクエストのCodeActionParams
- 診断プロバイダ（DScanner, DUB, dfmt）からの診断情報

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| title | string | アクションの表示名 |
| kind | CodeActionKind | アクション種別（quickfix, refactor, sourceOrganizeImports等） |
| edit | WorkspaceEdit | テキスト編集（直接適用可能な場合） |
| command | Command | エディタコマンド（code-d.addImport, code-d.sortImports等） |
| isPreferred | bool | 推奨アクションフラグ |
| diagnostics | Diagnostic[] | 関連する診断情報 |
| data | JsonValue | 遅延解決用データ（id, uri等） |

### 出力先

LSPクライアント（JSON-RPCレスポンスとして返却）

## 処理フロー

### 処理シーケンス

```
1. textDocument/codeActionリクエスト受信
   └─ CodeActionParamsからURI・範囲・診断・フィルタを取得
2. ドキュメントと設定の取得
   └─ documents[uri], workspace(uri).config
3. DCDExtComponentのインターフェース実装チェック
   └─ カーソル位置が `:` の後ろにある場合、implementAllで実装可能性を確認
   └─ スニペットモード or refactorモードでアクション追加
4. ImporterComponentのインポートソート
   └─ findImportCodeSlicesでインポートブロック検出
   └─ sourceOrganizeImportsアクション追加
5. DUB診断の処理 (addDubDiagnostics)
   └─ IndexComponent使用時: 未定義識別子からの自動インポート候補
   └─ IndexComponent未使用時: 正規表現でインポート文抽出
   └─ `==`/`!=` → `is`/`!is` 置換提案
   └─ "perhaps change" メッセージからのコード置換
6. DScanner診断の処理 (addDScannerDiagnostics)
   └─ インポートソート修正
   └─ autofixの適用（即時コード置換またはresolveContext経由）
   └─ 警告の抑制（行単位/ファイル単位）
7. 構文診断の処理 (addSyntaxDiagnostics)
   └─ foreach-autoの修正
8. 結果返却
```

### フローチャート

```mermaid
flowchart TD
    A[codeAction リクエスト受信] --> B[ドキュメント・設定取得]
    B --> C{D言語 and インスタンス存在?}
    C -->|No| D[空配列返却]
    C -->|Yes| E[DCDExtチェック - インターフェース実装]
    E --> F[Importerチェック - インポートソート]
    F --> G[addDubDiagnostics]
    G --> H{診断ループ}
    H --> I{DScanner診断?}
    I -->|Yes| J[addDScannerDiagnostics]
    I -->|No| K{構文診断?}
    K -->|Yes| L[addSyntaxDiagnostics]
    K -->|No| M[次の診断へ]
    J --> M
    L --> M
    M --> H
    H --> N[CodeAction配列返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-26-01 | 言語チェック | D言語ファイルでない場合は空配列を返す | 処理開始時（48行目） |
| BR-26-02 | KindフィルタZing | context.onlyが指定されている場合、該当するKindのアクションのみ返す | 各アクション追加時 |
| BR-26-03 | インターフェース検出 | カーソル位置から逆方向にスキャンし、`:` を見つけた場合にインターフェース実装を提案 | DCDExtComponent存在時（69-107行目） |
| BR-26-04 | スニペットモード | implementInterfaceSnippetsフラグによりCommandベースとrefactorベースを切り替え | インターフェース実装アクション |
| BR-26-05 | 未定義識別子解決 | undefinedIdentifier, undefinedTemplate, noPropertyの正規表現パターンで未定義識別子を検出 | DUB診断処理 |
| BR-26-06 | 自動インポート候補 | IndexComponentから未定義識別子に一致するモジュールを検索し、インポート追加アクションとして提案 | IndexComponent存在時 |
| BR-26-07 | DScanner自動修正 | diagnostic.dataのautofixesフィールドからコード置換情報を抽出 | DScanner診断時 |
| BR-26-08 | 警告抑制 | DScannerの警告キーに基づき、行単位/ファイル単位の抑制アクションを提供 | DScanner診断時 |
| BR-26-09 | DCD遅延ロード | コードアクション要求があったファイルでDCDComponentを遅延ロードする | DCDComponent存在時（53-54行目） |

### 計算ロジック

未定義識別子の検出には以下の正規表現パターンを使用する：
- `undefinedIdentifier`: `^undefined identifier (\w+)(?:, did you mean .*? (\w+)\?)?$`
- `undefinedTemplate`: `template (\w+) is not defined`
- `noProperty`: `^no property (\w+)(?: for type .*?)?$`

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 空結果 | D言語ファイルでない場合 | 空配列を返却 |
| - | 空結果 | バックエンドインスタンスが存在しない場合 | 空配列を返却 |
| - | 警告ログ | 未対応のDScanner autofixが検出された場合 | warning()でログ出力、スキップ |
| - | 警告ログ | 未対応の構文診断が検出された場合 | warning()でログ出力 |

### リトライ仕様

リトライは不要。

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

トランザクションは使用しない（読み取り専用操作。テキスト編集はクライアント側で適用される）。

## パフォーマンス要件

- DCDExtComponent.implementAllはgetYieldで非同期待機する
- DscannerComponent.resolveAutoFixesはgetYieldで非同期待機する
- コードアクションはユーザーインタラクションの一部として呼ばれるため、低レイテンシが求められる

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

特になし。

## 備考

- provideCodeActionsは複数のサブ関数（addDubDiagnostics, addDScannerDiagnostics, addSyntaxDiagnostics）に処理を委譲する大規模な関数である
- codeAction/resolve（resolveCodeAction関数、154-189行目）はsortImportsとimplementMethodsの遅延解決に対応する
- served/sortImports（sortImports関数、538-566行目）とserved/implementMethods（implementMethods関数、572-655行目）は独立したプロトコルメソッドとしても呼び出し可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | code_actions.d | `source/served/commands/code_actions.d` | 正規表現パターンの定義（30-41行目）: importRegex, undefinedIdentifier, undefinedTemplate, noProperty, moduleRegex |
| 1-2 | types.d | `source/served/types.d` | CodeAction, CodeActionKind, WorkspaceEdit, Command等の型定義 |

**読解のコツ**: D言語の`package auto`（30行目等）はモジュールスコープの正規表現変数をコンパイル時に初期化する。code_lens.dからも参照される（importRegexがpackageスコープ）。

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

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

**主要処理フロー**:
1. **46-49行目**: ドキュメント取得、言語チェック、インスタンス取得
2. **53-54行目**: DCDComponentの遅延ロード
3. **61-66行目**: wantsKindヘルパー関数でCodeActionKindフィルタ
4. **69-107行目**: DCDExtによるインターフェース実装チェック
5. **110-137行目**: ImporterComponentによるインポートソート
6. **139行目**: addDubDiagnostics呼び出し
7. **140-151行目**: 診断ループでDScanner/構文診断の処理

#### Step 3: DUB診断処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | code_actions.d | `source/served/commands/code_actions.d` | addDubDiagnostics関数（191-341行目）で未定義識別子の解決とコード置換提案を行う |

**主要処理フロー**:
- **196-266行目**: IndexComponent使用時の自動インポート候補生成
- **268-281行目**: IndexComponent未使用時のフォールバック（正規表現ベース）
- **283-341行目**: autofixFromError関数による `==`/`!=` → `is`/`!is` 置換と "perhaps change" 提案

#### Step 4: DScanner診断処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | code_actions.d | `source/served/commands/code_actions.d` | addDScannerDiagnostics関数（389-497行目）でDScanner自動修正と警告抑制を処理する |

**主要処理フロー**:
- **414-418行目**: インポートソート修正アクション
- **420-484行目**: autofixesの解析（即時置換またはresolveContext経由）
- **487-496行目**: 警告抑制アクション（行単位/ファイル単位）

#### Step 5: codeAction/resolveを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | code_actions.d | `source/served/commands/code_actions.d` | resolveCodeAction関数（154-189行目）でsortImportsとimplementMethodsの遅延解決 |

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

```
provideCodeActions (code_actions.d:44)
    |
    +-- DCDExtComponent.implementAll (インターフェース実装チェック)
    |
    +-- ImporterComponent.findImportCodeSlices (インポートブロック検出)
    |
    +-- addDubDiagnostics (code_actions.d:191)
    |       |
    |       +-- provideAutoImports (complete.d) [自動インポート候補]
    |       +-- autofixFromError (code_actions.d:283) [==→is等の置換]
    |       +-- createCodeReplacementSuggestion (code_actions.d:343) [コード置換]
    |
    +-- addDScannerDiagnostics (code_actions.d:389)
    |       |
    |       +-- diagnosticDataToCodeReplacement (dscanner.d)
    |       +-- diagnosticDataToResolveContext (dscanner.d)
    |       +-- DscannerComponent.resolveAutoFixes
    |
    +-- addSyntaxDiagnostics (code_actions.d:499)

resolveCodeAction (code_actions.d:155)
    |
    +-- sortImports (code_actions.d:539)
    +-- implementMethods (code_actions.d:573)
```

### データフロー図

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

CodeActionParams -----------> provideCodeActions ----------------> CodeAction[]
  (uri, range, diagnostics,         |
   context.only)                    v
                            +-- インターフェース実装チェック (DCDExt)
                            +-- インポートソートチェック (Importer)
                            +-- DUB診断処理 (Index + 正規表現)
                            +-- DScanner診断処理 (autofix)
                            +-- 構文診断処理
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| code_actions.d | `source/served/commands/code_actions.d` | ソース | コードアクションのメイン実装（provideCodeActions, resolveCodeAction, sortImports, implementMethods等） |
| format.d | `source/served/commands/format.d` | ソース | generateDfmtArgs関数の提供（インポート: 13行目） |
| dscanner.d (linters) | `source/served/linters/dscanner.d` | ソース | DScannerDiagnosticSource定数、diagnosticDataToCodeReplacement/ResolveContext関数 |
| dub.d (linters) | `source/served/linters/dub.d` | ソース | DubDiagnosticSource定数 |
| complete.d | `source/served/commands/complete.d` | ソース | provideAutoImports関数の提供 |
| types.d | `source/served/types.d` | ソース | LSP型定義 |
| dcdext.d (workspaced) | `workspace-d/source/workspaced/com/dcdext.d` | ソース | DCDExtComponent.implementAll/getInterfaceDetails |
| importer.d (workspaced) | `workspace-d/source/workspaced/com/importer.d` | ソース | ImporterComponent.findImportCodeSlices/sortImportBlock |
| index.d (workspaced) | `workspace-d/source/workspaced/com/index.d` | ソース | IndexComponent |
