Index: docs/ClangFormatStyleOptions.rst =================================================================== --- docs/ClangFormatStyleOptions.rst +++ docs/ClangFormatStyleOptions.rst @@ -994,18 +994,6 @@ -**BreakBeforeInheritanceComma** (``bool``) - If ``true``, in the class inheritance expression clang-format will - break before ``:`` and ``,`` if there is multiple inheritance. - - .. code-block:: c++ - - true: false: - class MyClass vs. class MyClass : public X, public Y { - : public X }; - , public Y { - }; - **BreakBeforeTernaryOperators** (``bool``) If ``true``, ternary operators will be placed after line breaks. @@ -1056,6 +1044,42 @@ +**BreakInheritanceList** (``BreakInheritanceListStyle``) + The inheritance list style to use. + + Possible values: + + * ``BILS_BeforeColon`` (in configuration: ``BeforeColon``) + Break inheritance list before the colon and after the commas. + + .. code-block:: c++ + + class Foo + : Base1, + Base2 + {}; + + * ``BILS_BeforeComma`` (in configuration: ``BeforeComma``) + Break inheritance list before the colon and commas, and align + the commas with the colon. + + .. code-block:: c++ + + Constructor() + : initializer1() + , initializer2() + + * ``BILS_AfterColon`` (in configuration: ``AfterColon``) + Break inheritance list after the colon and commas. + + .. code-block:: c++ + + Constructor() : + initializer1(), + initializer2() + + + **BreakStringLiterals** (``bool``) Allow breaking string literals when formatting. @@ -1122,7 +1146,7 @@ **ConstructorInitializerIndentWidth** (``unsigned``) The number of characters to use for indentation of constructor - initializer lists. + initializer lists as well as inheritance lists. **ContinuationIndentWidth** (``unsigned``) Indent width for line continuations. Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -893,16 +893,35 @@ /// \endcode std::string CommentPragmas; - /// If ``true``, in the class inheritance expression clang-format will - /// break before ``:`` and ``,`` if there is multiple inheritance. - /// \code - /// true: false: - /// class MyClass vs. class MyClass : public X, public Y { - /// : public X }; - /// , public Y { - /// }; - /// \endcode - bool BreakBeforeInheritanceComma; + /// Different ways to break inheritance list. + enum BreakInheritanceListStyle { + /// Break inheritance list before the colon and after the commas. + /// \code + /// class Foo + /// : Base1, + /// Base2 + /// {}; + /// \endcode + BILS_BeforeColon, + /// Break inheritance list before the colon and commas, and align + /// the commas with the colon. + /// \code + /// Constructor() + /// : initializer1() + /// , initializer2() + /// \endcode + BILS_BeforeComma, + /// Break inheritance list after the colon and commas. + /// \code + /// Constructor() : + /// initializer1(), + /// initializer2() + /// \endcode + BILS_AfterColon + }; + + /// The inheritance list style to use. + BreakInheritanceListStyle BreakInheritanceList; /// If ``true``, consecutive namespace declarations will be on the same /// line. If ``false``, each namespace is declared on a new line. @@ -946,7 +965,7 @@ bool ConstructorInitializerAllOnOneLineOrOnePerLine; /// The number of characters to use for indentation of constructor - /// initializer lists. + /// initializer lists as well as inheritance lists. unsigned ConstructorInitializerIndentWidth; /// Indent width for line continuations. @@ -1673,7 +1692,7 @@ BreakAfterJavaFieldAnnotations == R.BreakAfterJavaFieldAnnotations && BreakStringLiterals == R.BreakStringLiterals && ColumnLimit == R.ColumnLimit && CommentPragmas == R.CommentPragmas && - BreakBeforeInheritanceComma == R.BreakBeforeInheritanceComma && + BreakInheritanceList == R.BreakInheritanceList && ConstructorInitializerAllOnOneLineOrOnePerLine == R.ConstructorInitializerAllOnOneLineOrOnePerLine && ConstructorInitializerIndentWidth == Index: lib/Format/ContinuationIndenter.cpp =================================================================== --- lib/Format/ContinuationIndenter.cpp +++ lib/Format/ContinuationIndenter.cpp @@ -131,7 +131,7 @@ Style.BreakConstructorInitializers != FormatStyle::BCIS_BeforeComma) && (Previous.isNot(TT_InheritanceComma) || - !Style.BreakBeforeInheritanceComma)); + Style.BreakInheritanceList != FormatStyle::BILS_BeforeComma)); } static bool opensProtoMessageField(const FormatToken &LessTok, @@ -576,7 +576,11 @@ // If "BreakBeforeInheritanceComma" mode, don't break within the inheritance // declaration unless there is multiple inheritance. - if (Style.BreakBeforeInheritanceComma && Current.is(TT_InheritanceColon)) + if (Style.BreakInheritanceList == FormatStyle::BILS_BeforeComma && + Current.is(TT_InheritanceColon)) + State.Stack.back().NoLineBreak = true; + if (Style.BreakInheritanceList == FormatStyle::BILS_AfterColon && + Previous.is(TT_InheritanceColon)) State.Stack.back().NoLineBreak = true; if (Current.is(TT_SelectorName) && @@ -1019,6 +1023,9 @@ if (PreviousNonComment && PreviousNonComment->is(TT_CtorInitializerColon) && Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon) return State.Stack.back().Indent; + if (PreviousNonComment && PreviousNonComment->is(TT_InheritanceColon) && + Style.BreakInheritanceList == FormatStyle::BILS_AfterColon) + return State.Stack.back().Indent; if (NextNonComment->isOneOf(TT_CtorInitializerColon, TT_InheritanceColon, TT_InheritanceComma)) return State.FirstIndent + Style.ConstructorInitializerIndentWidth; @@ -1103,7 +1110,7 @@ } if (Current.is(TT_InheritanceColon)) State.Stack.back().Indent = - State.FirstIndent + Style.ContinuationIndentWidth; + State.FirstIndent + Style.ConstructorInitializerIndentWidth; if (Current.isOneOf(TT_BinaryOperator, TT_ConditionalExpr) && Newline) State.Stack.back().NestedBlockIndent = State.Column + Current.ColumnWidth + 1; Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -149,6 +149,16 @@ }; template <> +struct ScalarEnumerationTraits { + static void + enumeration(IO &IO, FormatStyle::BreakInheritanceListStyle &Value) { + IO.enumCase(Value, "BeforeColon", FormatStyle::BILS_BeforeColon); + IO.enumCase(Value, "BeforeComma", FormatStyle::BILS_BeforeComma); + IO.enumCase(Value, "AfterColon", FormatStyle::BILS_AfterColon); + } +}; + +template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, FormatStyle::PPDirectiveIndentStyle &Value) { IO.enumCase(Value, "None", FormatStyle::PPDIS_None); @@ -350,8 +360,19 @@ IO.mapOptional("BreakBeforeBinaryOperators", Style.BreakBeforeBinaryOperators); IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces); + + bool BreakBeforeInheritanceComma = false; IO.mapOptional("BreakBeforeInheritanceComma", - Style.BreakBeforeInheritanceComma); + BreakBeforeInheritanceComma); + IO.mapOptional("BreakInheritanceList", + Style.BreakInheritanceList); + // If BreakBeforeInheritanceComma was specified but + // BreakInheritance was not, initialize the latter from the + // former for backwards compatibility. + if (BreakBeforeInheritanceComma && + Style.BreakInheritanceList == FormatStyle::BILS_BeforeColon) + Style.BreakInheritanceList = FormatStyle::BILS_BeforeComma; + IO.mapOptional("BreakBeforeTernaryOperators", Style.BreakBeforeTernaryOperators); @@ -624,7 +645,7 @@ false, false, true, true, true}; LLVMStyle.BreakAfterJavaFieldAnnotations = false; LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon; - LLVMStyle.BreakBeforeInheritanceComma = false; + LLVMStyle.BreakInheritanceList = FormatStyle::BILS_BeforeColon; LLVMStyle.BreakStringLiterals = true; LLVMStyle.ColumnLimit = 80; LLVMStyle.CommentPragmas = "^ IWYU pragma:"; @@ -840,7 +861,7 @@ MozillaStyle.BinPackArguments = false; MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla; MozillaStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma; - MozillaStyle.BreakBeforeInheritanceComma = true; + MozillaStyle.BreakInheritanceList = FormatStyle::BILS_BeforeComma; MozillaStyle.ConstructorInitializerIndentWidth = 2; MozillaStyle.ContinuationIndentWidth = 2; MozillaStyle.Cpp11BracedListStyle = false; Index: lib/Format/TokenAnnotator.cpp =================================================================== --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -2888,7 +2888,8 @@ !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) return true; // Break only if we have multiple inheritance. - if (Style.BreakBeforeInheritanceComma && Right.is(TT_InheritanceComma)) + if (Style.BreakInheritanceList == FormatStyle::BILS_BeforeComma && + Right.is(TT_InheritanceComma)) return true; if (Right.is(tok::string_literal) && Right.TokenText.startswith("R\"")) // Multiline raw string literals are special wrt. line breaks. The author @@ -3085,8 +3086,10 @@ return Style.BreakBeforeTernaryOperators; if (Left.is(TT_ConditionalExpr) || Left.is(tok::question)) return !Style.BreakBeforeTernaryOperators; + if (Left.is(TT_InheritanceColon)) + return Style.BreakInheritanceList == FormatStyle::BILS_AfterColon; if (Right.is(TT_InheritanceColon)) - return true; + return Style.BreakInheritanceList != FormatStyle::BILS_AfterColon; if (Right.is(TT_ObjCMethodExpr) && !Right.is(tok::r_square) && Left.isNot(TT_SelectorName)) return true; @@ -3174,9 +3177,11 @@ if (Right.is(TT_CtorInitializerComma) && Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma) return true; - if (Left.is(TT_InheritanceComma) && Style.BreakBeforeInheritanceComma) + if (Left.is(TT_InheritanceComma) && + Style.BreakInheritanceList == FormatStyle::BILS_BeforeComma) return false; - if (Right.is(TT_InheritanceComma) && Style.BreakBeforeInheritanceComma) + if (Right.is(TT_InheritanceComma) && + Style.BreakInheritanceList == FormatStyle::BILS_BeforeComma) return true; if ((Left.is(tok::greater) && Right.is(tok::greater)) || (Left.is(tok::less) && Right.is(tok::less))) Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -1316,15 +1316,40 @@ verifyFormat("class ::A::B {};"); } -TEST_F(FormatTest, BreakBeforeInheritanceComma) { - FormatStyle StyleWithInheritanceBreak = getLLVMStyle(); - StyleWithInheritanceBreak.BreakBeforeInheritanceComma = true; - - verifyFormat("class MyClass : public X {};", StyleWithInheritanceBreak); +TEST_F(FormatTest, BreakInheritanceStyle) { + FormatStyle StyleWithInheritanceBreakBeforeComma = getLLVMStyle(); + StyleWithInheritanceBreakBeforeComma.BreakInheritanceList = + FormatStyle::BILS_BeforeComma; + verifyFormat("class MyClass : public X {};", + StyleWithInheritanceBreakBeforeComma); verifyFormat("class MyClass\n" " : public X\n" " , public Y {};", - StyleWithInheritanceBreak); + StyleWithInheritanceBreakBeforeComma); + verifyFormat("class AAAAAAAAAAAAAAAAAAAAAA\n" + " : public BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n" + " , public CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC {};", + StyleWithInheritanceBreakBeforeComma); + verifyFormat("struct aaaaaaaaaaaaa\n" + " : public aaaaaaaaaaaaaaaaaaa< // break\n" + " aaaaaaaaaaaaaaaa> {};", + StyleWithInheritanceBreakBeforeComma); + + FormatStyle StyleWithInheritanceBreakAfterColon = getLLVMStyle(); + StyleWithInheritanceBreakAfterColon.BreakInheritanceList = + FormatStyle::BILS_AfterColon; + verifyFormat("class MyClass : public X {};", + StyleWithInheritanceBreakAfterColon); + verifyFormat("class MyClass : public X, public Y {};", + StyleWithInheritanceBreakAfterColon); + verifyFormat("class AAAAAAAAAAAAAAAAAAAAAA :\n" + " public BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB,\n" + " public CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC {};", + StyleWithInheritanceBreakAfterColon); + verifyFormat("struct aaaaaaaaaaaaa :\n" + " public aaaaaaaaaaaaaaaaaaa< // break\n" + " aaaaaaaaaaaaaaaa> {};", + StyleWithInheritanceBreakAfterColon); } TEST_F(FormatTest, FormatsVariableDeclarationsAfterStructOrClass) { @@ -3726,6 +3751,23 @@ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb {}", Style); + + // `ConstructorInitializerIndentWidth` actually applies to InheritanceList as well + Style.BreakInheritanceList = FormatStyle::BILS_BeforeColon; + verifyFormat("class SomeClass\n" + " : public aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" + " public bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb {};", + Style); + Style.BreakInheritanceList = FormatStyle::BILS_BeforeComma; + verifyFormat("class SomeClass\n" + " : public aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" + " , public bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb {};", + Style); + Style.BreakInheritanceList = FormatStyle::BILS_AfterColon; + verifyFormat("class SomeClass :\n" + " public aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" + " public bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb {};", + Style); } #ifndef EXPENSIVE_CHECKS @@ -9164,7 +9206,7 @@ " bbbbbbbbbbbbbbbb(2) {}", CtorInitializerStyle); - FormatStyle InheritanceStyle = getLLVMStyle(); + FormatStyle InheritanceStyle = getLLVMStyleWithColumns(30); InheritanceStyle.SpaceBeforeInheritanceColon = false; verifyFormat("class Foo: public Bar {};", InheritanceStyle); verifyFormat("Foo::Foo() : foo(1) {}", InheritanceStyle); @@ -9180,6 +9222,29 @@ "default:\n" "}", InheritanceStyle); + InheritanceStyle.BreakInheritanceList = FormatStyle::BILS_AfterColon; + verifyFormat("class Foooooooooooooooooooooo:\n" + " public aaaaaaaaaaaaaaaaaa,\n" + " public bbbbbbbbbbbbbbbbbb {\n" + "}", + InheritanceStyle); + InheritanceStyle.BreakInheritanceList = FormatStyle::BILS_BeforeComma; + verifyFormat("class Foooooooooooooooooooooo\n" + " : public aaaaaaaaaaaaaaaaaa\n" + " , public bbbbbbbbbbbbbbbbbb {\n" + "}", + InheritanceStyle); + InheritanceStyle.BreakInheritanceList = FormatStyle::BILS_BeforeColon; + verifyFormat("class Foooooooooooooooooooooo\n" + " : public aaaaaaaaaaaaaaaaaa,\n" + " public bbbbbbbbbbbbbbbbbb {\n" + "}", + InheritanceStyle); + InheritanceStyle.ConstructorInitializerIndentWidth = 0; + verifyFormat("class Foooooooooooooooooooooo\n" + ": public aaaaaaaaaaaaaaaaaa,\n" + " public bbbbbbbbbbbbbbbbbb {}", + InheritanceStyle); FormatStyle ForLoopStyle = getLLVMStyle(); ForLoopStyle.SpaceBeforeRangeBasedForLoopColon = false; @@ -10534,7 +10599,6 @@ CHECK_PARSE_BOOL(BreakAfterJavaFieldAnnotations); CHECK_PARSE_BOOL(BreakBeforeTernaryOperators); CHECK_PARSE_BOOL(BreakStringLiterals); - CHECK_PARSE_BOOL(BreakBeforeInheritanceComma) CHECK_PARSE_BOOL(CompactNamespaces); CHECK_PARSE_BOOL(ConstructorInitializerAllOnOneLineOrOnePerLine); CHECK_PARSE_BOOL(DerivePointerAlignment); @@ -10651,6 +10715,17 @@ CHECK_PARSE("BreakConstructorInitializersBeforeComma: true", BreakConstructorInitializers, FormatStyle::BCIS_BeforeComma); + Style.BreakInheritanceList = FormatStyle::BILS_BeforeColon; + CHECK_PARSE("BreakInheritanceList: BeforeComma", + BreakInheritanceList, FormatStyle::BILS_BeforeComma); + CHECK_PARSE("BreakInheritanceList: AfterColon", + BreakInheritanceList, FormatStyle::BILS_AfterColon); + CHECK_PARSE("BreakInheritanceList: BeforeColon", + BreakInheritanceList, FormatStyle::BILS_BeforeColon); + // For backward compatibility: + CHECK_PARSE("BreakBeforeInheritanceComma: true", + BreakInheritanceList, FormatStyle::BILS_BeforeComma); + Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak; CHECK_PARSE("AlignAfterOpenBracket: Align", AlignAfterOpenBracket, FormatStyle::BAS_Align);