Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -695,15 +695,37 @@ /// \brief Always break constructor initializers before commas and align /// the commas with the colon. - /// \code - /// true: false: - /// SomeClass::Constructor() vs. SomeClass::Constructor() : a(a), - /// : a(a) b(b), - /// , b(b) c(c) {} - /// , c(c) {} - /// \endcode + /// This option is **deprecated* and is retained for backwards compatibility. bool BreakConstructorInitializersBeforeComma; + /// \brief Different ways to break initializers. + enum BreakConstructorInitializersStyle + { + /// Break constructor initializers before the colon and after the commas. + /// \code + /// Constructor() + /// : initializer1(), + /// initializer2() + /// \endcode + BCIS_BeforeColonAfterComma, + /// Break constructor initializers before the colon and commas, and align + /// the commas with the colon. + /// \code + /// Constructor() + /// : initializer1() + /// , initializer2() + /// \endcode + BCIS_BeforeColonAndComma, + /// Break constructor initializers after the colon and commas. + /// \code + /// Constructor() : + /// initializer1(), + /// initializer2() + /// \endcode + BCIS_AfterColonAndComma + }; + BreakConstructorInitializersStyle BreakConstructorInitializers; + /// \brief Break after each annotation on a field in Java files. /// \code{.java} /// true: false: @@ -1370,8 +1392,7 @@ BreakBeforeBinaryOperators == R.BreakBeforeBinaryOperators && BreakBeforeBraces == R.BreakBeforeBraces && BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators && - BreakConstructorInitializersBeforeComma == - R.BreakConstructorInitializersBeforeComma && + BreakConstructorInitializers == R.BreakConstructorInitializers && BreakAfterJavaFieldAnnotations == R.BreakAfterJavaFieldAnnotations && BreakStringLiterals == R.BreakStringLiterals && ColumnLimit == R.ColumnLimit && CommentPragmas == R.CommentPragmas && Index: lib/Format/ContinuationIndenter.cpp =================================================================== --- lib/Format/ContinuationIndenter.cpp +++ lib/Format/ContinuationIndenter.cpp @@ -54,13 +54,14 @@ const FormatStyle &Style) { const FormatToken &Previous = *Current.Previous; if (Current.is(TT_CtorInitializerComma) && - Style.BreakConstructorInitializersBeforeComma) + Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeColonAndComma) return true; return Previous.is(tok::comma) && !Current.isTrailingComment() && ((Previous.isNot(TT_CtorInitializerComma) || - !Style.BreakConstructorInitializersBeforeComma) && + (Style.BreakConstructorInitializers != + FormatStyle::BCIS_BeforeColonAndComma)) && (Previous.isNot(TT_InheritanceComma) || - !Style.BreakBeforeInheritanceComma)); + !Style.BreakBeforeInheritanceComma)); } ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style, @@ -179,11 +180,22 @@ getColumnLimit(State)) return true; if (Current.is(TT_CtorInitializerColon) && + (Style.BreakConstructorInitializers != + FormatStyle::BCIS_AfterColonAndComma) && (State.Column + State.Line->Last->TotalLength - Current.TotalLength + 2 > getColumnLimit(State) || State.Stack.back().BreakBeforeParameter) && ((Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All) || - Style.BreakConstructorInitializersBeforeComma || Style.ColumnLimit != 0)) + (Style.BreakConstructorInitializers == + FormatStyle::BCIS_BeforeColonAndComma) || + Style.ColumnLimit != 0)) + return true; + if (Previous.is(TT_CtorInitializerColon) && + (Style.BreakConstructorInitializers == + FormatStyle::BCIS_AfterColonAndComma) && + (State.Column + State.Line->Last->TotalLength - Previous.TotalLength > + getColumnLimit(State) || + State.Stack.back().BreakBeforeParameter)) return true; if (Current.is(TT_ObjCMethodExpr) && !Previous.is(TT_SelectorName) && State.Line->startsWith(TT_ObjCMethodSpecifier)) @@ -455,6 +467,11 @@ !Previous.is(TT_OverloadedOperator)) || (Previous.is(tok::colon) && Previous.is(TT_ObjCMethodExpr)))) { State.Stack.back().LastSpace = State.Column; + } else if (Previous.is(TT_CtorInitializerColon) && + (Style.BreakConstructorInitializers == + FormatStyle::BCIS_AfterColonAndComma)) { + State.Stack.back().Indent = State.Column; + State.Stack.back().LastSpace = State.Column; } else if ((Previous.isOneOf(TT_BinaryOperator, TT_ConditionalExpr, TT_CtorInitializerColon)) && ((Previous.getPrecedence() != prec::Assignment && @@ -612,7 +629,7 @@ State.Stack[i].BreakBeforeParameter = true; if (PreviousNonComment && - !PreviousNonComment->isOneOf(tok::comma, tok::semi) && + !PreviousNonComment->isOneOf(tok::comma, tok::colon, tok::semi) && (PreviousNonComment->isNot(TT_TemplateCloser) || Current.NestingLevel != 0) && !PreviousNonComment->isOneOf( @@ -746,6 +763,10 @@ return ContinuationIndent; if (NextNonComment->is(TT_CtorInitializerComma)) return State.Stack.back().Indent; + if (PreviousNonComment && PreviousNonComment->is(TT_CtorInitializerColon) && + (Style.BreakConstructorInitializers == + FormatStyle::BCIS_AfterColonAndComma)) + return State.Stack.back().Indent; if (NextNonComment->isOneOf(TT_CtorInitializerColon, TT_InheritanceColon, TT_InheritanceComma)) return State.FirstIndent + Style.ConstructorInitializerIndentWidth; @@ -805,19 +826,31 @@ State.FirstIndent + Style.ContinuationIndentWidth; } } - if (Current.is(TT_CtorInitializerColon)) { + if (Current.is(TT_CtorInitializerColon) && + (Style.BreakConstructorInitializers != + FormatStyle::BCIS_AfterColonAndComma)) { // Indent 2 from the column, so: // SomeClass::SomeClass() // : First(...), ... // Next(...) // ^ line up here. State.Stack.back().Indent = - State.Column + (Style.BreakConstructorInitializersBeforeComma ? 0 : 2); + State.Column + (Style.BreakConstructorInitializers == + FormatStyle::BCIS_BeforeColonAndComma ? 0 : 2); State.Stack.back().NestedBlockIndent = State.Stack.back().Indent; if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine) State.Stack.back().AvoidBinPacking = true; State.Stack.back().BreakBeforeParameter = false; } + if (Current.is(TT_CtorInitializerColon) && + (Style.BreakConstructorInitializers == + FormatStyle::BCIS_AfterColonAndComma)) { + State.Stack.back().Indent = + State.FirstIndent + Style.ConstructorInitializerIndentWidth; + State.Stack.back().NestedBlockIndent = State.Stack.back().Indent; + if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine) + State.Stack.back().AvoidBinPacking = true; + } if (Current.is(TT_InheritanceColon)) State.Stack.back().Indent = State.FirstIndent + Style.ContinuationIndentWidth; Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -123,6 +123,14 @@ } }; +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &IO, FormatStyle::BreakConstructorInitializersStyle &Value) { + IO.enumCase(Value, "BeforeColonAfterComma", FormatStyle::BCIS_BeforeColonAfterComma); + IO.enumCase(Value, "BeforeColonAndComma", FormatStyle::BCIS_BeforeColonAndComma); + IO.enumCase(Value, "AfterColonAndComma", FormatStyle::BCIS_AfterColonAndComma); + } +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) { @@ -293,6 +301,15 @@ Style.BreakBeforeTernaryOperators); IO.mapOptional("BreakConstructorInitializersBeforeComma", Style.BreakConstructorInitializersBeforeComma); + IO.mapOptional("BreakConstructorInitializers", + Style.BreakConstructorInitializers); + // If BreakConstructorInitializersBeforeComma was specified but + // BreakConstructorInitializers was not, initialize the latter from the + // former for backwards compatibility. + if (Style.BreakConstructorInitializersBeforeComma && + Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeColonAfterComma) + Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColonAndComma; + IO.mapOptional("BreakAfterJavaFieldAnnotations", Style.BreakAfterJavaFieldAnnotations); IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals); @@ -523,6 +540,7 @@ false, false, false, false, false}; LLVMStyle.BreakAfterJavaFieldAnnotations = false; LLVMStyle.BreakConstructorInitializersBeforeComma = false; + LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColonAfterComma; LLVMStyle.BreakBeforeInheritanceComma = false; LLVMStyle.BreakStringLiterals = true; LLVMStyle.ColumnLimit = 80; @@ -678,6 +696,7 @@ MozillaStyle.BinPackArguments = false; MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla; MozillaStyle.BreakConstructorInitializersBeforeComma = true; + MozillaStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColonAndComma; MozillaStyle.BreakBeforeInheritanceComma = true; MozillaStyle.ConstructorInitializerIndentWidth = 2; MozillaStyle.ContinuationIndentWidth = 2; @@ -701,6 +720,7 @@ Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All; Style.BreakBeforeBraces = FormatStyle::BS_WebKit; Style.BreakConstructorInitializersBeforeComma = true; + Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColonAndComma; Style.Cpp11BracedListStyle = false; Style.ColumnLimit = 0; Style.FixNamespaceComments = false; Index: lib/Format/TokenAnnotator.cpp =================================================================== --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -1984,7 +1984,7 @@ if (Left.is(tok::comment)) return 1000; - if (Left.isOneOf(TT_RangeBasedForLoopColon, TT_InheritanceColon)) + if (Left.isOneOf(TT_RangeBasedForLoopColon, TT_InheritanceColon, TT_CtorInitializerColon)) return 2; if (Right.isMemberAccess()) { @@ -2490,8 +2490,14 @@ Right.Previous->MatchingParen->NestingLevel == 0 && Style.AlwaysBreakTemplateDeclarations) return true; - if ((Right.isOneOf(TT_CtorInitializerComma, TT_CtorInitializerColon)) && - Style.BreakConstructorInitializersBeforeComma && + if (Right.is(TT_CtorInitializerComma) && + (Style.BreakConstructorInitializers == + FormatStyle::BCIS_BeforeColonAndComma) && + !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) + return true; + if (Right.is(TT_CtorInitializerColon) && + (Style.BreakConstructorInitializers == + FormatStyle::BCIS_BeforeColonAndComma) && !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) return true; // Break only if we have multiple inheritance. @@ -2599,7 +2605,10 @@ // The first comment in a braced lists is always interpreted as belonging to // the first list element. Otherwise, it should be placed outside of the // list. - return Left.BlockKind == BK_BracedInit; + return Left.BlockKind == BK_BracedInit || + (Left.is(TT_CtorInitializerColon) && + (Style.BreakConstructorInitializers == + FormatStyle::BCIS_AfterColonAndComma)); if (Left.is(tok::question) && Right.is(tok::colon)) return false; if (Right.is(TT_ConditionalExpr) || Right.is(tok::question)) @@ -2672,11 +2681,17 @@ if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral)) return true; + if (Left.is(TT_CtorInitializerColon)) + return Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColonAndComma; + if (Right.is(TT_CtorInitializerColon)) + return Style.BreakConstructorInitializers != FormatStyle::BCIS_AfterColonAndComma; if (Left.is(TT_CtorInitializerComma) && - Style.BreakConstructorInitializersBeforeComma) + (Style.BreakConstructorInitializers == + FormatStyle::BCIS_BeforeColonAndComma)) return false; if (Right.is(TT_CtorInitializerComma) && - Style.BreakConstructorInitializersBeforeComma) + (Style.BreakConstructorInitializers == + FormatStyle::BCIS_BeforeColonAndComma)) return true; if (Left.is(TT_InheritanceComma) && Style.BreakBeforeInheritanceComma) return false; Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -56,16 +56,17 @@ return *Result; } - FormatStyle getLLVMStyleWithColumns(unsigned ColumnLimit) { - FormatStyle Style = getLLVMStyle(); + FormatStyle getStyleWithColumns(FormatStyle Style, unsigned ColumnLimit) { Style.ColumnLimit = ColumnLimit; return Style; } + FormatStyle getLLVMStyleWithColumns(unsigned ColumnLimit) { + return getStyleWithColumns(getLLVMStyle(), ColumnLimit); + } + FormatStyle getGoogleStyleWithColumns(unsigned ColumnLimit) { - FormatStyle Style = getGoogleStyle(); - Style.ColumnLimit = ColumnLimit; - return Style; + return getStyleWithColumns(getGoogleStyle(), ColumnLimit); } void verifyFormat(llvm::StringRef Code, @@ -2699,6 +2700,128 @@ " aaaa(aaaa) {}")); } +TEST_F(FormatTest, BreakConstructorInitializersAfterColonAndComma) { + FormatStyle Style = getLLVMStyle(); + Style.BreakConstructorInitializers = FormatStyle::BCIS_AfterColonAndComma; + + verifyFormat("Constructor() : Initializer(FitsOnTheLine) {}"); + verifyFormat("Constructor() : Inttializer(FitsOnTheLine) {}", + getStyleWithColumns(Style, 45)); + verifyFormat("Constructor() :\n" + " Inttializer(FitsOnTheLine) {}", + getStyleWithColumns(Style, 44)); + verifyFormat("Constructor() :\n" + " Inttializer(FitsOnTheLine) {}", + getStyleWithColumns(Style, 43)); + + verifyFormat("template \n" + "Constructor() : Initializer(FitsOnTheLine) {}", + getStyleWithColumns(Style, 50)); + + verifyFormat( + "SomeClass::Constructor() :\n" + " aaaaaaaaaaaaa(aaaaaaaaaaaaaa), aaaaaaaaaaaaaaa(aaaaaaaaaaaa) {}", + Style); + + verifyFormat( + "SomeClass::Constructor() :\n" + " aaaaaaaaaaaaa(aaaaaaaaaaaaaa), aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n" + " aaaaaaaaaaaaa(aaaaaaaaaaaaaa) {}", + Style); + verifyFormat( + "SomeClass::Constructor() :\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa),\n" + " aaaaaaaaaaaaaaa(aaaaaaaaaaaa) {}", + Style); + verifyFormat("Constructor(aaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" + " aaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) :\n" + " aaaaaaaaaa(aaaaaa) {}", + Style); + + verifyFormat("Constructor() :\n" + " aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaa),\n" + " aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaa),\n" + " aaaaaaaaaaaaaaaaaaaaaaa() {}", + Style); + + verifyFormat("Constructor() :\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}", + Style); + + verifyFormat("Constructor(int Parameter = 0) :\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaa),\n" + " aaaaaaaaaaaa(aaaaaaaaaaaaaaaaa) {}", + Style); + verifyFormat("Constructor() :\n" + " aaaaaaaaaaaaaaaaaaaaaa(a), bbbbbbbbbbbbbbbbbbbbbbbb(b) {\n" + "}", + getStyleWithColumns(Style, 60)); + verifyFormat("Constructor() :\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" + " aaaaaaaaaaaaaaaaaaaaaaaaa(aaaa, aaaa)) {}", + Style); + + // Here a line could be saved by splitting the second initializer onto two + // lines, but that is not desirable. + verifyFormat("Constructor() :\n" + " aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaa),\n" + " aaaaaaaaaaa(aaaaaaaaaaa),\n" + " aaaaaaaaaaaaaaaaaaaaat(aaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}", + Style); + + FormatStyle OnePerLine = Style; + OnePerLine.ConstructorInitializerAllOnOneLineOrOnePerLine = true; + OnePerLine.AllowAllParametersOfDeclarationOnNextLine = false; + verifyFormat("SomeClass::Constructor() :\n" + " aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n" + " aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n" + " aaaaaaaaaaaaa(aaaaaaaaaaaaaa) {}", + OnePerLine); + verifyFormat("SomeClass::Constructor() :\n" + " aaaaaaaaaaaaa(aaaaaaaaaaaaaa), // Some comment\n" + " aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n" + " aaaaaaaaaaaaa(aaaaaaaaaaaaaa) {}", + OnePerLine); + verifyFormat("MyClass::MyClass(int var) :\n" + " some_var_(var), // 4 space indent\n" + " some_other_var_(var + 1) { // lined up\n" + "}", + OnePerLine); + verifyFormat("Constructor() :\n" + " aaaaa(aaaaaa),\n" + " aaaaa(aaaaaa),\n" + " aaaaa(aaaaaa),\n" + " aaaaa(aaaaaa),\n" + " aaaaa(aaaaaa) {}", + OnePerLine); + verifyFormat("Constructor() :\n" + " aaaaa(aaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaa,\n" + " aaaaaaaaaaaaaaaaaaaaaa) {}", + OnePerLine); + OnePerLine.BinPackParameters = false; + verifyFormat( + "Constructor() :\n" + " aaaaaaaaaaaaaaaaaaaaaaaa(\n" + " aaaaaaaaaaa().aaa(),\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}", + OnePerLine); + OnePerLine.ColumnLimit = 60; + verifyFormat("Constructor() :\n" + " aaaaaaaaaaaaaaaaaaaa(a),\n" + " bbbbbbbbbbbbbbbbbbbbbbbb(b) {}", + OnePerLine); + + EXPECT_EQ("Constructor() :\n" + " // Comment forcing unwanted break.\n" + " aaaa(aaaa) {}", + format("Constructor() :\n" + " // Comment forcing unwanted break.\n" + " aaaa(aaaa) {}", + Style)); +} + TEST_F(FormatTest, MemoizationTests) { // This breaks if the memoization lookup does not take \c Indent and // \c LastSpace into account. @@ -8774,6 +8897,17 @@ CHECK_PARSE("BreakBeforeBinaryOperators: true", BreakBeforeBinaryOperators, FormatStyle::BOS_All); + Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColonAfterComma; + CHECK_PARSE("BreakConstructorInitializers: BeforeColonAndComma", + BreakConstructorInitializers, FormatStyle::BCIS_BeforeColonAndComma); + CHECK_PARSE("BreakConstructorInitializers: AfterColonAndComma", + BreakConstructorInitializers, FormatStyle::BCIS_AfterColonAndComma); + CHECK_PARSE("BreakConstructorInitializers: BeforeColonAfterComma", + BreakConstructorInitializers, FormatStyle::BCIS_BeforeColonAfterComma); + // For backward compatibility: + CHECK_PARSE("BreakConstructorInitializersBeforeComma: true", + BreakConstructorInitializers, FormatStyle::BCIS_BeforeColonAndComma); + Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak; CHECK_PARSE("AlignAfterOpenBracket: Align", AlignAfterOpenBracket, FormatStyle::BAS_Align); @@ -9191,9 +9325,9 @@ Style); } -TEST_F(FormatTest, BreakConstructorInitializersBeforeComma) { +TEST_F(FormatTest, BreakConstructorInitializersBeforeColonAndComma) { FormatStyle Style = getLLVMStyle(); - Style.BreakConstructorInitializersBeforeComma = true; + Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColonAndComma; Style.ConstructorInitializerIndentWidth = 4; verifyFormat("SomeClass::Constructor()\n" " : a(a)\n"