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;
}
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
/// \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 {
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)
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);
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.
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) &&
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.
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
// 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 &&
" 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 } };");
}
//===----------------------------------------------------------------------===//
"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) {
"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"
" { 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"