Penalty += Style.PenaltyExcessCharacter * ExcessCharacters;
}
+ if (Current.Role)
+ Current.Role->formatFromToken(State, this, DryRun);
// If the previous has a special role, let it consume tokens as appropriate.
// It is necessary to start at the previous token for the only implemented
// role (comma separated list). That way, the decision whether or not to break
// after the "{" is already done and both options are tried and evaluated.
// FIXME: This is ugly, find a better way.
if (Previous && Previous->Role)
- Penalty += Previous->Role->format(State, this, DryRun);
+ Penalty += Previous->Role->formatAfterToken(State, this, DryRun);
return Penalty;
}
void TokenRole::precomputeFormattingInfos(const FormatToken *Token) {}
-unsigned CommaSeparatedList::format(LineState &State,
- ContinuationIndenter *Indenter,
- bool DryRun) {
- if (!State.NextToken->Previous || !State.NextToken->Previous->Previous ||
- Commas.size() <= 2)
+unsigned CommaSeparatedList::formatAfterToken(LineState &State,
+ ContinuationIndenter *Indenter,
+ bool DryRun) {
+ if (!State.NextToken->Previous || !State.NextToken->Previous->Previous)
return 0;
// Ensure that we start on the opening brace.
return Penalty;
}
+unsigned CommaSeparatedList::formatFromToken(LineState &State,
+ ContinuationIndenter *Indenter,
+ bool DryRun) {
+ if (HasNestedBracedList)
+ State.Stack.back().AvoidBinPacking = true;
+ return 0;
+}
+
// Returns the lengths in code points between Begin and End (both included),
// assuming that the entire sequence is put on a single line.
static unsigned CodePointsBetween(const FormatToken *Begin,
void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
// FIXME: At some point we might want to do this for other lists, too.
- if (!Token->MatchingParen || Token->isNot(tok::l_brace) ||
- Token->NestingLevel != 0)
+ if (!Token->MatchingParen || Token->isNot(tok::l_brace))
return;
FormatToken *ItemBegin = Token->Next;
// trailing comments which are otherwise ignored for column alignment.
SmallVector<unsigned, 8> EndOfLineItemLength;
- bool HasNestedBracedList = false;
for (unsigned i = 0, e = Commas.size() + 1; i != e; ++i) {
// Skip comments on their own line.
while (ItemBegin->HasUnescapedNewline && ItemBegin->isTrailingComment())
ItemBegin = ItemEnd->Next;
}
+ // If this doesn't have a nested list, we require at least 6 elements in order
+ // create a column layout. If it has a nested list, column layout ensures one
+ // list element per line.
+ if (HasNestedBracedList || Commas.size() < 5 ||
+ Token->NestingLevel != 0)
+ return;
+
// We can never place more than ColumnLimit / 3 items in a row (because of the
// spaces and the comma).
for (unsigned Columns = 1; Columns <= Style.ColumnLimit / 3; ++Columns) {
if (Format.TotalWidth > Style.ColumnLimit)
continue;
- // If this braced list has nested braced list, we format it either with one
- // element per line or with all elements on one line.
- if (HasNestedBracedList && Columns > 1 && Format.LineCount > 1)
- continue;
-
Formats.push_back(Format);
}
}
/// \brief Apply the special formatting that the given role demands.
///
+ /// Assumes that the token having this role is already formatted.
+ ///
/// Continues formatting from \p State leaving indentation to \p Indenter and
/// returns the total penalty that this formatting incurs.
- virtual unsigned format(LineState &State, ContinuationIndenter *Indenter,
- bool DryRun) {
+ virtual unsigned formatFromToken(LineState &State,
+ ContinuationIndenter *Indenter,
+ bool DryRun) {
+ return 0;
+ }
+
+ /// \brief Same as \c formatFromToken, but assumes that the first token has
+ /// already been set thereby deciding on the first line break.
+ virtual unsigned formatAfterToken(LineState &State,
+ ContinuationIndenter *Indenter,
+ bool DryRun) {
return 0;
}
class CommaSeparatedList : public TokenRole {
public:
- CommaSeparatedList(const FormatStyle &Style) : TokenRole(Style) {}
+ CommaSeparatedList(const FormatStyle &Style)
+ : TokenRole(Style), HasNestedBracedList(false) {}
virtual void precomputeFormattingInfos(const FormatToken *Token);
- virtual unsigned format(LineState &State, ContinuationIndenter *Indenter,
- bool DryRun);
+ virtual unsigned formatAfterToken(LineState &State,
+ ContinuationIndenter *Indenter,
+ bool DryRun);
+
+ virtual unsigned formatFromToken(LineState &State,
+ ContinuationIndenter *Indenter, bool DryRun);
/// \brief Adds \p Token as the next comma to the \c CommaSeparated list.
virtual void CommaFound(const FormatToken *Token) { Commas.push_back(Token); }
/// \brief Precomputed formats that can be used for this list.
SmallVector<ColumnFormat, 4> Formats;
+
+ bool HasNestedBracedList;
};
} // namespace format
" } };");
verifyFormat(
- "SomeArrayOfSomeType a = { { { 1, 2, 3 }, { 1, 2, 3 },\n"
+ "SomeArrayOfSomeType a = { { { 1, 2, 3 },\n"
+ " { 1, 2, 3 },\n"
" { 111111111111111111111111111111,\n"
" 222222222222222222222222222222,\n"
" 333333333333333333333333333333 },\n"
- " { 1, 2, 3 }, { 1, 2, 3 } } };");
+ " { 1, 2, 3 },\n"
+ " { 1, 2, 3 } } };");
verifyFormat(
- "SomeArrayOfSomeType a = { { { 1, 2, 3 } }, { { 1, 2, 3 } },\n"
+ "SomeArrayOfSomeType a = { { { 1, 2, 3 } },\n"
+ " { { 1, 2, 3 } },\n"
" { { 111111111111111111111111111111,\n"
" 222222222222222222222222222222,\n"
" 333333333333333333333333333333 } },\n"
- " { { 1, 2, 3 } }, { { 1, 2, 3 } } };");
+ " { { 1, 2, 3 } },\n"
+ " { { 1, 2, 3 } } };");
verifyGoogleFormat(
"SomeArrayOfSomeType a = {\n"
- " {{1, 2, 3}}, {{1, 2, 3}},\n"
+ " {{1, 2, 3}},\n"
+ " {{1, 2, 3}},\n"
" {{111111111111111111111111111111, 222222222222222222222222222222,\n"
" 333333333333333333333333333333}},\n"
- " {{1, 2, 3}}, {{1, 2, 3}}};");
+ " {{1, 2, 3}},\n"
+ " {{1, 2, 3}}};");
verifyFormat(
"struct {\n"
" { aaaaaaaaaaaaaaaaa } };",
getLLVMStyleWithColumns(60));
- // No column layout for nested lists.
+ // With nested lists, we should either format one item per line or all nested
+ // lists one one line.
// FIXME: For some nested lists, we can do better.
verifyFormat(
"SomeStruct my_struct_array = {\n"
" { aaaaaa, aaaaaaaa, aaaaaaaaaa, aaaaaaaaa, aaaaaaaaa, aaaaaaaaaa,\n"
" aaaaaaaaaaaaa, aaaaaaa, aaa },\n"
+ " { aaa, aaa },\n"
+ " { aaa, aaa },\n"
" { aaaa, aaaa, aaaa, aaaa, aaaa, aaaa, aaaa, aaa },\n"
" { aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaa, a, aaaaaaaaaa, aaaaaaaaa, aaa },\n"
"};");
+
+ // No column layout should be used here.
+ verifyFormat("aaaaaaaaaaaaaaa = { aaaaaaaaaaaaaaaaaaaaaaaaaaa, 0, 0,\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb };");
}
TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) {