# 機能設計書 70-clang-format

## 概要

本ドキュメントは、clang-format ツールの機能設計について記載する。clang-formatは、C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C#コードの自動フォーマットツールである。

### 本機能の処理概要

clang-formatは、ソースコードをプロジェクトやチームのコーディングスタイルに合わせて自動的に整形するツールである。様々なプリセットスタイル（LLVM、Google、Chromiumなど）を提供し、.clang-formatファイルによるカスタマイズも可能。

**業務上の目的・背景**：一貫したコーディングスタイルを維持することは、コードの可読性とメンテナンス性の向上に重要である。clang-formatを使用することで、手動でのスタイル調整を不要にし、コードレビューでのスタイル議論を削減できる。

**機能の利用シーン**：
- ソースファイルの自動フォーマット
- エディタ/IDE統合によるリアルタイムフォーマット
- CI/CDパイプラインでのスタイルチェック
- #includeのソート
- 特定範囲のみのフォーマット

**主要な処理内容**：
1. ソースファイルの読み込みとスタイル適用
2. #includeのソート
3. コードの再フォーマット
4. インプレース編集または標準出力への出力
5. XML形式での置換情報出力

**関連システム・外部連携**：Clang Format ライブラリ

**権限による制御**：特になし（ファイルシステムへのアクセス権限のみ必要）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | CLIツール | 主機能 | コマンドラインインターフェースによる操作 |

## 機能種別

コードフォーマット / スタイル適用

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| 入力ファイル | string[] | No | フォーマット対象ファイル（省略時は標準入力） | - |
| -style | string | No | 使用するスタイル（デフォルト: file） | - |
| -fallback-style | string | No | .clang-format未発見時のフォールバック（デフォルト: LLVM） | - |
| -assume-filename | string | No | 標準入力時のファイル名（言語検出用） | - |
| -i | flag | No | インプレース編集 | - |
| -offset | uint[] | No | フォーマット範囲の開始バイト位置 | - |
| -length | uint[] | No | フォーマット範囲の長さ | - |
| -lines | range[] | No | フォーマット範囲の行（start:end形式） | - |
| -cursor | uint | No | カーソル位置（エディタ統合用） | - |
| -output-replacements-xml | flag | No | XML形式で置換情報を出力 | - |
| -dump-config | flag | No | 設定内容をダンプ | - |
| -sort-includes | flag | No | #includeをソート | - |
| -qualifier-alignment | string | No | 修飾子の配置（left/right） | - |
| -files | path | No | 処理対象ファイルリスト | - |
| -verbose | flag | No | 詳細出力 | - |
| -n / --dry-run | flag | No | 実際の変更を行わない | - |
| -Werror | flag | No | 警告をエラーとして扱う | - |
| -ferror-limit | uint | No | エラー上限数 | - |
| --fail-on-incomplete-format | flag | No | 不完全フォーマット時にエラー終了 | - |

### 入力データソース

- ソースファイル（C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C#/Verilog/TableGen）
- 標準入力
- .clang-formatファイル（スタイル設定）
- .clang-format-ignoreファイル（除外パターン）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| フォーマット済みコード | テキスト | 整形されたソースコード |
| 置換情報XML | XML | 変更箇所の詳細情報 |
| カーソル位置 | JSON | エディタ統合用のカーソル位置情報 |
| 設定ダンプ | YAML | スタイル設定の内容 |

### 出力先

- 標準出力（デフォルト）
- 元ファイル（-iオプション指定時）

## 処理フロー

### 処理シーケンス

