1 //===--- FormatToken.cpp - Format C++ code --------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 /// This file implements specific functions of \c FormatTokens and their
13 //===----------------------------------------------------------------------===//
15 #include "FormatToken.h"
16 #include "ContinuationIndenter.h"
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/Support/Debug.h"
24 const char *getTokenTypeName(TokenType Type
) {
25 static const char *const TokNames
[] = {
31 if (Type
< NUM_TOKEN_TYPES
)
32 return TokNames
[Type
];
33 llvm_unreachable("unknown TokenType");
37 // FIXME: This is copy&pasted from Sema. Put it in a common place and remove
39 bool FormatToken::isSimpleTypeSpecifier() const {
40 switch (Tok
.getKind()) {
44 case tok::kw___int128
:
46 case tok::kw_unsigned
:
54 case tok::kw__Float16
:
55 case tok::kw___float128
:
56 case tok::kw___ibm128
:
59 #define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
60 #include "clang/Basic/TransformTypeTraits.def"
61 case tok::annot_typename
:
63 case tok::kw_char16_t
:
64 case tok::kw_char32_t
:
66 case tok::kw_decltype
:
74 bool FormatToken::isTypeOrIdentifier() const {
75 return isSimpleTypeSpecifier() || Tok
.isOneOf(tok::kw_auto
, tok::identifier
);
78 bool FormatToken::isBlockIndentedInitRBrace(const FormatStyle
&Style
) const {
79 assert(is(tok::r_brace
));
80 if (!Style
.Cpp11BracedListStyle
||
81 Style
.AlignAfterOpenBracket
!= FormatStyle::BAS_BlockIndent
) {
84 const auto *LBrace
= MatchingParen
;
85 assert(LBrace
&& LBrace
->is(tok::l_brace
));
86 if (LBrace
->is(BK_BracedInit
))
88 if (LBrace
->Previous
&& LBrace
->Previous
->is(tok::equal
))
93 bool FormatToken::opensBlockOrBlockTypeList(const FormatStyle
&Style
) const {
94 // C# Does not indent object initialisers as continuations.
95 if (is(tok::l_brace
) && getBlockKind() == BK_BracedInit
&& Style
.isCSharp())
97 if (is(TT_TemplateString
) && opensScope())
99 return is(TT_ArrayInitializerLSquare
) || is(TT_ProtoExtensionLSquare
) ||
101 (getBlockKind() == BK_Block
|| is(TT_DictLiteral
) ||
102 (!Style
.Cpp11BracedListStyle
&& NestingLevel
== 0))) ||
103 (is(tok::less
) && Style
.isProto());
106 TokenRole::~TokenRole() {}
108 void TokenRole::precomputeFormattingInfos(const FormatToken
*Token
) {}
110 unsigned CommaSeparatedList::formatAfterToken(LineState
&State
,
111 ContinuationIndenter
*Indenter
,
113 if (!State
.NextToken
|| !State
.NextToken
->Previous
)
116 if (Formats
.size() == 1)
117 return 0; // Handled by formatFromToken
119 // Ensure that we start on the opening brace.
120 const FormatToken
*LBrace
=
121 State
.NextToken
->Previous
->getPreviousNonComment();
122 if (!LBrace
|| !LBrace
->isOneOf(tok::l_brace
, TT_ArrayInitializerLSquare
) ||
123 LBrace
->is(BK_Block
) || LBrace
->is(TT_DictLiteral
) ||
124 LBrace
->Next
->is(TT_DesignatedInitializerPeriod
)) {
128 // Calculate the number of code points we have to format this list. As the
129 // first token is already placed, we have to subtract it.
130 unsigned RemainingCodePoints
=
131 Style
.ColumnLimit
- State
.Column
+ State
.NextToken
->Previous
->ColumnWidth
;
133 // Find the best ColumnFormat, i.e. the best number of columns to use.
134 const ColumnFormat
*Format
= getColumnFormat(RemainingCodePoints
);
136 // If no ColumnFormat can be used, the braced list would generally be
137 // bin-packed. Add a severe penalty to this so that column layouts are
138 // preferred if possible.
142 // Format the entire list.
143 unsigned Penalty
= 0;
146 while (State
.NextToken
!= LBrace
->MatchingParen
) {
147 bool NewLine
= false;
148 unsigned ExtraSpaces
= 0;
150 // If the previous token was one of our commas, we are now on the next item.
151 if (Item
< Commas
.size() && State
.NextToken
->Previous
== Commas
[Item
]) {
152 if (!State
.NextToken
->isTrailingComment()) {
153 ExtraSpaces
+= Format
->ColumnSizes
[Column
] - ItemLengths
[Item
];
159 if (Column
== Format
->Columns
|| State
.NextToken
->MustBreakBefore
) {
164 // Place token using the continuation indenter and store the penalty.
165 Penalty
+= Indenter
->addTokenToState(State
, NewLine
, DryRun
, ExtraSpaces
);
170 unsigned CommaSeparatedList::formatFromToken(LineState
&State
,
171 ContinuationIndenter
*Indenter
,
173 // Formatting with 1 Column isn't really a column layout, so we don't need the
174 // special logic here. We can just avoid bin packing any of the parameters.
175 if (Formats
.size() == 1 || HasNestedBracedList
)
176 State
.Stack
.back().AvoidBinPacking
= true;
180 // Returns the lengths in code points between Begin and End (both included),
181 // assuming that the entire sequence is put on a single line.
182 static unsigned CodePointsBetween(const FormatToken
*Begin
,
183 const FormatToken
*End
) {
184 assert(End
->TotalLength
>= Begin
->TotalLength
);
185 return End
->TotalLength
- Begin
->TotalLength
+ Begin
->ColumnWidth
;
188 void CommaSeparatedList::precomputeFormattingInfos(const FormatToken
*Token
) {
189 // FIXME: At some point we might want to do this for other lists, too.
190 if (!Token
->MatchingParen
||
191 !Token
->isOneOf(tok::l_brace
, TT_ArrayInitializerLSquare
)) {
195 // In C++11 braced list style, we should not format in columns unless they
196 // have many items (20 or more) or we allow bin-packing of function call
198 if (Style
.Cpp11BracedListStyle
&& !Style
.BinPackArguments
&&
199 Commas
.size() < 19) {
203 // Limit column layout for JavaScript array initializers to 20 or more items
204 // for now to introduce it carefully. We can become more aggressive if this
206 if (Token
->is(TT_ArrayInitializerLSquare
) && Commas
.size() < 19)
209 // Column format doesn't really make sense if we don't align after brackets.
210 if (Style
.AlignAfterOpenBracket
== FormatStyle::BAS_DontAlign
)
213 FormatToken
*ItemBegin
= Token
->Next
;
214 while (ItemBegin
->isTrailingComment())
215 ItemBegin
= ItemBegin
->Next
;
216 SmallVector
<bool, 8> MustBreakBeforeItem
;
218 // The lengths of an item if it is put at the end of the line. This includes
219 // trailing comments which are otherwise ignored for column alignment.
220 SmallVector
<unsigned, 8> EndOfLineItemLength
;
221 MustBreakBeforeItem
.reserve(Commas
.size() + 1);
222 EndOfLineItemLength
.reserve(Commas
.size() + 1);
223 ItemLengths
.reserve(Commas
.size() + 1);
225 bool HasSeparatingComment
= false;
226 for (unsigned i
= 0, e
= Commas
.size() + 1; i
!= e
; ++i
) {
228 // Skip comments on their own line.
229 while (ItemBegin
->HasUnescapedNewline
&& ItemBegin
->isTrailingComment()) {
230 ItemBegin
= ItemBegin
->Next
;
231 HasSeparatingComment
= i
> 0;
234 MustBreakBeforeItem
.push_back(ItemBegin
->MustBreakBefore
);
235 if (ItemBegin
->is(tok::l_brace
))
236 HasNestedBracedList
= true;
237 const FormatToken
*ItemEnd
= nullptr;
238 if (i
== Commas
.size()) {
239 ItemEnd
= Token
->MatchingParen
;
240 const FormatToken
*NonCommentEnd
= ItemEnd
->getPreviousNonComment();
241 ItemLengths
.push_back(CodePointsBetween(ItemBegin
, NonCommentEnd
));
242 if (Style
.Cpp11BracedListStyle
&&
243 !ItemEnd
->Previous
->isTrailingComment()) {
244 // In Cpp11 braced list style, the } and possibly other subsequent
245 // tokens will need to stay on a line with the last element.
246 while (ItemEnd
->Next
&& !ItemEnd
->Next
->CanBreakBefore
)
247 ItemEnd
= ItemEnd
->Next
;
249 // In other braced lists styles, the "}" can be wrapped to the new line.
250 ItemEnd
= Token
->MatchingParen
->Previous
;
254 // The comma is counted as part of the item when calculating the length.
255 ItemLengths
.push_back(CodePointsBetween(ItemBegin
, ItemEnd
));
257 // Consume trailing comments so the are included in EndOfLineItemLength.
258 if (ItemEnd
->Next
&& !ItemEnd
->Next
->HasUnescapedNewline
&&
259 ItemEnd
->Next
->isTrailingComment()) {
260 ItemEnd
= ItemEnd
->Next
;
263 EndOfLineItemLength
.push_back(CodePointsBetween(ItemBegin
, ItemEnd
));
264 // If there is a trailing comma in the list, the next item will start at the
265 // closing brace. Don't create an extra item for this.
266 if (ItemEnd
->getNextNonComment() == Token
->MatchingParen
)
268 ItemBegin
= ItemEnd
->Next
;
271 // Don't use column layout for lists with few elements and in presence of
272 // separating comments.
273 if (Commas
.size() < 5 || HasSeparatingComment
)
276 if (Token
->NestingLevel
!= 0 && Token
->is(tok::l_brace
) && Commas
.size() < 19)
279 // We can never place more than ColumnLimit / 3 items in a row (because of the
280 // spaces and the comma).
281 unsigned MaxItems
= Style
.ColumnLimit
/ 3;
282 SmallVector
<unsigned> MinSizeInColumn
;
283 MinSizeInColumn
.reserve(MaxItems
);
284 for (unsigned Columns
= 1; Columns
<= MaxItems
; ++Columns
) {
286 Format
.Columns
= Columns
;
287 Format
.ColumnSizes
.resize(Columns
);
288 MinSizeInColumn
.assign(Columns
, UINT_MAX
);
289 Format
.LineCount
= 1;
290 bool HasRowWithSufficientColumns
= false;
292 for (unsigned i
= 0, e
= ItemLengths
.size(); i
!= e
; ++i
) {
293 assert(i
< MustBreakBeforeItem
.size());
294 if (MustBreakBeforeItem
[i
] || Column
== Columns
) {
298 if (Column
== Columns
- 1)
299 HasRowWithSufficientColumns
= true;
301 (Column
== Columns
- 1) ? EndOfLineItemLength
[i
] : ItemLengths
[i
];
302 Format
.ColumnSizes
[Column
] = std::max(Format
.ColumnSizes
[Column
], Length
);
303 MinSizeInColumn
[Column
] = std::min(MinSizeInColumn
[Column
], Length
);
306 // If all rows are terminated early (e.g. by trailing comments), we don't
307 // need to look further.
308 if (!HasRowWithSufficientColumns
)
310 Format
.TotalWidth
= Columns
- 1; // Width of the N-1 spaces.
312 for (unsigned i
= 0; i
< Columns
; ++i
)
313 Format
.TotalWidth
+= Format
.ColumnSizes
[i
];
315 // Don't use this Format, if the difference between the longest and shortest
316 // element in a column exceeds a threshold to avoid excessive spaces.
318 for (unsigned i
= 0; i
< Columns
- 1; ++i
)
319 if (Format
.ColumnSizes
[i
] - MinSizeInColumn
[i
] > 10)
326 // Ignore layouts that are bound to violate the column limit.
327 if (Format
.TotalWidth
> Style
.ColumnLimit
&& Columns
> 1)
330 Formats
.push_back(Format
);
334 const CommaSeparatedList::ColumnFormat
*
335 CommaSeparatedList::getColumnFormat(unsigned RemainingCharacters
) const {
336 const ColumnFormat
*BestFormat
= nullptr;
337 for (const ColumnFormat
&Format
: llvm::reverse(Formats
)) {
338 if (Format
.TotalWidth
<= RemainingCharacters
|| Format
.Columns
== 1) {
339 if (BestFormat
&& Format
.LineCount
> BestFormat
->LineCount
)
341 BestFormat
= &Format
;
347 } // namespace format