diff options
-rw-r--r-- | lib/Format/Format.cpp | 50 | ||||
-rw-r--r-- | lib/Format/TokenAnnotator.cpp | 2 | ||||
-rw-r--r-- | unittests/Format/FormatTest.cpp | 35 |
3 files changed, 71 insertions, 16 deletions
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index 08ea8e97de..2a606974e5 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -229,7 +229,8 @@ public: LineState State; State.Column = FirstIndent; State.NextToken = &RootToken; - State.Stack.push_back(ParenState(FirstIndent + 4, FirstIndent)); + State.Stack.push_back(ParenState(FirstIndent + 4, FirstIndent, + !Style.BinPackParameters)); State.VariablePos = 0; State.LineContainsContinuedForLoopSection = false; @@ -298,10 +299,11 @@ private: } struct ParenState { - ParenState(unsigned Indent, unsigned LastSpace) + ParenState(unsigned Indent, unsigned LastSpace, bool AvoidBinPacking) : Indent(Indent), LastSpace(LastSpace), AssignmentColumn(0), FirstLessLess(0), BreakBeforeClosingBrace(false), QuestionColumn(0), - BreakAfterComma(false), HasMultiParameterLine(false) { + AvoidBinPacking(AvoidBinPacking), BreakAfterComma(false), + HasMultiParameterLine(false) { } /// \brief The position to which a specific parenthesis level needs to be @@ -334,7 +336,15 @@ private: /// \brief The column of a \c ? in a conditional expression; unsigned QuestionColumn; + /// \brief Avoid bin packing, i.e. multiple parameters/elements on multiple + /// lines, in this context. + bool AvoidBinPacking; + + /// \brief Break after the next comma (or all the commas in this context if + /// \c AvoidBinPacking is \c true). bool BreakAfterComma; + + /// \brief This context already has a line with more than one parameter. bool HasMultiParameterLine; bool operator<(const ParenState &Other) const { @@ -350,6 +360,8 @@ private: return BreakBeforeClosingBrace; if (QuestionColumn != Other.QuestionColumn) return QuestionColumn < Other.QuestionColumn; + if (AvoidBinPacking != Other.AvoidBinPacking) + return AvoidBinPacking; if (BreakAfterComma != Other.BreakAfterComma) return BreakAfterComma; if (HasMultiParameterLine != Other.HasMultiParameterLine) @@ -444,6 +456,9 @@ private: State.Column = State.Stack[ParenLevel].Indent; } + if (Previous.is(tok::comma) && !State.Stack.back().AvoidBinPacking) + State.Stack.back().BreakAfterComma = false; + if (RootToken.is(tok::kw_for)) State.LineContainsContinuedForLoopSection = Previous.isNot(tok::semi); @@ -499,6 +514,7 @@ private: State.Stack.back().LastSpace = State.Column; else if (Previous.ParameterCount > 1 && (Previous.is(tok::l_paren) || Previous.is(tok::l_square) || + Previous.is(tok::l_brace) || Previous.Type == TT_TemplateOpener)) // If this function has multiple parameters, indent nested calls from // the start of the first parameter. @@ -509,7 +525,7 @@ private: if (Newline && Previous.is(tok::l_brace)) State.Stack.back().BreakBeforeClosingBrace = true; - if (!Style.BinPackParameters && Newline) { + if (State.Stack.back().AvoidBinPacking && Newline) { // If we are breaking after '(', '{', '<', this is not bin packing unless // AllowAllParametersOfDeclarationOnNextLine is false. if ((Previous.isNot(tok::l_paren) && Previous.isNot(tok::l_brace) && @@ -538,6 +554,17 @@ private: State.Stack.back().FirstLessLess = State.Column; if (Current.is(tok::question)) State.Stack.back().QuestionColumn = State.Column; + if (Current.is(tok::l_brace) && Current.MatchingParen != NULL && + Current.Children[0].isNot(tok::l_brace) && + !Current.MatchingParen->MustBreakBefore) { + AnnotatedToken *End = Current.MatchingParen; + while (!End->Children.empty() && !End->Children[0].CanBreakBefore) { + End = &End->Children[0]; + } + unsigned Length = End->TotalLength - Current.TotalLength + 1; + if (Length + State.Column > getColumnLimit()) + State.Stack.back().BreakAfterComma = true; + } // If we encounter an opening (, [, { or <, we add a level to our stacks to // prepare for the following tokens. @@ -545,16 +572,16 @@ private: Current.is(tok::l_brace) || State.NextToken->Type == TT_TemplateOpener) { unsigned NewIndent; + bool AvoidBinPacking; if (Current.is(tok::l_brace)) { - // FIXME: This does not work with nested static initializers. - // Implement a better handling for static initializers and similar - // constructs. - NewIndent = Line.Level * 2 + 2; + NewIndent = 2 + State.Stack.back().LastSpace; + AvoidBinPacking = false; } else { NewIndent = 4 + State.Stack.back().LastSpace; + AvoidBinPacking = !Style.BinPackParameters; } - State.Stack.push_back(ParenState(NewIndent, - State.Stack.back().LastSpace)); + State.Stack.push_back(ParenState(NewIndent, State.Stack.back().LastSpace, + AvoidBinPacking)); } // If we encounter a closing ), ], } or >, we can remove a level from our @@ -611,7 +638,8 @@ private: // Trying to insert a parameter on a new line if there are already more than // one parameter on the current line is bin packing. if (NewLine && State.NextToken->Parent->is(tok::comma) && - State.Stack.back().HasMultiParameterLine && !Style.BinPackParameters) + State.Stack.back().HasMultiParameterLine && + State.Stack.back().AvoidBinPacking) return UINT_MAX; if (!NewLine && (State.NextToken->Type == TT_CtorInitializerColon || (State.NextToken->Parent->ClosesTemplateDeclaration && diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index eabc8cff28..ecc9b4e468 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -206,6 +206,8 @@ public: } if (CurrentToken->is(tok::r_paren) || CurrentToken->is(tok::r_square)) return false; + if (CurrentToken->is(tok::comma)) + ++Left->ParameterCount; if (!consumeToken()) return false; } diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index 97358982cf..5ffd351889 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -506,13 +506,20 @@ TEST_F(FormatTest, CommentsInStaticInitializers) { " bbbbbbbbbbb, ccccccccccc };"); verifyGoogleFormat( "static SomeType type = { aaaaaaaaaaa, // comment for aa...\n" - " bbbbbbbbbbb,\n" - " ccccccccccc };"); + " bbbbbbbbbbb, ccccccccccc };"); verifyGoogleFormat("static SomeType type = { aaaaaaaaaaa,\n" " // comment for bb....\n" - " bbbbbbbbbbb,\n" - " ccccccccccc };"); + " bbbbbbbbbbb, ccccccccccc };"); + verifyFormat("S s = { { a, b, c }, // Group #1\n" + " { d, e, f }, // Group #2\n" + " { g, h, i } }; // Group #3"); + verifyFormat("S s = { { // Group #1\n" + " a, b, c },\n" + " { // Group #2\n" + " d, e, f },\n" + " { // Group #3\n" + " g, h, i } };"); } //===----------------------------------------------------------------------===// @@ -649,6 +656,12 @@ TEST_F(FormatTest, StaticInitializers) { "static SomeClass = { a, b, c, d, e, f, g, h, i, j,\n" " looooooooooooooooooooooooooooooooooongname,\n" " looooooooooooooooooooooooooooooong };"); + // Allow bin-packing in static initializers as this would often lead to + // terrible results, e.g.: + verifyGoogleFormat( + "static SomeClass = { a, b, c, d, e, f, g, h, i, j,\n" + " looooooooooooooooooooooooooooooooooongname,\n" + " looooooooooooooooooooooooooooooong };"); } TEST_F(FormatTest, NestedStaticInitializers) { @@ -657,7 +670,12 @@ TEST_F(FormatTest, NestedStaticInitializers) { "static A x = { { { init1, init2, init3, init4 },\n" " { init1, init2, init3, init4 } } };"); - // FIXME: Fix this in general and verify that it works in LLVM style again. + verifyFormat( + "somes Status::global_reps[3] = {\n" + " { kGlobalRef, OK_CODE, NULL, NULL, NULL },\n" + " { kGlobalRef, CANCELLED_CODE, NULL, NULL, NULL },\n" + " { kGlobalRef, UNKNOWN_CODE, NULL, NULL, NULL }\n" + "};"); verifyGoogleFormat( "somes Status::global_reps[3] = {\n" " { kGlobalRef, OK_CODE, NULL, NULL, NULL },\n" @@ -669,6 +687,13 @@ TEST_F(FormatTest, NestedStaticInitializers) { " { rect.fRight - rect.fLeft, rect.fBottom - rect.fTop" " } };"); + verifyFormat( + "SomeArrayOfSomeType a = { { { 1, 2, 3 }, { 1, 2, 3 },\n" + " { 111111111111111111111111111111,\n" + " 222222222222222222222222222222,\n" + " 333333333333333333333333333333 },\n" + " { 1, 2, 3 }, { 1, 2, 3 } } };"); + // FIXME: We might at some point want to handle this similar to parameter // lists, where we have an option to put each on a single line. verifyFormat("struct {\n" |