Index: docs/ClangFormatStyleOptions.rst =================================================================== --- docs/ClangFormatStyleOptions.rst +++ docs/ClangFormatStyleOptions.rst @@ -256,6 +256,8 @@ Like ``Attach``, but break before function definitions, and 'else'. * ``BS_Allman`` (in configuration: ``Allman``) Always break before braces. + * ``BS_Whitesmiths`` (in configuration: ``Whitesmiths``) + Like ``Allman``, with the braces intended too. * ``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 Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -319,6 +319,8 @@ BS_Stroustrup, /// Always break before braces. BS_Allman, + /// Allman style with a level of indentation before the braces + BS_Whitesmiths, /// 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. Index: lib/Format/ContinuationIndenter.h =================================================================== --- lib/Format/ContinuationIndenter.h +++ lib/Format/ContinuationIndenter.h @@ -156,7 +156,8 @@ NestedNameSpecifierContinuation(0), CallContinuation(0), VariablePos(0), ContainsLineBreak(false), ContainsUnwrappedBuilder(0), AlignColons(true), ObjCSelectorNameFound(false), - HasMultipleNestedBlocks(false), NestedBlockInlined(false) {} + HasMultipleNestedBlocks(false), NestedBlockInlined(false), + BlockNoExtraIndent(false) {} /// \brief The position to which a specific parenthesis level needs to be /// indented. @@ -265,6 +266,9 @@ // "function" in JavaScript) is not wrapped to a new line. bool NestedBlockInlined; + // + bool BlockNoExtraIndent; + bool operator<(const ParenState &Other) const { if (Indent != Other.Indent) return Indent < Other.Indent; Index: lib/Format/ContinuationIndenter.cpp =================================================================== --- lib/Format/ContinuationIndenter.cpp +++ lib/Format/ContinuationIndenter.cpp @@ -513,9 +513,19 @@ return std::max(State.Stack.back().LastSpace, State.Stack.back().Indent + Style.ContinuationIndentWidth); - if (NextNonComment->is(tok::l_brace) && NextNonComment->BlockKind == BK_Block) + // Start of braced block + if (NextNonComment->is(tok::l_brace) && + NextNonComment->BlockKind == BK_Block) { + // Whitesmiths indents the { and } too, compared to Allman, + // this also needs to happen for the special parsed blocks. + if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) + return (Current.NestingLevel == 0 ? State.FirstIndent + : State.Stack.back().Indent) + + Style.IndentWidth; return Current.NestingLevel == 0 ? State.FirstIndent : State.Stack.back().Indent; + } + // End of braced block (or ]) if (Current.isOneOf(tok::r_brace, tok::r_square)) { if (Current.closesBlockTypeList(Style)) return State.Stack[State.Stack.size() - 2].NestedBlockIndent; @@ -589,6 +599,15 @@ // Ensure that we fall back to the continuation indent width instead of // just flushing continuations left. return State.Stack.back().Indent + Style.ContinuationIndentWidth; + + // Whitesmiths indents the { and } too, compared to Allman, + // this also needs to happen for the special parsed blocks. + // The content between the braces needs to no extra indent + if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) { + if (PreviousNonComment && PreviousNonComment->is(tok::l_brace) && + PreviousNonComment->BlockKind == BK_Block) + return State.Stack.back().Indent - Style.IndentWidth; + } return State.Stack.back().Indent; } Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -95,6 +95,7 @@ IO.enumCase(Value, "Linux", FormatStyle::BS_Linux); IO.enumCase(Value, "Stroustrup", FormatStyle::BS_Stroustrup); IO.enumCase(Value, "Allman", FormatStyle::BS_Allman); + IO.enumCase(Value, "Whitesmiths", FormatStyle::BS_Whitesmiths); IO.enumCase(Value, "GNU", FormatStyle::BS_GNU); } }; Index: lib/Format/TokenAnnotator.cpp =================================================================== --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -1888,6 +1888,7 @@ Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline); if (isAllmanBrace(Left) || isAllmanBrace(Right)) return Style.BreakBeforeBraces == FormatStyle::BS_Allman || + Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths || Style.BreakBeforeBraces == FormatStyle::BS_GNU; if (Style.Language == FormatStyle::LK_Proto && Left.isNot(tok::l_brace) && Right.is(TT_SelectorName)) Index: lib/Format/UnwrappedLineFormatter.cpp =================================================================== --- lib/Format/UnwrappedLineFormatter.cpp +++ lib/Format/UnwrappedLineFormatter.cpp @@ -135,6 +135,7 @@ if (Limit == 0) return 0; if ((Style.BreakBeforeBraces == FormatStyle::BS_Allman || + Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths || Style.BreakBeforeBraces == FormatStyle::BS_GNU) && (I[1]->First->is(tok::l_brace) && !Style.AllowShortBlocksOnASingleLine)) return 0; @@ -499,6 +500,13 @@ if (PreviousLine && PreviousLine->First->isAccessSpecifier()) Newlines = std::min(1u, Newlines); + if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) { + // Setting the indent level for Whitesmiths is implemented similar to + // Allman. e.g. Getting the indentation correct except for the { and } + // tokens. The correction of those tokens is done here. + if (RootToken.isOneOf(tok::l_brace, tok::r_brace)) + Indent += Style.IndentWidth; + } Whitespaces->replaceWhitespace(RootToken, Newlines, IndentLevel, Indent, Indent, InPPDirective && !RootToken.HasUnescapedNewline); Index: lib/Format/UnwrappedLineParser.cpp =================================================================== --- lib/Format/UnwrappedLineParser.cpp +++ lib/Format/UnwrappedLineParser.cpp @@ -156,7 +156,8 @@ CompoundStatementIndenter(UnwrappedLineParser *Parser, const FormatStyle &Style, unsigned &LineLevel) : LineLevel(LineLevel), OldLineLevel(LineLevel) { - if (Style.BreakBeforeBraces == FormatStyle::BS_Allman) { + if (Style.BreakBeforeBraces == FormatStyle::BS_Allman || + Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) { Parser->addUnwrappedLine(); } else if (Style.BreakBeforeBraces == FormatStyle::BS_GNU) { Parser->addUnwrappedLine(); @@ -441,6 +442,7 @@ case FormatStyle::BS_Linux: return InitialToken.isOneOf(tok::kw_namespace, tok::kw_class); case FormatStyle::BS_Allman: + case FormatStyle::BS_Whitesmiths: case FormatStyle::BS_GNU: return true; default: @@ -1115,6 +1117,7 @@ CompoundStatementIndenter Indenter(this, Style, Line->Level); parseBlock(/*MustBeDeclaration=*/false); if (Style.BreakBeforeBraces == FormatStyle::BS_Allman || + Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths || Style.BreakBeforeBraces == FormatStyle::BS_GNU) { addUnwrappedLine(); } else { @@ -1168,6 +1171,7 @@ CompoundStatementIndenter Indenter(this, Style, Line->Level); parseBlock(/*MustBeDeclaration=*/false); if (Style.BreakBeforeBraces == FormatStyle::BS_Allman || + Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths || Style.BreakBeforeBraces == FormatStyle::BS_GNU || Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup) { addUnwrappedLine(); @@ -1202,6 +1206,7 @@ CompoundStatementIndenter Indenter(this, Style, Line->Level); parseBlock(/*MustBeDeclaration=*/false); if (Style.BreakBeforeBraces == FormatStyle::BS_Allman || + Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths || Style.BreakBeforeBraces == FormatStyle::BS_GNU || Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup) { addUnwrappedLine(); @@ -1263,7 +1268,8 @@ if (FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); parseBlock(/*MustBeDeclaration=*/false); - if (Style.BreakBeforeBraces == FormatStyle::BS_GNU) + if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths || + Style.BreakBeforeBraces == FormatStyle::BS_GNU) addUnwrappedLine(); } else { addUnwrappedLine(); @@ -1293,6 +1299,7 @@ if (FormatTok->Tok.is(tok::kw_break)) { // "break;" after "}" on its own line only for BS_Allman and BS_GNU if (Style.BreakBeforeBraces == FormatStyle::BS_Allman || + Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths || Style.BreakBeforeBraces == FormatStyle::BS_GNU) { addUnwrappedLine(); } @@ -1545,6 +1552,7 @@ if (FormatTok->Tok.is(tok::l_brace)) { if (Style.BreakBeforeBraces == FormatStyle::BS_Allman || + Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths || Style.BreakBeforeBraces == FormatStyle::BS_GNU) addUnwrappedLine(); parseBlock(/*MustBeDeclaration=*/true); Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -2270,6 +2270,16 @@ " // something\n" "}", Style); + Style.BreakBeforeBraces = FormatStyle::BS_Whitesmiths; + verifyFormat("try\n" + " {\n" + " // something\n" + " }\n" + "catch (...)\n" + " {\n" + " // something\n" + " }", + Style); Style.BreakBeforeBraces = FormatStyle::BS_GNU; verifyFormat("try\n" " {\n" @@ -3672,6 +3682,7 @@ // they are not function-like. FormatStyle Style = getGoogleStyle(); Style.ColumnLimit = 47; + verifyFormat("void someLongFunction(\n" " int someLoooooooooooooongParameter) const {\n}", getLLVMStyleWithColumns(47)); @@ -3723,6 +3734,13 @@ "}", Style); + Style.BreakBeforeBraces = FormatStyle::BS_Whitesmiths; + verifyFormat("void someLongFunction(\n" + " int someLongParameter) const\n" + " {\n" + " }", + Style); + // Unless these are unknown annotations. verifyFormat("void SomeFunction(aaaaaaaaaa aaaaaaaaaaaaaaa,\n" " aaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n" @@ -8154,6 +8172,10 @@ LinuxBraceStyle); verifyFormat("enum X {\n" " Y = 0,\n" + "};\n", + LinuxBraceStyle); + verifyFormat("enum X {\n" + " Y = 0,\n" "}\n", LinuxBraceStyle); verifyFormat("struct S {\n" @@ -8320,6 +8342,11 @@ " Y = 0\n" "}\n", AllmanBraceStyle); + verifyFormat("enum X\n" + "{\n" + " Y = 0\n" + "};\n", + AllmanBraceStyle); verifyFormat("@interface BSApplicationController ()\n" "{\n" @@ -8418,6 +8445,230 @@ BreakBeforeBraceShortIfs); } +TEST_F(FormatTest, WhitesmithsBraceBreaking) { + FormatStyle WhitesmithsBraceStyle = getLLVMStyle(); + WhitesmithsBraceStyle.BreakBeforeBraces = FormatStyle::BS_Whitesmiths; + + verifyFormat("class A;\n" + "namespace B\n" + " {\n" + "class C;\n" + "// Comment\n" + "class D\n" + " {\n" + "public:\n" + " D();\n" + " ~D() {}\n" + "private:\n" + " enum E\n" + " {\n" + " F\n" + " }\n" + " };\n" + " }\n", + WhitesmithsBraceStyle); + + verifyFormat("namespace a\n" + " {\n" + "class A\n" + " {\n" + " void f()\n" + " {\n" + " if (true)\n" + " {\n" + " a();\n" + " b();\n" + " }\n" + " }\n" + " void g() { return; }\n" + " };\n" + "struct B\n" + " {\n" + " int x;\n" + " };\n" + " }", + WhitesmithsBraceStyle); + + verifyFormat("void f()\n" + " {\n" + " if (true)\n" + " {\n" + " a();\n" + " }\n" + " else if (false)\n" + " {\n" + " b();\n" + " }\n" + " else\n" + " {\n" + " c();\n" + " }\n" + " }\n", + WhitesmithsBraceStyle); + + verifyFormat("void f()\n" + " {\n" + " for (int i = 0; i < 10; ++i)\n" + " {\n" + " a();\n" + " }\n" + " while (false)\n" + " {\n" + " b();\n" + " }\n" + " do\n" + " {\n" + " c();\n" + " }\n" + " while (false)\n" + " }\n", + WhitesmithsBraceStyle); + + verifyFormat("void f(int a)\n" + " {\n" + " switch (a)\n" + " {\n" + " case 0:\n" + " break;\n" + " case 1:\n" + " {\n" + " break;\n" + " }\n" + " case 2:\n" + " {\n" + " }\n" + " break;\n" + " default:\n" + " break;\n" + " }\n" + " }\n", + WhitesmithsBraceStyle); + + verifyFormat("enum X\n" + " {\n" + " Y = 0,\n" + " }\n", + WhitesmithsBraceStyle); + verifyFormat("enum X\n" + " {\n" + " Y = 0\n" + " }\n", + WhitesmithsBraceStyle); + verifyFormat("enum X\n" + " {\n" + " Y = 0,\n" + " Z = 1\n" + " };\n", + WhitesmithsBraceStyle); + + verifyFormat("@interface BSApplicationController ()\n" + " {\n" + "@private\n" + " id _extraIvar;\n" + " }\n" + "@end\n", + WhitesmithsBraceStyle); + + verifyFormat("#ifdef _DEBUG\n" + "int foo(int i = 0)\n" + "#else\n" + "int foo(int i = 5)\n" + "#endif\n" + " {\n" + " return i;\n" + " }", + WhitesmithsBraceStyle); + + verifyFormat("void foo() {}\n" + "void bar()\n" + "#ifdef _DEBUG\n" + " {\n" + " foo();\n" + " }\n" + "#else\n" + " {\n" + " }\n" + "#endif", + WhitesmithsBraceStyle); + + verifyFormat("void foobar() { int i = 5; }\n" + "#ifdef _DEBUG\n" + "void bar() {}\n" + "#else\n" + "void bar() { foobar(); }\n" + "#endif", + WhitesmithsBraceStyle); + + // This shouldn't affect ObjC blocks.. + verifyFormat("[self doSomeThingWithACompletionHandler:^{\n" + " // ...\n" + " int i;\n" + "}];", + WhitesmithsBraceStyle); + verifyFormat("void (^block)(void) = ^{\n" + " // ...\n" + " int i;\n" + "};", + WhitesmithsBraceStyle); + // .. or dict literals. + verifyFormat("void f()\n" + " {\n" + " [object someMethod:@{ @\"a\" : @\"b\" }];\n" + " }", + WhitesmithsBraceStyle); + verifyFormat("int f()\n" + " { // comment\n" + " return 42;\n" + " }", + WhitesmithsBraceStyle); + + verifyFormat("void f(Attribute Attribute)\n" + " {\n" + " auto ItFind = std::find_if(randomcontainerlongname.cbegin(),\n" + " randomcontainerlongname.cend(),\n" + " [&Attribute](const Attribute &Element) -> bool\n" + " {\n" + " return true;\n" + " });\n" + " }", + WhitesmithsBraceStyle); + + WhitesmithsBraceStyle.ColumnLimit = 19; + verifyFormat("void f() { int i; }", WhitesmithsBraceStyle); + WhitesmithsBraceStyle.ColumnLimit = 18; + verifyFormat("void f()\n" + " {\n" + " int i;\n" + " }", + WhitesmithsBraceStyle); + WhitesmithsBraceStyle.ColumnLimit = 80; + + FormatStyle BreakBeforeBraceShortIfs = WhitesmithsBraceStyle; + BreakBeforeBraceShortIfs.AllowShortIfStatementsOnASingleLine = true; + BreakBeforeBraceShortIfs.AllowShortLoopsOnASingleLine = true; + verifyFormat("void f(bool b)\n" + " {\n" + " if (b)\n" + " {\n" + " return;\n" + " }\n" + " }\n", + BreakBeforeBraceShortIfs); + verifyFormat("void f(bool b)\n" + " {\n" + " if (b) return;\n" + " }\n", + BreakBeforeBraceShortIfs); + verifyFormat("void f(bool b)\n" + " {\n" + " while (b)\n" + " {\n" + " return;\n" + " }\n" + " }\n", + BreakBeforeBraceShortIfs); +} + TEST_F(FormatTest, GNUBraceBreaking) { FormatStyle GNUBraceStyle = getLLVMStyle(); GNUBraceStyle.BreakBeforeBraces = FormatStyle::BS_GNU; @@ -8502,6 +8753,11 @@ " Y = 0,\n" "}\n", GNUBraceStyle); + verifyFormat("enum X\n" + "{\n" + " Y = 0\n" + "};\n", + GNUBraceStyle); verifyFormat("@interface BSApplicationController ()\n" "{\n" @@ -8806,6 +9062,8 @@ FormatStyle::BS_Stroustrup); CHECK_PARSE("BreakBeforeBraces: Allman", BreakBeforeBraces, FormatStyle::BS_Allman); + CHECK_PARSE("BreakBeforeBraces: Whitesmiths", BreakBeforeBraces, + FormatStyle::BS_Whitesmiths); CHECK_PARSE("BreakBeforeBraces: GNU", BreakBeforeBraces, FormatStyle::BS_GNU); Style.NamespaceIndentation = FormatStyle::NI_All;