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.cpp =================================================================== --- lib/Format/ContinuationIndenter.cpp +++ lib/Format/ContinuationIndenter.cpp @@ -588,6 +588,11 @@ // Ensure that we fall back to the continuation indent width instead of // just flushing continuations left. return State.Stack.back().Indent + Style.ContinuationIndentWidth; + + // Whitesmiths has already indented the braces, so we don't want the extra + // indent. + if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) + 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 @@ -1876,6 +1876,7 @@ Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline); } else if (isAllmanBrace(Left) || isAllmanBrace(Right)) { return Style.BreakBeforeBraces == FormatStyle::BS_Allman || + Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths || Style.BreakBeforeBraces == FormatStyle::BS_GNU; } else 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; Index: lib/Format/UnwrappedLineParser.cpp =================================================================== --- lib/Format/UnwrappedLineParser.cpp +++ lib/Format/UnwrappedLineParser.cpp @@ -32,6 +32,25 @@ namespace { +/** +Simple guard which promises that the Level will be reset to its original value +when this goes out of scope. +*/ +class LevelGuard { +public: + LevelGuard(unsigned &Level) + : Level(Level) + , OldLevel(Level) { + } + ~LevelGuard() { + Level = OldLevel; + } + +private: + unsigned &Level; ///< Ref to orignal level + unsigned OldLevel; ///< The old value +}; + class ScopedDeclarationState { public: ScopedDeclarationState(UnwrappedLine &Line, std::vector &Stack, @@ -155,19 +174,28 @@ public: CompoundStatementIndenter(UnwrappedLineParser *Parser, const FormatStyle &Style, unsigned &LineLevel) - : LineLevel(LineLevel), OldLineLevel(LineLevel) { + : LineLevel(LineLevel), OldLineLevel(LineLevel) + , IndentAfterwardsNeeded(true) { if (Style.BreakBeforeBraces == FormatStyle::BS_Allman) { Parser->addUnwrappedLine(); + } else if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) { + Parser->addUnwrappedLine(); + ++LineLevel; + IndentAfterwardsNeeded = false; } else if (Style.BreakBeforeBraces == FormatStyle::BS_GNU) { Parser->addUnwrappedLine(); ++LineLevel; } } + + bool mustIndentAfterwards() const { return IndentAfterwardsNeeded; } + ~CompoundStatementIndenter() { LineLevel = OldLineLevel; } private: unsigned &LineLevel; unsigned OldLineLevel; + bool IndentAfterwardsNeeded; }; namespace { @@ -441,6 +469,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: @@ -794,7 +823,14 @@ if (Style.BreakBeforeBraces != FormatStyle::BS_Attach) addUnwrappedLine(); FormatTok->Type = TT_FunctionLBrace; - parseBlock(/*MustBeDeclaration=*/false); + + bool isWhitesmiths = + Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths; + + LevelGuard Guard(Line->Level); + if (isWhitesmiths) + ++Line->Level; + parseBlock(/*MustBeDeclaration=*/false, /*AddLevel=*/!isWhitesmiths); addUnwrappedLine(); return; } @@ -980,6 +1016,7 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) { bool HasError = false; + // Eat the l_brace nextToken(); // FIXME: Once we have an expression parser in the UnwrappedLineParser, @@ -1112,8 +1149,9 @@ bool NeedsUnwrappedLine = false; if (FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(/*MustBeDeclaration=*/false, Indenter.mustIndentAfterwards()); if (Style.BreakBeforeBraces == FormatStyle::BS_Allman || + Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths || Style.BreakBeforeBraces == FormatStyle::BS_GNU) { addUnwrappedLine(); } else { @@ -1131,7 +1169,7 @@ nextToken(); if (FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(/*MustBeDeclaration=*/false, Indenter.mustIndentAfterwards()); addUnwrappedLine(); } else if (FormatTok->Tok.is(tok::kw_if)) { parseIfThenElse(); @@ -1165,8 +1203,9 @@ } if (FormatTok->is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(/*MustBeDeclaration=*/false, Indenter.mustIndentAfterwards()); if (Style.BreakBeforeBraces == FormatStyle::BS_Allman || + Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths || Style.BreakBeforeBraces == FormatStyle::BS_GNU || Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup) { addUnwrappedLine(); @@ -1199,8 +1238,9 @@ } NeedsUnwrappedLine = false; CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(/*MustBeDeclaration=*/false, Indenter.mustIndentAfterwards()); if (Style.BreakBeforeBraces == FormatStyle::BS_Allman || + Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths || Style.BreakBeforeBraces == FormatStyle::BS_GNU || Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup) { addUnwrappedLine(); @@ -1216,13 +1256,17 @@ void UnwrappedLineParser::parseNamespace() { assert(FormatTok->Tok.is(tok::kw_namespace) && "'namespace' expected"); + LevelGuard Guard(Line->Level); const FormatToken &InitialToken = *FormatTok; nextToken(); if (FormatTok->Tok.is(tok::identifier)) nextToken(); if (FormatTok->Tok.is(tok::l_brace)) { - if (ShouldBreakBeforeBrace(Style, InitialToken)) + if (ShouldBreakBeforeBrace(Style, InitialToken)) { addUnwrappedLine(); + if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) + ++Line->Level; + } bool AddLevel = Style.NamespaceIndentation == FormatStyle::NI_All || (Style.NamespaceIndentation == FormatStyle::NI_Inner && @@ -1246,7 +1290,7 @@ parseParens(); if (FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(/*MustBeDeclaration=*/false, Indenter.mustIndentAfterwards()); addUnwrappedLine(); } else { addUnwrappedLine(); @@ -1261,8 +1305,10 @@ nextToken(); if (FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(/*MustBeDeclaration=*/false); - if (Style.BreakBeforeBraces == FormatStyle::BS_GNU) + parseBlock(/*MustBeDeclaration=*/false, Indenter.mustIndentAfterwards()); + + if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths || + Style.BreakBeforeBraces == FormatStyle::BS_GNU) addUnwrappedLine(); } else { addUnwrappedLine(); @@ -1288,10 +1334,12 @@ --Line->Level; if (CommentsBeforeNextToken.empty() && FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(/*MustBeDeclaration=*/false, Indenter.mustIndentAfterwards()); if (FormatTok->Tok.is(tok::kw_break)) { - // "break;" after "}" on its own line only for BS_Allman and BS_GNU + // "break;" after "}" on its own line only for BS_Allman, + // BS_Whitesmiths and BS_GNU if (Style.BreakBeforeBraces == FormatStyle::BS_Allman || + Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths || Style.BreakBeforeBraces == FormatStyle::BS_GNU) { addUnwrappedLine(); } @@ -1320,7 +1368,7 @@ parseParens(); if (FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(/*MustBeDeclaration=*/false, Indenter.mustIndentAfterwards()); addUnwrappedLine(); } else { addUnwrappedLine(); @@ -1372,6 +1420,11 @@ return; } + LevelGuard Guard(Line->Level); + if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) { + addUnwrappedLine(); + ++Line->Level; + } // Parse enum body. bool HasError = !parseBracedList(/*ContinueOnSemicolons=*/true); if (HasError) { @@ -1380,6 +1433,13 @@ addUnwrappedLine(); } + if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) + { + if (FormatTok->is(tok::semi)) + nextToken(); + addUnwrappedLine(); + } + // We fall through to parsing a structural element afterwards, so that in // enum A {} n, m; // "} n, m;" will end up in one unwrapped line. @@ -1483,13 +1543,27 @@ } } } + + LevelGuard Guard(Line->Level); if (FormatTok->Tok.is(tok::l_brace)) { - if (ShouldBreakBeforeBrace(Style, InitialToken)) + bool isWhitesmiths = Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths; + if (ShouldBreakBeforeBrace(Style, InitialToken)) { addUnwrappedLine(); + if (isWhitesmiths) + ++Line->Level; + } - parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/true, + parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/!isWhitesmiths, /*MunchSemi=*/false); + + // If the token after the r_brace is a semi, + // then we want it to be grouped with the r_brace + if (FormatTok->is(tok::semi)) { + nextToken(); + addUnwrappedLine(); + } } + // We fall through to parsing a structural element afterwards, so // class A {} n, m; // will end up in one unwrapped line. @@ -1531,27 +1605,34 @@ nextToken(); nextToken(); // interface name - // @interface can be followed by either a base class, or a category. - if (FormatTok->Tok.is(tok::colon)) { - nextToken(); - nextToken(); // base class name - } else if (FormatTok->Tok.is(tok::l_paren)) - // Skip category, if present. - parseParens(); + { + LevelGuard Guard(Line->Level); - if (FormatTok->Tok.is(tok::less)) - parseObjCProtocolList(); + // @interface can be followed by either a base class, or a category. + if (FormatTok->Tok.is(tok::colon)) { + nextToken(); + nextToken(); // base class name + } else if (FormatTok->Tok.is(tok::l_paren)) + // Skip category, if present. + parseParens(); - if (FormatTok->Tok.is(tok::l_brace)) { - if (Style.BreakBeforeBraces == FormatStyle::BS_Allman || - Style.BreakBeforeBraces == FormatStyle::BS_GNU) - addUnwrappedLine(); - parseBlock(/*MustBeDeclaration=*/true); - } + if (FormatTok->Tok.is(tok::less)) + parseObjCProtocolList(); + if (FormatTok->Tok.is(tok::l_brace)) { + if (Style.BreakBeforeBraces == FormatStyle::BS_Allman || + Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths || + Style.BreakBeforeBraces == FormatStyle::BS_GNU) + addUnwrappedLine(); + if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) + ++Line->Level; + parseBlock(/*MustBeDeclaration=*/true); + } + // With instance variables, this puts '}' on its own line. Without instance // variables, this ends the @interface line. addUnwrappedLine(); + } parseObjCUntilAtEnd(); } Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -2262,6 +2262,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" @@ -3715,6 +3725,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" @@ -8140,6 +8157,10 @@ LinuxBraceStyle); verifyFormat("enum X {\n" " Y = 0,\n" + "};\n", + LinuxBraceStyle); + verifyFormat("enum X {\n" + " Y = 0,\n" "}\n", LinuxBraceStyle); verifyFormat("struct S {\n" @@ -8306,6 +8327,11 @@ " Y = 0\n" "}\n", AllmanBraceStyle); + verifyFormat("enum X\n" + "{\n" + " Y = 0\n" + "};\n", + AllmanBraceStyle); verifyFormat("@interface BSApplicationController ()\n" "{\n" @@ -8404,6 +8430,217 @@ 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" + " };\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); + + 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; @@ -8488,6 +8725,11 @@ " Y = 0,\n" "}\n", GNUBraceStyle); + verifyFormat("enum X\n" + "{\n" + " Y = 0\n" + "};\n", + GNUBraceStyle); verifyFormat("@interface BSApplicationController ()\n" "{\n" @@ -8792,6 +9034,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;