CLang-Format 代码格式化工具

2022-10-12 10:50:55
## 简述 Clang-Format是基于 clang 的一个命令行工具,这个工具能够自动化格式C/C++/Obj-C代码,支持多种代码风格(Google, Chromium, LLVM, Mozilla, WebKit),同时也支持自定义风格(通过编写.clang-format文件)。 ## 安装方式 ``` # Ubuntu $ sudo apt install clang-format # CentOS $ yum install clang # macOS $ brew install clang-format # Windows 需要访问 LLVM 官网下载 Windows 安装包(Windows installer)。http://llvm.org/builds/ ``` ## 参数解析 官方文档的参数解析为:http://clang.llvm.org/docs/ClangFormatStyleOptions.html BasedOnStyle样式信息: * 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的样式; ``` clang-format --style=LLVM -dump-config > .clang-format ``` ``` --- # 语言 Language: Cpp # BasedOnStyle: LLVM #类的访问修饰关键字(private,public,protected···)缩进 # private: # int a; # 1表示不缩进 # 大于1的值表示访问修饰关键字的左侧从int a的左侧列开始往右侧移动的距离 AccessModifierOffset: -2 # 在未封闭(括号的开始和结束不在同一行)的括号中的代码是否对齐 # if(a &;&; #b) # AlignAfterOpenBracket: Align # 多行赋值语句按 = 号对齐 AlignConsecutiveAssignments: false # 多行声明语句按 = 号对齐 AlignConsecutiveDeclarations: false # (EscapedNewlineAlignmentStyle)用于在转义换行符中对齐反斜杠的选项,可能的值如下所示: AlignEscapedNewlines: Right + ENAS_DontAlign:在配置DontAlign中不要对齐转义的换行符; + ENAS_Left:在配置Left中尽可能向左对齐转义的换行符; + ENAS_Right:在配置Right中对齐最右列中的转义换行符 # (bool)是否水平对齐二进制和三元表达式的操作数 AlignOperands: true # 是否把注释右对齐,下面为右对齐的效果 #void someFunction() { #doWork(); // Does something #doMoreWork(); // Does something else #} AlignTrailingComments: true # (bool)是否允许将函数声明的所有参数放到下一行(BinPackParameters为false不影响该参数) AllowAllParametersOfDeclarationOnNextLine: true # 是否允许短代码块在一行写完 # 如 if (a) { return; } AllowShortBlocksOnASingleLine: false # 是否允许短switch的case 语句在一行写完 AllowShortCaseLabelsOnASingleLine: false # 是否允许短的函数在一行写完 AllowShortFunctionsOnASingleLine: All # 是否允许短的语句在一行写完 AllowShortIfStatementsOnASingleLine: false # 是否允许短的循环在一行写完,如果为真(true), 语句“while (true) continue;” 能被放到单行 AllowShortLoopsOnASingleLine: false # 用于函数定义返回类型换行样式,这个选项是过时的并且被保留向后兼容(可选值如下所示) AlwaysBreakAfterDefinitionReturnType: None + DRTBS_None (在配置中: None) 再返回类型后自动换行,PenaltyReturnTypeOnItsOwnLine 会被考虑到; + DRTBS_All (在配置中: All) 总是在返回类型后换行; + DRTBS_TopLevel (在配置中: TopLevel) 总是在返回类型的顶级函数后换行; # 用于函数声明返回类型换行样式(可选值如下所示) AlwaysBreakAfterReturnType: None + RTBS_None (在配置中: None) 在返回类型后自动换行。“PenaltyReturnTypeOnItsOwnLine”会被考虑. + RTBS_All (在配置中: All) 再返回类型后总是换行; + RTBS_TopLevel (在配置中: TopLevel) 在方法的顶层的返回类型后总是换行; + RTBS_AllDefinitions (在配置中: AllDefinitions) 在方法定义中的返回类型后总是换行; + RTBS_TopLevelDefinitions (在配置中: TopLevelDefinitions) 在顶层定义的返回类型后总是换行 # 使在文件中有多行字符串的情况看起来更一致。因此,如果字符串被“ContinuationIndentWidth”空格导致换行,它将会在行首生效。如果为真(true), 在多行字面量字符串前总是换行 AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: MultiLine # 如果为假(false), 函数调用的参数要么是在同一行上,要么将在同一行上有一行 BinPackArguments: true # 如果为假(false), 函数声明或函数定义的参数将都在同一行上,或各有一行 BinPackParameters: true # 控制单独的大括号换行事件,如果“BreakBeforeBraces”设置为“BS_Custom”, 使用这个指定如何处理每个单独的括号的情况。否则,这是被忽略的嵌套结构的标志 BraceWrapping: # 使类定义换行 AfterClass: false # 使控制语句(if/for/while/switch/..)换行 AfterControlStatement: false # 使枚举定义换行 AfterEnum: false # 使方法定义换行 AfterFunction: false # 使命名空间定义换行 AfterNamespace: false # 使OC定义(@autoreleasepool, interfaces, ..)换行 AfterObjCDeclaration: false # 使结构体定义换行 AfterStruct: false # 使共同体定义换行 AfterUnion: false AfterExternBlock: false # 在catch之前换行 BeforeCatch: false # 在else之前换行 BeforeElse: false # 缩进换行的大括号 IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true # 在二元运算符前断行 BreakBeforeBinaryOperators: None # 括号的断行模式 BreakBeforeBraces: Attach BreakBeforeInheritanceComma: false BreakInheritanceList: BeforeColon # 在三元运算符前断行 BreakBeforeTernaryOperators: true # 在构造函数初始化时按逗号断行,并以冒号对齐 BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeColon BreakAfterJavaFieldAnnotations: false # 当格式化时,总是对字面量字符串换行 BreakStringLiterals: true # 最大宽度,如果代码超过这个宽度会按语义折行 ColumnLimit: 80 # 一个固定的表达式,它描述了具有特殊意义的注释,不应该被分裂成行或以其他方式改变 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false # 如果构造函数初始化器不适合在一行,把每个初始化放到单独的行 ConstructorInitializerAllOnOneLineOrOnePerLine: false # 使用构造函数初始化列表缩进的字符数 ConstructorInitializerIndentWidth: 4 # 在续行(/下一行)时的缩进长度 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DerivePointerAlignment: false # 禁用当前format文件 DisableFormat: false # 如果为真(true), clang-format检测函数调用和定义格式化为每行一个参数。每个调用都可以被包装,每行一个或不确定的。如果是不确定的,例如完全在一行,但需要做出一个决定,clang-format分析文件中是否有其他被包装的事例和相应的行动。 # 注意:这是一个实验标志,可能会消失或被重命名。不要在配置文件中使用。你自己要为你的使用负责 ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true # 一个宏,应解释为foreach循环而不是作为函数调用矢量 ForEachMacros: - foreach - Q_FOREACH - BOOST_FOREACH IncludeBlocks: Preserve # 正则表达式表示不同的#include类别被用于#includes命令,这些正则表达式与一个包含(包括< >或“)的文件的文件名相匹配。属于第一匹配正则表达式的值被分配,并且#include首先根据增加类别数然后在每个类别按字母的顺序排序。如果正则表达式都不匹配,int_max分配类别。源文件的主要头引用自动获取类别0。因此,它通常是保持在#include开头(http://llvm.org/docs/CodingStandards.html#include-style)。然而,如果你有总是需要排在首位的头引用,你也可以分配负面的优先事项。为了在.clang-format文件中配置这个, 请使用 IncludeCategories: - Regex: '^"(llvm|llvm-c|clang|clang-c)/' Priority: 2 - Regex: '^(<|"(gtest|gmock|isl|json)/)' Priority: 3 - Regex: '.*' Priority: 1 # 指定一个常用的可以在文件主要包括映射的正则表达式的表达式,在猜测是否#include是“main”include(指定类别0,见上文),使用这个正则表达式允许后缀的头引用源。部分匹配完成,所以说:-“”意思是任意后缀,-“$”的意思是没有后缀,例如,如果配置”(_test)?$”,然后.h将被视为包括在a.cc和a_test.ccde中的“main”。 IncludeIsMainRegex: '(Test)?$' # case语句的位置总是在switch语句后缩进一级 IndentCaseLabels: false IndentPPDirectives: None # 用于缩进的列数 IndentWidth: 2 # 缩进如果函数定义或声明后包的类型 IndentWrappedFunctionNames: false # JavaScriptQuotes中可能的值如下所示 JavaScriptQuotes: Leave + JSQS_Leave (在配置中: Leave) 留下字符串原本的括号; + JSQS_Single (在配置中: Single) 总是使用单括号; + JSQS_Double (在配置中: Double) 总是使用双括号 JavaScriptWrapImports: true # 在block从空行开始 KeepEmptyLinesAtTheStartOfBlocks: true # block开始的正则 MacroBlockBegin: '' # block开始的正则 MacroBlockEnd: '' # 允许最大连续空行数 MaxEmptyLinesToKeep: 1 # 命名空间缩进 NamespaceIndentation: None ObjCBinPackProtocolList: Auto # block内的缩进 ObjCBlockIndentWidth: 2 # 是否需要在"@property"后加上空格 ObjCSpaceAfterProperty: false # 是否需要在协议名后加上空格 ObjCSpaceBeforeProtocolList: true PenaltyBreakAssignment: 2 # 在调用小括号“(”后给一个方法调用换行的处罚 PenaltyBreakBeforeFirstCallParameter: 19 # 包含在一个注释中的每一个换行的处罚 PenaltyBreakComment: 300 # 在第一个“<<”前的换行的处罚 PenaltyBreakFirstLessLess: 120 # 包含一个字面量的字符串中的每一个换行的处罚 PenaltyBreakString: 1000 PenaltyBreakTemplateDeclaration: 10 # 最多能超出ColumnLimit多少个字符 PenaltyExcessCharacter: 1000000 # 把一个方法返回类型放到函数的同一行 PenaltyReturnTypeOnItsOwnLine: 60 # 指针在类型那边还是在变量名那边还是在中间 PointerAlignment: Right # 如果为真(true), clang-format 将会尝试将注释重新流布局 ReflowComments: true # 如果为真(true), clang-format 将会分类#includes SortIncludes: true SortUsingDeclarations: true # 如果为真(true), 可能在一个C样式描述后插入一个空格 SpaceAfterCStyleCast: false # 如果为真(true), 在“template”关键字后插入一个空格 SpaceAfterTemplateKeyword: true # 如果为假(false),移除分配操作符(=)前空格 SpaceBeforeAssignmentOperators: true SpaceBeforeCpp11BracedList: false SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true # 是否在括号前加上空格 SpaceBeforeParens: ControlStatements SpaceBeforeRangeBasedForLoopColon: true # 是否在空括号中加空格 SpaceInEmptyParentheses: false # 单行注释前的空格数 SpacesBeforeTrailingComments: 1 # 是否在<>中间插入空格 SpacesInAngles: false # 是否在容器字面量(@[@"1",@"2"])中插入空格 SpacesInContainerLiterals: true # 如果为真(true), 将会在C样式描述中插入空格 SpacesInCStyleCastParentheses: false # 是否在非空的括号中插入空格 SpacesInParentheses: false # 如果为真(true),将会在“[”之后和“]”之前插入空格 SpacesInSquareBrackets: false # 用这个标准格式化:例如:在LS_Cpp03中使用 A<A<int> > 而不是 A<A<int>>(可能的值如下所示) + LS_Cpp03 (在配置中: Cpp03) 使用Use C++03统一语法; + LS_Cpp11 (在配置中: Cpp11) 使用C++11的特征(例如 A<A<int>>而不是A<A<int> >); + LS_Auto (在配置中: Auto) 基于输入自动检查; Standard: Cpp11 # tab的缩进空格数 TabWidth: 8 # 在结果文件中使用制表符字符的方式可能的值如下所示) UseTab: Never + UT_Never (在配置中: Never) 从不使用制表符; + UT_ForIndentation (在配置中: ForIndentation) 仅缩排时使用制表符; + UT_Always (在配置中: Always) 使用标签时,我们需要填补的空白,至少从一个制表位到下一个; ... ``` ## 使用示例 ``` clang-format [-参数] <输入文件> 参数说明: -style=LLVM|Google|Chromium|Mozilla|Webkit 设定风格;目前只支持这5种风格;默认是LLVM风格 -i 文件替换;如果指定了这个参数则直接替换源文件,否则将美化过的代码打印到标准输出 $ clang-format -i hello.cpp $ clang-format -style='{IndentWidth:4}' -i hello.cpp $ clang-format --style=Webkit -i hello.cpp ```