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)) return; FormatToken *ItemBegin = Token->Next; SmallVector<bool, 8> MustBreakBeforeItem; // The lengths of an item if it is put at the end of the line. This includes // trailing comments which are otherwise ignored for column alignment. SmallVector<unsigned, 8> EndOfLineItemLength; for (unsigned i = 0, e = Commas.size() + 1; i != e; ++i) { // Skip comments on their own line. while (ItemBegin->HasUnescapedNewline && ItemBegin->isTrailingComment()) ItemBegin = ItemBegin->Next; MustBreakBeforeItem.push_back(ItemBegin->MustBreakBefore); const FormatToken *ItemEnd = NULL; if (i == Commas.size()) { ItemEnd = Token->MatchingParen; const FormatToken *NonCommentEnd = ItemEnd->getPreviousNonComment(); ItemLengths.push_back(CodePointsBetween(ItemBegin, NonCommentEnd)); if (Style.Cpp11BracedListStyle) { // In Cpp11 braced list style, the } and possibly other subsequent // tokens will need to stay on a line with the last element. while (ItemEnd->Next && !ItemEnd->Next->CanBreakBefore) ItemEnd = ItemEnd->Next; } else { // In other braced lists styles, the "}" can be wrapped to the new line. ItemEnd = Token->MatchingParen->Previous; } } else { ItemEnd = Commas[i]; // The comma is counted as part of the item when calculating the length. ItemLengths.push_back(CodePointsBetween(ItemBegin, ItemEnd)); // Consume trailing comments so the are included in EndOfLineItemLength. if (ItemEnd->Next && !ItemEnd->Next->HasUnescapedNewline && ItemEnd->Next->isTrailingComment()) ItemEnd = ItemEnd->Next; } EndOfLineItemLength.push_back(CodePointsBetween(ItemBegin, ItemEnd)); // If there is a trailing comma in the list, the next item will start at the // closing brace. Don't create an extra item for this. if (ItemEnd->getNextNonComment() == Token->MatchingParen) break; ItemBegin = ItemEnd->Next; } // 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) { ColumnFormat Format; Format.Columns = Columns; Format.ColumnSizes.resize(Columns); Format.LineCount = 0; bool HasRowWithSufficientColumns = false; unsigned Column = 0; for (unsigned i = 0, e = ItemLengths.size(); i != e; ++i) { if (MustBreakBeforeItem[i] || Column == Columns) { ++Format.LineCount; Column = 0; } if (Column == Columns - 1) HasRowWithSufficientColumns = true; unsigned length = (Column == Columns - 1) ? EndOfLineItemLength[i] : ItemLengths[i]; Format.ColumnSizes[Column] = std::max(Format.ColumnSizes[Column], length); ++Column; } // If all rows are terminated early (e.g. by trailing comments), we don't // need to look further. if (!HasRowWithSufficientColumns) break; Format.TotalWidth = Columns - 1; // Width of the N-1 spaces. for (unsigned i = 0; i < Columns; ++i) { Format.TotalWidth += Format.ColumnSizes[i]; } // Ignore layouts that are bound to violate the column limit. if (Format.TotalWidth > Style.ColumnLimit) continue; Formats.push_back(Format); } }
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)) return; // In C++11 braced list style, we should not format in columns unless they // have many items (20 or more) or we allow bin-packing of function call // arguments. if (Style.Cpp11BracedListStyle && !Style.BinPackArguments && Commas.size() < 19) return; // Column format doesn't really make sense if we don't align after brackets. if (!Style.AlignAfterOpenBracket) return; FormatToken *ItemBegin = Token->Next; while (ItemBegin->isTrailingComment()) ItemBegin = ItemBegin->Next; SmallVector<bool, 8> MustBreakBeforeItem; // The lengths of an item if it is put at the end of the line. This includes // trailing comments which are otherwise ignored for column alignment. SmallVector<unsigned, 8> EndOfLineItemLength; bool HasSeparatingComment = false; for (unsigned i = 0, e = Commas.size() + 1; i != e; ++i) { // Skip comments on their own line. while (ItemBegin->HasUnescapedNewline && ItemBegin->isTrailingComment()) { ItemBegin = ItemBegin->Next; HasSeparatingComment = i > 0; } MustBreakBeforeItem.push_back(ItemBegin->MustBreakBefore); if (ItemBegin->is(tok::l_brace)) HasNestedBracedList = true; const FormatToken *ItemEnd = nullptr; if (i == Commas.size()) { ItemEnd = Token->MatchingParen; const FormatToken *NonCommentEnd = ItemEnd->getPreviousNonComment(); ItemLengths.push_back(CodePointsBetween(ItemBegin, NonCommentEnd)); if (Style.Cpp11BracedListStyle) { // In Cpp11 braced list style, the } and possibly other subsequent // tokens will need to stay on a line with the last element. while (ItemEnd->Next && !ItemEnd->Next->CanBreakBefore) ItemEnd = ItemEnd->Next; } else { // In other braced lists styles, the "}" can be wrapped to the new line. ItemEnd = Token->MatchingParen->Previous; } } else { ItemEnd = Commas[i]; // The comma is counted as part of the item when calculating the length. ItemLengths.push_back(CodePointsBetween(ItemBegin, ItemEnd)); // Consume trailing comments so the are included in EndOfLineItemLength. if (ItemEnd->Next && !ItemEnd->Next->HasUnescapedNewline && ItemEnd->Next->isTrailingComment()) ItemEnd = ItemEnd->Next; } EndOfLineItemLength.push_back(CodePointsBetween(ItemBegin, ItemEnd)); // If there is a trailing comma in the list, the next item will start at the // closing brace. Don't create an extra item for this. if (ItemEnd->getNextNonComment() == Token->MatchingParen) break; ItemBegin = ItemEnd->Next; } // Don't use column layout for nested lists, lists with few elements and in // presence of separating comments. if (Token->NestingLevel != 0 || Commas.size() < 5 || HasSeparatingComment) return; // We can never place more than ColumnLimit / 3 items in a row (because of the // spaces and the comma). unsigned MaxItems = Style.ColumnLimit / 3; std::vector<unsigned> MinSizeInColumn; MinSizeInColumn.reserve(MaxItems); for (unsigned Columns = 1; Columns <= MaxItems; ++Columns) { ColumnFormat Format; Format.Columns = Columns; Format.ColumnSizes.resize(Columns); MinSizeInColumn.assign(Columns, UINT_MAX); Format.LineCount = 1; bool HasRowWithSufficientColumns = false; unsigned Column = 0; for (unsigned i = 0, e = ItemLengths.size(); i != e; ++i) { assert(i < MustBreakBeforeItem.size()); if (MustBreakBeforeItem[i] || Column == Columns) { ++Format.LineCount; Column = 0; } if (Column == Columns - 1) HasRowWithSufficientColumns = true; unsigned Length = (Column == Columns - 1) ? EndOfLineItemLength[i] : ItemLengths[i]; Format.ColumnSizes[Column] = std::max(Format.ColumnSizes[Column], Length); MinSizeInColumn[Column] = std::min(MinSizeInColumn[Column], Length); ++Column; } // If all rows are terminated early (e.g. by trailing comments), we don't // need to look further. if (!HasRowWithSufficientColumns) break; Format.TotalWidth = Columns - 1; // Width of the N-1 spaces. for (unsigned i = 0; i < Columns; ++i) Format.TotalWidth += Format.ColumnSizes[i]; // Don't use this Format, if the difference between the longest and shortest // element in a column exceeds a threshold to avoid excessive spaces. if ([&] { for (unsigned i = 0; i < Columns - 1; ++i) if (Format.ColumnSizes[i] - MinSizeInColumn[i] > 10) return true; return false; }()) continue; // Ignore layouts that are bound to violate the column limit. if (Format.TotalWidth > Style.ColumnLimit) continue; Formats.push_back(Format); } }