I use some of the code generation and refactoring tools in QtCreator. These save a lot of time, but they don’t format C++ code how I like it. For example they produce C++ code like this:
void MyClass::foo(int *x)
But I like my code formatted like this:
void MyClass::foo( int* x )
The differences may seem minor, but they are a source of significant irritation to me. I like my code how I like it, goddammit! And consistent formatting enhances readability. However re-formatting it by hand is time-consuming and tedious.
What I need is a tool that can enforce consistent formatting in the style that I like, or something close. I have tried to use automatic C++ formatting (pretty printing) tools in the past, but I couldn’t get them to produce a format that was close enough to what I wanted. But I have finally found the tool for the job. Clang-Format.
Clang-Format is part of the LLVM family of tools. It is a free, command-line tool that reformats C++, Objective-C or C according to the settings in a config file. As with many free tools, it isn’t terribly well documented. Some of the documentation on the web is out of date and some of it is incomplete. But I have managed to find out enough to configure it how I like it.
To run it you just need to place your options in a .clang-format file, make sure the clang-format executable is in the path and then run it:
clang-format.exe -i -style=file <C++ file>
Here are the settings I am currently using in my .clang-format file:
Language: Cpp AccessModifierOffset: -4 AlignAfterOpenBracket: false AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignEscapedNewlinesLeft: false AlignOperands: true AlignTrailingComments: false AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: Inline AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: false BinPackArguments: true BinPackParameters: true BraceWrapping: AfterClass: true AfterControlStatement: true AfterEnum: true AfterFunction: true AfterNamespace: true AfterObjCDeclaration: true AfterStruct: true AfterUnion: false BeforeCatch: true BeforeElse: true IndentBraces: false BreakBeforeBinaryOperators: None BreakBeforeBraces: Allman BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false ColumnLimit: 0 CommentPragmas: '^ IWYU pragma:' ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 0 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] IndentCaseLabels: true IndentWidth: 4 IndentWrappedFunctionNames: false KeepEmptyLinesAtTheStartOfBlocks: true MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 2 NamespaceIndentation: None PenaltyBreakBeforeFirstCallParameter: 100 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyExcessCharacter: 10000 PointerAlignment: Left ReflowComments: true SortIncludes: false SpaceAfterCStyleCast: false SpaceBeforeAssignmentOperators: true SpaceBeforeParens: ControlStatements SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: true SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: true SpacesInParentheses: true SpacesInSquareBrackets: true Standard: Cpp11 TabWidth: 4 UseTab: Never
It took me a few hours of fiddling with the settings to find the best combination. It would be really useful if someone could write a tool that would analyze your C++ code and create a .clang-format file for you. You would probably only want to do this once though, so I don’t think it has much potential as a commercial product.
There are only two things I couldn’t get quite right in the formatting:
- I couldn’t get it to add a blank line after public, protected and private declarations. I fixed this with a quick Perl hack (see below).
- I couldn’t get it to indent continuation lines how I would like (ideally indented 1 or 2 spaces from the first line). It is a small price to pay and I am just putting up with it for now.
Perhaps there are options to do these and I just didn’t find them.
Here is the Windows .bat script I used to format all the C++ files in a folder.
for %%f in (*.h *.cpp *.inl) do ( clang-format.exe -i -style=file %%f ) for %%f in (*.h) do ( clang-format.exe -i -style=file %%f perl -p -i.bak -e "s/public:/public:\n/g" %%f perl -p -i.bak -e "s/protected:/protected:\n/g" %%f perl -p -i.bak -e "s/private:/private:\n/g" %%f perl -p -i.bak -e "s/ Q_OBJECT/Q_OBJECT/g" %%f ) del *.bak del *.tmp
No doubt there is a more elegant way to do the Perl, but it works.
I now just run this batch periodically to keep my code beautiful and consistent.
Thanks Andy.
Do you take on any mentees?
Thanks, Hatim
Hatim, I am not involved in 1-to-1 mentoring. Not enough hours in the day!
Oh, my! Even with the long list of parameters you showed, there are still some missing.
I indent continuation lines one space, too.
I also do continuation lines with my parameters one per line. I did not see a parameter for that either.
And just to make it messy, I sometimes have continuation depend on other lines. (I think that multi-line report titles should have the same continuation regardless of length. When line commenting, I sometimes want several adjacent lines’ comments to be equally indented; I use this especially with parameters and variable declarations.)
The indenting war will never be over. Sigh!
>Oh, my! Even with the long list of parameters you showed, there are still some missing.
It was based on a config dump, so it should be complete. What am I missing?
>I also do continuation lines with my parameters one per line. I did not see a parameter for that either.
I think there is, bit I am not sure in what circumstances it applies – only to function declarations perhaps?
Anyway I have decided that I am prepared to put up with a less than my perfect formatting in return for consistency and automation.