あなたの.clang-format、どのスタイルに近い？

# はじめに

`.clang-format`を長く使って育てていると、古くなってしまっている部分もあるかもしれません。最新版のテンプレートとの差分を確認して、自分が変更した点を取捨選択したい、ということはありませんか？

どのスタイルに近くて、どこを変更したかをあぶり出す、という作業を今回してみましたので記事に残しておきます。

# clang-formatに付属のテンプレート

現在clang-format(`version 14.0.6`)には、以下の7つのスタイルテンプレートが標準で付属しています。

- `LLVM`: [LLVM coding standards](https://llvm.org/docs/CodingStandards.html)
- `Google`: [Google’s C++ style guide](https://google.github.io/styleguide/cppguide.html)
- `Chromium`: [Chromium’s style guide](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/styleguide/styleguide.md)
- `Mozilla`: [Mozilla’s style guide](https://firefox-source-docs.mozilla.org/code-quality/coding-style/index.html)
- `WebKit`: [WebKit’s style guide](https://www.webkit.org/coding/coding-style.html)
- `Microsoft`: [Microsoft’s style guide](https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference)
- `GNU`: [GNU coding standards](https://www.gnu.org/prep/standards/standards.html)

# 近いテンプレートをdiff行数で比較

自分のスタイルがどのテンプレートに近いか、次のようにコンフィグの`diff`行数を距離とすることで簡易的に得ることができます。

```bash
clang-format --version

cd ".clang-formatのある場所"
mkdir tmp
clang-format --dump-config --style=file > tmp/clang-format.conf
for i in LLVM GNU Google Chromium Microsoft Mozilla WebKit; do
  clang-format --dump-config --style=$i > tmp/clang-format-$i.conf
  diff -uBb tmp/clang-format-$i.conf tmp/clang-format.conf > tmp/$i.diff
done
wc -l tmp/*.diff | sort -n
```

スクリプトでは、利用中の`clang-format`で`--dump-config --style=file`して得られた現バージョンでのコンフィグと、`--dump-config --style=***`して得られた現バージョンでの**コンフィグテンプレート**を比較しています。数字が小さいスタイルがあなたのスタイルに近いスタイルです。

私の場合、`Mozilla`に近いことがわかりました。

   ```
   clang-format version 14.0.6
    125 tmp/Mozilla.diff
    138 tmp/LLVM.diff
    143 tmp/Microsoft.diff
    161 tmp/WebKit.diff
    185 tmp/GNU.diff
    214 tmp/Chromium.diff
    223 tmp/Google.diff
   1189 total
   ```

以降、今回やってわかった私の`.clang-format`について紹介します。

# 私の.clang-formatこだわりポイント

1. 私は、ほとんどの設定は`Mozilla`に従っています。
2. `Mozilla`よりもコード行数を減らしたいため、次の3点を変更しています。
   - **括弧の位置**
   - メソッド**呼び出し**
   - メソッド**宣言・定義**
3. またエディタ(`Xcode`)の自動補正とコンフリクトしないように、インデント調整しています。

## 具体的な設定

<details><summary>私が利用している.clang-format (この行をクリック)</summary><div>

```yaml
---
Language:        Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveMacros: None
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignEscapedNewlines: Right
AlignOperands:   Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros:
  - __capability
BinPackArguments: true
BinPackParameters: false
BraceWrapping:
  AfterCaseLabel:  false
  AfterClass:      true
  AfterControlStatement: Never
  AfterEnum:       false
  AfterFunction:   true
  AfterNamespace:  true
  AfterObjCDeclaration: false
  AfterStruct:     false
  AfterUnion:      false
  AfterExternBlock: false
  BeforeCatch:     false
  BeforeElse:      false
  BeforeLambdaBody: false
  BeforeWhile:     false
  IndentBraces:    false
  SplitEmptyFunction: true
  SplitEmptyRecord: true
  SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: true
BreakBeforeBraces: Linux
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit:     85
CommentPragmas:  '^ IWYU pragma:'
QualifierAlignment: Leave
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat:   false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
PackConstructorInitializers: NextLine
BasedOnStyle:    ''
ConstructorInitializerAllOnOneLineOrOnePerLine: false
AllowAllConstructorInitializersOnNextLine: true
FixNamespaceComments: true
ForEachMacros:
  - foreach
  - Q_FOREACH
  - BOOST_FOREACH
IfMacros:
  - KJ_IF_MAYBE
IncludeBlocks:   Preserve
IncludeCategories:
  - Regex:           '^"(llvm|llvm-c|clang|clang-c)/'
    Priority:        2
    SortPriority:    0
    CaseSensitive:   false
  - Regex:           '^(<|"(gtest|gmock|isl|json)/)'
    Priority:        3
    SortPriority:    0
    CaseSensitive:   false
  - Regex:           '.*'
    Priority:        1
    SortPriority:    0
    CaseSensitive:   false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseLabels: true
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentRequires:  false
IndentWidth:     4
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
LambdaBodyIndentation: Signature
MacroBlockBegin: ''
MacroBlockEnd:   ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: false
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 0
PenaltyIndentedWhitespace: 0
PointerAlignment: Left
PPIndentWidth:   -1
ReferenceAlignment: Pointer
ReflowComments:  true
RemoveBracesLLVM: false
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes:    CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
  AfterControlStatements: true
  AfterForeachMacros: true
  AfterFunctionDefinitionName: false
  AfterFunctionDeclarationName: false
  AfterIfMacros:   true
  AfterOverloadedOperator: false
  BeforeNonEmptyParentheses: false
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles:  Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
  Minimum:         1
  Maximum:         -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard:        Latest
StatementAttributeLikeMacros:
  - Q_EMIT
StatementMacros:
  - Q_UNUSED
  - QT_REQUIRE_VERSION
TabWidth:        4
UseCRLF:         false
UseTab:          Always
WhitespaceSensitiveMacros:
  - STRINGIZE
  - PP_STRINGIZE
  - BOOST_PP_STRINGIZE
  - NS_SWIFT_NAME
  - CF_SWIFT_NAME
...

```

</div></details>

## こだわり点ピックアップ

- 基本は`Mozilla`を利用★

- **インデント**

  - エディタとの調整

    ```yaml
    IndentWidth:     4		# mozilla: 2
    TabWidth:        4		# mozilla: 8
    UseTab:          Always		# mozilla: Never
    ColumnLimit:     85		# mozilla: 80
    ConstructorInitializerIndentWidth: 4		# mozilla: 2
    ContinuationIndentWidth: 8		# mozilla: 2
    AccessModifierOffset: -4		# mozilla: -2
    ```

- **括弧の位置**

  - 括弧前後の改行は`Linux`スタイルを利用しています。

    ```yaml
    BreakBeforeBraces: Linux		# mozilla: Mozilla
    ```

    すなわち、下記が`Mozilla`と比べて変更になっています。

    ```yaml
    BraceWrapping:
      AfterEnum:       false		# mozilla: true
      AfterNamespace:  true		# mozilla: false
      AfterStruct:     false		# mozilla: true
      AfterUnion:      false		# mozilla: true
      AfterExternBlock: false		# mozilla: true
      SplitEmptyRecord: true		# mozilla: false
    ```

- **メソッド呼び出し**

  - 引数が長く、改行する場合でも、各行にそれぞれ入るだけ複数の引数を書くようにしています。

    ```yaml
    BinPackArguments: true		# mozilla: false
    ```

- **メソッド宣言・定義**

  - 返り値型と関数名は1行に書く。

    ```yaml
    AlwaysBreakAfterDefinitionReturnType: None		# mozilla: TopLevel
    AlwaysBreakAfterReturnType: None		# mozilla: TopLevel
    ```

  - ただし関数名(+引数など)が長いなら、躊躇せず返り値型を切り離す。

    ```yaml
    PenaltyReturnTypeOnItsOwnLine: 0		# mozilla: 200
    ```

  - 複数の親から継承しても、短いなら1行で継承を記述するようにする。

    ```yaml
    BreakInheritanceList: BeforeColon		# mozilla: BeforeComma
    ```

  - 同様にコンストラクタ初期化子も短いなら1行で。ただし初期化子が長い場合は、変数ごとに個別に改行する。

    ```yaml
    BreakConstructorInitializers: BeforeColon		# mozilla: BeforeComma
    PackConstructorInitializers: NextLine		# mozilla: BinPack
    ```

  - 超短い関数の内容定義は、関数名と同じ行で1行で済ませる。

    ```yaml
    AllowShortFunctionsOnASingleLine: All		# mozilla: Inline
    ```

- **その他**

  - Namespaceを閉じるときのコメントは、常に正しくなるようにする。

    ```yaml
    FixNamespaceComments: true		# mozilla: false
    ```



以上です。


# 補足

clang-formatのコンフィグの記述は、clang-formatがバージョンアップするとよく変化しているようです。下位互換を保っているようで気づくことは普通はありませんが、いつ切り捨てられるかわかりません。ときどきは新しい記述にアップデートした方が良さそうです。
この方法で新しい記述に変換できますのでときどき実行してみることをおすすめします。

```bash
cd ".clang-formatのある場所"
clang-format --dump-config --style=file > .clang-format
```

これで長く安心して使い続けられますね。