はじめに
.clang-format
を長く使って育てていると、古くなってしまっている部分もあるかもしれません。最新版のテンプレートとの差分を確認して、自分が変更した点を取捨選択したい、ということはありませんか?
どのスタイルに近くて、どこを変更したかをあぶり出す、という作業を今回してみましたので記事に残しておきます。
clang-formatに付属のテンプレート
現在clang-format(version 14.0.6
)には、以下の7つのスタイルテンプレートが標準で付属しています。
-
LLVM
: LLVM coding standards -
Google
: Google’s C++ style guide -
Chromium
: Chromium’s style guide -
Mozilla
: Mozilla’s style guide -
WebKit
: WebKit’s style guide -
Microsoft
: Microsoft’s style guide -
GNU
: GNU coding standards
近いテンプレートをdiff行数で比較
自分のスタイルがどのテンプレートに近いか、次のようにコンフィグのdiff
行数を距離とすることで簡易的に得ることができます。
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こだわりポイント
- 私は、ほとんどの設定は
Mozilla
に従っています。 -
Mozilla
よりもコード行数を減らしたいため、次の3点を変更しています。- 括弧の位置
- メソッド呼び出し
- メソッド宣言・定義
- またエディタ(
Xcode
)の自動補正とコンフリクトしないように、インデント調整しています。
具体的な設定
私が利用している.clang-format (この行をクリック)
---
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
...
こだわり点ピックアップ
-
基本は
Mozilla
を利用★ -
インデント
-
エディタとの調整
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
スタイルを利用しています。BreakBeforeBraces: Linux # mozilla: Mozilla
すなわち、下記が
Mozilla
と比べて変更になっています。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
-
-
メソッド呼び出し
-
引数が長く、改行する場合でも、各行にそれぞれ入るだけ複数の引数を書くようにしています。
BinPackArguments: true # mozilla: false
-
-
メソッド宣言・定義
-
返り値型と関数名は1行に書く。
AlwaysBreakAfterDefinitionReturnType: None # mozilla: TopLevel AlwaysBreakAfterReturnType: None # mozilla: TopLevel
-
ただし関数名(+引数など)が長いなら、躊躇せず返り値型を切り離す。
PenaltyReturnTypeOnItsOwnLine: 0 # mozilla: 200
-
複数の親から継承しても、短いなら1行で継承を記述するようにする。
BreakInheritanceList: BeforeColon # mozilla: BeforeComma
-
同様にコンストラクタ初期化子も短いなら1行で。ただし初期化子が長い場合は、変数ごとに個別に改行する。
BreakConstructorInitializers: BeforeColon # mozilla: BeforeComma PackConstructorInitializers: NextLine # mozilla: BinPack
-
超短い関数の内容定義は、関数名と同じ行で1行で済ませる。
AllowShortFunctionsOnASingleLine: All # mozilla: Inline
-
-
その他
-
Namespaceを閉じるときのコメントは、常に正しくなるようにする。
FixNamespaceComments: true # mozilla: false
-
以上です。
補足
clang-formatのコンフィグの記述は、clang-formatがバージョンアップするとよく変化しているようです。下位互換を保っているようで気づくことは普通はありませんが、いつ切り捨てられるかわかりません。ときどきは新しい記述にアップデートした方が良さそうです。
この方法で新しい記述に変換できますのでときどき実行してみることをおすすめします。
cd ".clang-formatのある場所"
clang-format --dump-config --style=file > .clang-format
これで長く安心して使い続けられますね。