diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 79e26d0a0c6aa13be823024992b8b9c4b20df2b2..47b5bb69073ca487a64ae8e57f37be853fdf8205 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -101,6 +101,20 @@ struct FormatStyle { /// tab characters. bool UseTab; + /// \brief Different ways to attach braces to their surrounding context. + enum BraceBreakingStyle { + /// Always attach braces to surrounding context. + BS_Attach, + /// Like \c Attach, but break before braces on function, namespace and + /// class definitions. + BS_Linux, + /// Like \c Attach, but break before function definitions. + BS_Stroustrup + }; + + /// \brief The brace breaking style to use. + BraceBreakingStyle BreakBeforeBraces; + bool operator==(const FormatStyle &R) const { return AccessModifierOffset == R.AccessModifierOffset && AlignEscapedNewlinesLeft == R.AlignEscapedNewlinesLeft && @@ -122,7 +136,8 @@ struct FormatStyle { SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments && Standard == R.Standard && IndentWidth == R.IndentWidth && - UseTab == R.UseTab; + UseTab == R.UseTab && + BreakBeforeBraces == R.BreakBeforeBraces; } }; diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index a62fa379ab1f8f925b6961b920d8a3db4aa456d7..b8c40cf2633c2089117903ed388df60cbe37d7ef 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -36,11 +36,21 @@ namespace llvm { namespace yaml { template <> struct ScalarEnumerationTraits { - static void enumeration(IO &io, - clang::format::FormatStyle::LanguageStandard &value) { - io.enumCase(value, "C++03", clang::format::FormatStyle::LS_Cpp03); - io.enumCase(value, "C++11", clang::format::FormatStyle::LS_Cpp11); - io.enumCase(value, "Auto", clang::format::FormatStyle::LS_Auto); + static void enumeration(IO &IO, + clang::format::FormatStyle::LanguageStandard &Value) { + IO.enumCase(Value, "C++03", clang::format::FormatStyle::LS_Cpp03); + IO.enumCase(Value, "C++11", clang::format::FormatStyle::LS_Cpp11); + IO.enumCase(Value, "Auto", clang::format::FormatStyle::LS_Auto); + } +}; + +template<> +struct ScalarEnumerationTraits { + static void + enumeration(IO &IO, clang::format::FormatStyle::BraceBreakingStyle &Value) { + IO.enumCase(Value, "Attach", clang::format::FormatStyle::BS_Attach); + IO.enumCase(Value, "Linux", clang::format::FormatStyle::BS_Linux); + IO.enumCase(Value, "Stroustrup", clang::format::FormatStyle::BS_Stroustrup); } }; @@ -87,6 +97,7 @@ template <> struct MappingTraits { IO.mapOptional("Standard", Style.Standard); IO.mapOptional("IndentWidth", Style.IndentWidth); IO.mapOptional("UseTab", Style.UseTab); + IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces); } }; } @@ -115,6 +126,7 @@ FormatStyle getLLVMStyle() { LLVMStyle.Standard = FormatStyle::LS_Cpp03; LLVMStyle.IndentWidth = 2; LLVMStyle.UseTab = false; + LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; return LLVMStyle; } @@ -138,6 +150,7 @@ FormatStyle getGoogleStyle() { GoogleStyle.Standard = FormatStyle::LS_Auto; GoogleStyle.IndentWidth = 2; GoogleStyle.UseTab = false; + GoogleStyle.BreakBeforeBraces = FormatStyle::BS_Attach; return GoogleStyle; } diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 722af5d2b7630874a8b67b551cc6f1d1aabb8e3b..a08790d80dcaf623d43325f2c4020bcc114b60f4 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -402,6 +402,10 @@ void UnwrappedLineParser::parseStructuralElement() { // structural element. // FIXME: Figure out cases where this is not true, and add projections for // them (the one we know is missing are lambdas). + if (Style.BreakBeforeBraces == FormatStyle::BS_Linux || + Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup) + addUnwrappedLine(); + parseBlock(/*MustBeDeclaration=*/ false); addUnwrappedLine(); return; @@ -577,6 +581,9 @@ void UnwrappedLineParser::parseNamespace() { if (FormatTok.Tok.is(tok::identifier)) nextToken(); if (FormatTok.Tok.is(tok::l_brace)) { + if (Style.BreakBeforeBraces == FormatStyle::BS_Linux) + addUnwrappedLine(); + parseBlock(/*MustBeDeclaration=*/ true, 0); // Munch the semicolon after a namespace. This is more common than one would // think. Puttin the semicolon into its own line is very ugly. @@ -751,8 +758,12 @@ void UnwrappedLineParser::parseRecord() { } } } - if (FormatTok.Tok.is(tok::l_brace)) + if (FormatTok.Tok.is(tok::l_brace)) { + if (Style.BreakBeforeBraces == FormatStyle::BS_Linux) + addUnwrappedLine(); + parseBlock(/*MustBeDeclaration=*/ true); + } // We fall through to parsing a structural element afterwards, so // class A {} n, m; // will end up in one unwrapped line. diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index ce79a1c97b99c407c99669810a18026de4338bb5..9624ac92240a445355268d975068e8409cb39c69 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -4037,6 +4037,42 @@ TEST_F(FormatTest, ConfigurableUseOfTab) { Tab); } +TEST_F(FormatTest, LinuxBraceBreaking) { + FormatStyle BreakBeforeBrace = getLLVMStyle(); + BreakBeforeBrace.BreakBeforeBraces = FormatStyle::BS_Linux; + verifyFormat("namespace a\n" + "{\n" + "class A\n" + "{\n" + " void f()\n" + " {\n" + " if (true) {\n" + " a();\n" + " b();\n" + " }\n" + " }\n" + "}\n" + "}", + BreakBeforeBrace); +} + +TEST_F(FormatTest, StroustrupBraceBreaking) { + FormatStyle BreakBeforeBrace = getLLVMStyle(); + BreakBeforeBrace.BreakBeforeBraces = FormatStyle::BS_Stroustrup; + verifyFormat("namespace a {\n" + "class A {\n" + " void f()\n" + " {\n" + " if (true) {\n" + " a();\n" + " b();\n" + " }\n" + " }\n" + "}\n" + "}", + BreakBeforeBrace); +} + bool allStylesEqual(ArrayRef Styles) { for (size_t i = 1; i < Styles.size(); ++i) if (!(Styles[0] == Styles[i])) @@ -4113,6 +4149,14 @@ TEST_F(FormatTest, ParsesConfiguration) { CHECK_PARSE("BasedOnStyle: LLVM", ColumnLimit, BaseStyle.ColumnLimit); CHECK_PARSE("BasedOnStyle: LLVM\nColumnLimit: 1234", ColumnLimit, 1234u); + Style.BreakBeforeBraces = FormatStyle::BS_Stroustrup; + CHECK_PARSE("BreakBeforeBraces: Attach", BreakBeforeBraces, + FormatStyle::BS_Attach); + CHECK_PARSE("BreakBeforeBraces: Linux", BreakBeforeBraces, + FormatStyle::BS_Linux); + CHECK_PARSE("BreakBeforeBraces: Stroustrup", BreakBeforeBraces, + FormatStyle::BS_Stroustrup); + #undef CHECK_PARSE #undef CHECK_PARSE_BOOL }