Post

CPP ClangFormat in Action

CPP ClangFormat in Action

格式化工具 ClangFormat

Clang 有着非常模块化的设计,容易被其他工具复用其代码分析功能。LLVM 团队自己也提供一些工具,其中包括ClangFormat

ClangFormat describes a set of tools that are built on top of LibFormat. It can support your workflow in a variety of ways including a standalone tool and editor integrations.

Standalone Tool

clang-format is located in clang/tools/clang-format and can be used to format C/C++/Obj-C code.

$ clang-format -help OVERVIEW: A tool to format C/C++/Obj-C code.

When the desired code formatting style is different from the available options, the style can be customized using the -style="{key: value, ...}" option or by putting your style configuration in the .clang-format or _clang-format file in your project’s directory and using clang-format -style=file.

An easy way to create the .clang-format file is:

clang-format -style=llvm -dump-config > .clang-format

Available style options are described in Clang-Format Style Options.

editor integrations

There is an integration for vim which lets you run the clang-format standalone tool on your current buffer, optionally selecting regions to reformat. The integration has the form of a python-file which can be found under clang/tools/clang-format/clang-format.py.

Download the latest Visual Studio plugin from the alpha build site. The default key-binding is Ctrl-R,Ctrl-F.

The python script clang/tools/clang-format-diff.py parses the output of a unified diff and reformats all contained lines with clang-format.

usage: clang-format-diff.py [-h] [-p P] [-style STYLE] Reformat changed lines in diff. optional arguments: -h, --help show this help message and exit -p P strip the smallest prefix containing P slashes -style STYLE formatting style to apply (LLVM, Google, Chromium, Mozilla, WebKit)

So to reformat all the lines in the latest git commit, just do:

git diff -U0 HEAD^ | clang-format-diff.py -p1

The -U0 will create a diff without context lines (the script would format those as well).

模版配置 .clang-format

The .clang-format file uses YAML format:

key1: value1 key2: value2 # A comment. ...

An example of a configuration file for multiple languages:

--- # We'll use defaults from the LLVM style, but with 4 columns indentation. BasedOnStyle: LLVM IndentWidth: 4 --- Language: Cpp # Force pointers to the type for C++. DerivePointerAlignment: false PointerAlignment: Left --- Language: JavaScript # Use 100 columns for JS. ColumnLimit: 100 --- Language: Proto # Don't format .proto files. DisableFormat: true ...

执行 clang-format -style=google -dump-config 命令的输出:

--- Language: Cpp # BasedOnStyle: Google AccessModifierOffset: -1 ConstructorInitializerIndentWidth: 4 AlignEscapedNewlinesLeft: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false AllowShortIfStatementsOnASingleLine: true AllowShortLoopsOnASingleLine: true AllowShortFunctionsOnASingleLine: All AlwaysBreakTemplateDeclarations: true AlwaysBreakBeforeMultilineStrings: true BreakBeforeBinaryOperators: false BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false BinPackParameters: true ColumnLimit: 80 ConstructorInitializerAllOnOneLineOrOnePerLine: true DerivePointerAlignment: true ExperimentalAutoDetectBinPacking: false IndentCaseLabels: true IndentWrappedFunctionNames: false IndentFunctionDeclarationAfterType: false MaxEmptyLinesToKeep: 1 KeepEmptyLinesAtTheStartOfBlocks: false NamespaceIndentation: None ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: false PenaltyBreakBeforeFirstCallParameter: 1 PenaltyBreakComment: 300 PenaltyBreakString: 1000 PenaltyBreakFirstLessLess: 120 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left SpacesBeforeTrailingComments: 2 Cpp11BracedListStyle: true Standard: Auto IndentWidth: 2 TabWidth: 8 UseTab: Never BreakBeforeBraces: Attach SpacesInParentheses: false SpacesInAngles: false SpaceInEmptyParentheses: false SpacesInCStyleCastParentheses: false SpacesInContainerLiterals: true SpaceBeforeAssignmentOperators: true ContinuationIndentWidth: 4 CommentPragmas: '^ IWYU pragma:' ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] SpaceBeforeParens: ControlStatements DisableFormat: false ...

业务实际使用的配置可以参考clang-format -style=google -dump-config的默认配置,并在其基础上修改或增加新的选项。

Disabling Formatting on a Piece of Code

Clang-format understands also special comments that switch formatting in a delimited range. The code between a comment // clang-format off or /* clang-format off */ up to a comment // clang-format on or /* clang-format on */ will not be formatted. The comments themselves will be formatted (aligned) normally.

int formatted_code; // clang-format off void unformatted_code ; // clang-format on void formatted_code_again;

Configurable Format Style Options

Language

Language, this format style is targeted at.

Possible values:

  • LK_None (in configuration: None) Do not use.
  • LK_Cpp (in configuration: Cpp) Should be used for C, C++, ObjectiveC, ObjectiveC++.
  • LK_Java (in configuration: Java) Should be used for Java.
  • LK_JavaScript (in configuration: JavaScript) Should be used for JavaScript.
  • LK_Proto (in configuration: Proto) Should be used for Protocol Buffers (https://developers.google.com/protocol-buffers/).

BasedOnStyle (代码风格)

The style used for all options not specifically set in the configuration.

This option is supported only in the clang-format configuration (both within -style='{...}' and the .clang-format file).

Possible values:

DisableFormat (启用开关)

Disables formatting completely.

AlignTrailingComments (对齐注释)

If true, aligns trailing comments.

BreakBeforeBraces (大括号换行规则)

The brace breaking style to use.

  • BS_Attach (in configuration: Attach) Always attach braces to surrounding context.
  • BS_Linux (in configuration: Linux) Like Attach, but break before braces on function, namespace and class definitions.
  • BS_Mozilla (in configuration: Mozilla) Like Attach, but break before braces on enum, function, and record definitions.
  • BS_Stroustrup (in configuration: Stroustrup) Like Attach, but break before function definitions, and ‘else’.
  • BS_Allman (in configuration: Allman) Always break before braces.
  • BS_GNU (in configuration: GNU) Always break before braces and add an extra level of indentation to braces of control statements, not to those of class, function or other definitions.

ColumnLimit (每行的字符个数限制)

The column limit.

A column limit of 0 means that there is no column limit. In this case, clang-format will respect the input’s line breaking decisions within statements unless they contradict other rules.

IndentWidth (缩进宽度)

The number of columns to use for indentation.

TabWidth

The number of columns used for tab stops.

UseTab (UseTabStyle)

The way to use tab characters in the resulting file.

Possible values:

  • UT_Never (in configuration: Never) Never use tab.
  • UT_ForIndentation (in configuration: ForIndentation) Use tabs only for indentation.
  • UT_Always (in configuration: Always) Use tabs whenever we need to fill whitespace that spans at least from one tab stop to the next one.

Q&A

Why do the PointerAlignment options not work?

通过 clang-format -style=google -dump-config 命令,可以看到 DerivePointerAlignment: true

The documentation says it

If true, analyze the formatted file for the most common alignment of & and *. Pointer and reference alignment styles are going to be updated according to the preferences found in the file. PointerAlignment is then used only as fallback.

Which means one must explicitly set DerivePointerAlignment: false if one wants to handle it by oneself.

Refer

  • Clang 3.4 documentation

  • clang doc ver 3: https://releases.llvm.org/3.4/tools/clang/docs/ClangFormatStyleOptions.html
  • clang doc ver 12: https://clang.llvm.org/docs/ClangFormatStyleOptions.html
This post is licensed under CC BY 4.0 by the author.
Share