```
1. コマンドライン引数解析
   └─ cl::ParseCommandLineOptions()

2. 設定ダンプモード
   └─ -dump-config時は設定を出力して終了

3. ファイルリスト展開
   └─ -filesオプションからファイル一覧を読み込み

4. 各ファイルの処理
   ├─ .clang-format-ignore チェック
   ├─ ファイル読み込み
   ├─ スタイル取得（getStyle()）
   ├─ 範囲計算（fillRanges()）
   ├─ #includeソート（sortIncludes()）
   ├─ コードフォーマット（reformat()）
   └─ 結果出力

5. 結果の出力
   ├─ -i: インプレース書き込み
   ├─ -output-replacements-xml: XML出力
   └─ デフォルト: 標準出力
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[引数解析]
    B --> C{-dump-config?}
    C -->|Yes| D[dumpConfig]
    D --> E[終了]
    C -->|No| F{-files指定?}
    F -->|Yes| G[ファイルリスト読み込み]
    F -->|No| H{ファイル指定?}
    G --> I[各ファイル処理]
    H -->|Yes| I
    H -->|No| J[標準入力処理]
    I --> K{.clang-format-ignore?}
    K -->|除外| I
    K -->|処理| L[format関数]
    J --> L
    L --> M[ファイル読み込み]
    M --> N[getStyle]
    N --> O[fillRanges]
    O --> P[sortIncludes]
    P --> Q[reformat]
    Q --> R{出力モード?}
    R -->|-i| S[インプレース書き込み]
    R -->|XML| T[XML出力]
    R -->|標準| U[標準出力]
    S --> V{次のファイル?}
    T --> V
    U --> V
    V -->|Yes| I
    V -->|No| E
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-70-1 | 標準入力とインプレース排他 | -iは標準入力と併用不可 | 常時 |
| BR-70-2 | 範囲指定と複数ファイル排他 | -offset/-length/-linesは単一ファイルのみ | 常時 |
| BR-70-3 | スタイル検索 | style=fileは.clang-formatを上位ディレクトリから検索 | style=file時 |
| BR-70-4 | 言語自動検出 | ファイル拡張子から言語を自動検出 | 常時 |
| BR-70-5 | ignoreファイル | .clang-format-ignoreで除外パターンを指定可能 | 常時 |
| BR-70-6 | 空ファイル | 空ファイルは処理をスキップ | 常時 |

### 計算ロジック

- 範囲計算: -offset/-lengthまたは-linesからバイト範囲を計算
- カーソル位置: フォーマット後の新しいカーソル位置を計算

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

該当なし（データベースを使用しない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 1 | ファイル読み込みエラー | 入力ファイルが読み込めない | エラーメッセージを表示し終了 |
| 1 | スタイル取得エラー | .clang-formatが無効 | エラーメッセージを表示し終了 |
| 1 | BOMエラー | 非対応のBOM検出 | エラーメッセージを表示し終了 |
| 1 | 範囲エラー | -offset/-lengthの組み合わせが不正 | エラーメッセージを表示し終了 |
| 1 | 不完全フォーマット | フォーマットが完了しなかった | --fail-on-incomplete-format時にエラー |

### リトライ仕様

なし

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

該当なし

## パフォーマンス要件

特に定義なし

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

- 入力ファイルへの読み取りアクセス権限が必要
- -i使用時は入力ファイルへの書き込みアクセス権限が必要

## 備考

- 多数のエディタ/IDEとの統合プラグインが存在
- .clang-formatファイルはYAML形式
- JSONファイルのフォーマットもサポート（JavaScript変換技術を使用）

---

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

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

### 推奨読解順序

#### Step 1: コマンドラインオプションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ClangFormat.cpp | `clang/tools/clang-format/ClangFormat.cpp` | オプション定義（33-215行目） |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ClangFormat.cpp | `clang/tools/clang-format/ClangFormat.cpp` | main関数（668-734行目） |

**主要処理フロー**:
1. **669行目**: InitLLVM初期化
2. **674行目**: ParseCommandLineOptions()で引数解析
3. **689-690行目**: -dump-config時はdumpConfig()
4. **692-701行目**: -filesからファイルリスト読み込み
5. **703-706行目**: ファイル未指定時は標準入力
6. **718-731行目**: 各ファイルのformat()呼び出し

#### Step 3: フォーマット処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ClangFormat.cpp | `clang/tools/clang-format/ClangFormat.cpp` | format関数（404-543行目） |

**主要処理フロー**:
- **412-419行目**: ファイル読み込み
- **437-439行目**: fillRanges()で範囲計算
- **446-452行目**: getStyle()でスタイル取得
- **481-482行目**: sortIncludes()でインクルードソート
- **503-504行目**: reformat()でフォーマット
- **506-509行目**: ドライラン時の処理
- **510-541行目**: 出力処理

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

```
main()
    │
    ├─ cl::ParseCommandLineOptions()
    │
    ├─ [-dump-config]
    │      └─ dumpConfig()
    │             ├─ getStyle()
    │             └─ configurationAsText()
    │
    └─ [フォーマット処理]
           │
           ├─ isIgnored() [.clang-format-ignore チェック]
           │
           └─ format()
                  │
                  ├─ MemoryBuffer::getFileOrSTDIN()
                  │
                  ├─ fillRanges()
                  │      └─ parseLineRange() [-lines時]
                  │
                  ├─ getStyle()
                  │
                  ├─ sortIncludes()
                  │
                  ├─ applyAllReplacements()
                  │
                  ├─ reformat()
                  │
                  └─ 出力処理
                         ├─ [-i] Rewrite.overwriteChangedFiles()
                         ├─ [-output-replacements-xml] outputXML()
                         └─ [else] write(outs())
```

### データフロー図

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

ソースファイル
       │
       ▼
MemoryBuffer::getFileOrSTDIN()
       │
       ▼
fillRanges() ─────────▶ tooling::Range[]
       │
       ▼
getStyle() ───────────▶ FormatStyle
       │
       ▼
sortIncludes() ───────▶ Replacements (include sort)
       │
       ▼
applyAllReplacements()
       │
       ▼
reformat() ───────────▶ Replacements (format)
       │
       ▼
Replacements.merge()
       │
       ▼
┌──────┴──────────────────────────┐
│                                  │
▼                                  ▼
[-i]                        [標準出力/XML]
│                                  │
▼                                  ▼
Rewrite.overwriteChangedFiles()   write(outs())
│                                  │
▼                                  ▼
元ファイル更新                    標準出力/XMLファイル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ClangFormat.cpp | `clang/tools/clang-format/ClangFormat.cpp` | ソース | メインプログラム |
| MatchFilePath.h | `clang/lib/Format/MatchFilePath.h` | ヘッダ | ignoreパターンマッチング |
| CMakeLists.txt | `clang/tools/clang-format/CMakeLists.txt` | ビルド | ビルド設定 |
