/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Format/FormatToken.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- FormatToken.cpp - Format C++ code --------------------------------===// |
2 | | // |
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 |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | /// |
9 | | /// \file |
10 | | /// This file implements specific functions of \c FormatTokens and their |
11 | | /// roles. |
12 | | /// |
13 | | //===----------------------------------------------------------------------===// |
14 | | |
15 | | #include "FormatToken.h" |
16 | | #include "ContinuationIndenter.h" |
17 | | #include "llvm/ADT/SmallVector.h" |
18 | | #include "llvm/Support/Debug.h" |
19 | | #include <climits> |
20 | | |
21 | | namespace clang { |
22 | | namespace format { |
23 | | |
24 | 0 | const char *getTokenTypeName(TokenType Type) { |
25 | 0 | static const char *const TokNames[] = { |
26 | 0 | #define TYPE(X) #X, |
27 | 0 | LIST_TOKEN_TYPES |
28 | 0 | #undef TYPE |
29 | 0 | nullptr}; |
30 | |
|
31 | 0 | if (Type < NUM_TOKEN_TYPES) |
32 | 0 | return TokNames[Type]; |
33 | 0 | llvm_unreachable("unknown TokenType"); |
34 | 0 | return nullptr; |
35 | 0 | } |
36 | | |
37 | | // FIXME: This is copy&pasted from Sema. Put it in a common place and remove |
38 | | // duplication. |
39 | 398k | bool FormatToken::isSimpleTypeSpecifier() const { |
40 | 398k | switch (Tok.getKind()) { |
41 | 21 | case tok::kw_short: |
42 | 427 | case tok::kw_long: |
43 | 427 | case tok::kw___int64: |
44 | 427 | case tok::kw___int128: |
45 | 427 | case tok::kw_signed: |
46 | 1.45k | case tok::kw_unsigned: |
47 | 14.4k | case tok::kw_void: |
48 | 15.2k | case tok::kw_char: |
49 | 48.7k | case tok::kw_int: |
50 | 48.7k | case tok::kw_half: |
51 | 49.2k | case tok::kw_float: |
52 | 49.6k | case tok::kw_double: |
53 | 49.6k | case tok::kw___bf16: |
54 | 49.6k | case tok::kw__Float16: |
55 | 49.6k | case tok::kw___float128: |
56 | 49.6k | case tok::kw___ibm128: |
57 | 49.6k | case tok::kw_wchar_t: |
58 | 51.0k | case tok::kw_bool: |
59 | 51.0k | case tok::kw___underlying_type: |
60 | 51.0k | case tok::annot_typename: |
61 | 51.0k | case tok::kw_char8_t: |
62 | 51.0k | case tok::kw_char16_t: |
63 | 51.0k | case tok::kw_char32_t: |
64 | 51.1k | case tok::kw_typeof: |
65 | 51.2k | case tok::kw_decltype: |
66 | 51.3k | case tok::kw__Atomic: |
67 | 51.3k | return true; |
68 | 347k | default: |
69 | 347k | return false; |
70 | 398k | } |
71 | 398k | } |
72 | | |
73 | 8.52k | bool FormatToken::isTypeOrIdentifier() const { |
74 | 8.52k | return isSimpleTypeSpecifier() || Tok.isOneOf(tok::kw_auto, tok::identifier)5.60k ; |
75 | 8.52k | } |
76 | | |
77 | 569k | bool FormatToken::opensBlockOrBlockTypeList(const FormatStyle &Style) const { |
78 | | // C# Does not indent object initialisers as continuations. |
79 | 569k | if (is(tok::l_brace) && getBlockKind() == BK_BracedInit99.3k && Style.isCSharp()56.0k ) |
80 | 1.24k | return true; |
81 | 567k | if (is(TT_TemplateString) && opensScope()124 ) |
82 | 50 | return true; |
83 | 567k | return is(TT_ArrayInitializerLSquare) || is(TT_ProtoExtensionLSquare)565k || |
84 | 567k | (565k is(tok::l_brace)565k && |
85 | 565k | (98.1k getBlockKind() == BK_Block98.1k || is(TT_DictLiteral)62.0k || |
86 | 98.1k | (55.6k !Style.Cpp11BracedListStyle55.6k && NestingLevel == 01.57k ))) || |
87 | 567k | (522k is(tok::less)522k && (14.3k Style.Language == FormatStyle::LK_Proto14.3k || |
88 | 14.3k | Style.Language == FormatStyle::LK_TextProto13.0k )); |
89 | 567k | } |
90 | | |
91 | 17.1k | TokenRole::~TokenRole() {} |
92 | | |
93 | 0 | void TokenRole::precomputeFormattingInfos(const FormatToken *Token) {} |
94 | | |
95 | | unsigned CommaSeparatedList::formatAfterToken(LineState &State, |
96 | | ContinuationIndenter *Indenter, |
97 | 142k | bool DryRun) { |
98 | 142k | if (State.NextToken == nullptr || !State.NextToken->Previous142k ) |
99 | 1 | return 0; |
100 | | |
101 | 142k | if (Formats.size() == 1) |
102 | 108 | return 0; // Handled by formatFromToken |
103 | | |
104 | | // Ensure that we start on the opening brace. |
105 | 142k | const FormatToken *LBrace = |
106 | 142k | State.NextToken->Previous->getPreviousNonComment(); |
107 | 142k | if (!LBrace || !LBrace->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) || |
108 | 142k | LBrace->is(BK_Block)16.6k || LBrace->is(TT_DictLiteral)16.0k || |
109 | 142k | LBrace->Next->is(TT_DesignatedInitializerPeriod)15.5k ) { |
110 | 126k | return 0; |
111 | 126k | } |
112 | | |
113 | | // Calculate the number of code points we have to format this list. As the |
114 | | // first token is already placed, we have to subtract it. |
115 | 15.5k | unsigned RemainingCodePoints = |
116 | 15.5k | Style.ColumnLimit - State.Column + State.NextToken->Previous->ColumnWidth; |
117 | | |
118 | | // Find the best ColumnFormat, i.e. the best number of columns to use. |
119 | 15.5k | const ColumnFormat *Format = getColumnFormat(RemainingCodePoints); |
120 | | |
121 | | // If no ColumnFormat can be used, the braced list would generally be |
122 | | // bin-packed. Add a severe penalty to this so that column layouts are |
123 | | // preferred if possible. |
124 | 15.5k | if (!Format) |
125 | 15.0k | return 10000; |
126 | | |
127 | | // Format the entire list. |
128 | 424 | unsigned Penalty = 0; |
129 | 424 | unsigned Column = 0; |
130 | 424 | unsigned Item = 0; |
131 | 20.1k | while (State.NextToken != LBrace->MatchingParen) { |
132 | 19.7k | bool NewLine = false; |
133 | 19.7k | unsigned ExtraSpaces = 0; |
134 | | |
135 | | // If the previous token was one of our commas, we are now on the next item. |
136 | 19.7k | if (Item < Commas.size() && State.NextToken->Previous == Commas[Item]19.1k ) { |
137 | 6.63k | if (!State.NextToken->isTrailingComment()) { |
138 | 6.42k | ExtraSpaces += Format->ColumnSizes[Column] - ItemLengths[Item]; |
139 | 6.42k | ++Column; |
140 | 6.42k | } |
141 | 6.63k | ++Item; |
142 | 6.63k | } |
143 | | |
144 | 19.7k | if (Column == Format->Columns || State.NextToken->MustBreakBefore19.1k ) { |
145 | 851 | Column = 0; |
146 | 851 | NewLine = true; |
147 | 851 | } |
148 | | |
149 | | // Place token using the continuation indenter and store the penalty. |
150 | 19.7k | Penalty += Indenter->addTokenToState(State, NewLine, DryRun, ExtraSpaces); |
151 | 19.7k | } |
152 | 424 | return Penalty; |
153 | 15.5k | } |
154 | | |
155 | | unsigned CommaSeparatedList::formatFromToken(LineState &State, |
156 | | ContinuationIndenter *Indenter, |
157 | 90.1k | bool DryRun) { |
158 | | // Formatting with 1 Column isn't really a column layout, so we don't need the |
159 | | // special logic here. We can just avoid bin packing any of the parameters. |
160 | 90.1k | if (Formats.size() == 1 || HasNestedBracedList90.0k ) |
161 | 2.13k | State.Stack.back().AvoidBinPacking = true; |
162 | 90.1k | return 0; |
163 | 90.1k | } |
164 | | |
165 | | // Returns the lengths in code points between Begin and End (both included), |
166 | | // assuming that the entire sequence is put on a single line. |
167 | | static unsigned CodePointsBetween(const FormatToken *Begin, |
168 | 12.5k | const FormatToken *End) { |
169 | 12.5k | assert(End->TotalLength >= Begin->TotalLength); |
170 | 0 | return End->TotalLength - Begin->TotalLength + Begin->ColumnWidth; |
171 | 12.5k | } |
172 | | |
173 | 5.96k | void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) { |
174 | | // FIXME: At some point we might want to do this for other lists, too. |
175 | 5.96k | if (!Token->MatchingParen || |
176 | 5.96k | !Token->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)5.95k ) { |
177 | 3.83k | return; |
178 | 3.83k | } |
179 | | |
180 | | // In C++11 braced list style, we should not format in columns unless they |
181 | | // have many items (20 or more) or we allow bin-packing of function call |
182 | | // arguments. |
183 | 2.13k | if (Style.Cpp11BracedListStyle && !Style.BinPackArguments1.96k && |
184 | 2.13k | Commas.size() < 1949 ) { |
185 | 46 | return; |
186 | 46 | } |
187 | | |
188 | | // Limit column layout for JavaScript array initializers to 20 or more items |
189 | | // for now to introduce it carefully. We can become more aggressive if this |
190 | | // necessary. |
191 | 2.09k | if (Token->is(TT_ArrayInitializerLSquare) && Commas.size() < 19149 ) |
192 | 145 | return; |
193 | | |
194 | | // Column format doesn't really make sense if we don't align after brackets. |
195 | 1.94k | if (Style.AlignAfterOpenBracket == FormatStyle::BAS_DontAlign) |
196 | 18 | return; |
197 | | |
198 | 1.92k | FormatToken *ItemBegin = Token->Next; |
199 | 1.97k | while (ItemBegin->isTrailingComment()) |
200 | 51 | ItemBegin = ItemBegin->Next; |
201 | 1.92k | SmallVector<bool, 8> MustBreakBeforeItem; |
202 | | |
203 | | // The lengths of an item if it is put at the end of the line. This includes |
204 | | // trailing comments which are otherwise ignored for column alignment. |
205 | 1.92k | SmallVector<unsigned, 8> EndOfLineItemLength; |
206 | 1.92k | MustBreakBeforeItem.reserve(Commas.size() + 1); |
207 | 1.92k | EndOfLineItemLength.reserve(Commas.size() + 1); |
208 | 1.92k | ItemLengths.reserve(Commas.size() + 1); |
209 | | |
210 | 1.92k | bool HasSeparatingComment = false; |
211 | 7.80k | for (unsigned i = 0, e = Commas.size() + 1; i != e; ++i5.88k ) { |
212 | 6.29k | assert(ItemBegin); |
213 | | // Skip comments on their own line. |
214 | 6.34k | while (ItemBegin->HasUnescapedNewline && ItemBegin->isTrailingComment()927 ) { |
215 | 52 | ItemBegin = ItemBegin->Next; |
216 | 52 | HasSeparatingComment = i > 0; |
217 | 52 | } |
218 | | |
219 | 6.29k | MustBreakBeforeItem.push_back(ItemBegin->MustBreakBefore); |
220 | 6.29k | if (ItemBegin->is(tok::l_brace)) |
221 | 669 | HasNestedBracedList = true; |
222 | 6.29k | const FormatToken *ItemEnd = nullptr; |
223 | 6.29k | if (i == Commas.size()) { |
224 | 1.67k | ItemEnd = Token->MatchingParen; |
225 | 1.67k | const FormatToken *NonCommentEnd = ItemEnd->getPreviousNonComment(); |
226 | 1.67k | ItemLengths.push_back(CodePointsBetween(ItemBegin, NonCommentEnd)); |
227 | 1.67k | if (Style.Cpp11BracedListStyle && |
228 | 1.67k | !ItemEnd->Previous->isTrailingComment()1.54k ) { |
229 | | // In Cpp11 braced list style, the } and possibly other subsequent |
230 | | // tokens will need to stay on a line with the last element. |
231 | 3.28k | while (ItemEnd->Next && !ItemEnd->Next->CanBreakBefore2.29k ) |
232 | 1.77k | ItemEnd = ItemEnd->Next; |
233 | 1.51k | } else { |
234 | | // In other braced lists styles, the "}" can be wrapped to the new line. |
235 | 159 | ItemEnd = Token->MatchingParen->Previous; |
236 | 159 | } |
237 | 4.62k | } else { |
238 | 4.62k | ItemEnd = Commas[i]; |
239 | | // The comma is counted as part of the item when calculating the length. |
240 | 4.62k | ItemLengths.push_back(CodePointsBetween(ItemBegin, ItemEnd)); |
241 | | |
242 | | // Consume trailing comments so the are included in EndOfLineItemLength. |
243 | 4.62k | if (ItemEnd->Next && !ItemEnd->Next->HasUnescapedNewline && |
244 | 4.62k | ItemEnd->Next->isTrailingComment()4.06k ) { |
245 | 141 | ItemEnd = ItemEnd->Next; |
246 | 141 | } |
247 | 4.62k | } |
248 | 6.29k | EndOfLineItemLength.push_back(CodePointsBetween(ItemBegin, ItemEnd)); |
249 | | // If there is a trailing comma in the list, the next item will start at the |
250 | | // closing brace. Don't create an extra item for this. |
251 | 6.29k | if (ItemEnd->getNextNonComment() == Token->MatchingParen) |
252 | 416 | break; |
253 | 5.88k | ItemBegin = ItemEnd->Next; |
254 | 5.88k | } |
255 | | |
256 | | // Don't use column layout for lists with few elements and in presence of |
257 | | // separating comments. |
258 | 1.92k | if (Commas.size() < 5 || HasSeparatingComment114 ) |
259 | 1.81k | return; |
260 | | |
261 | 111 | if (Token->NestingLevel != 0 && Token->is(tok::l_brace)26 && Commas.size() < 1924 ) |
262 | 21 | return; |
263 | | |
264 | | // We can never place more than ColumnLimit / 3 items in a row (because of the |
265 | | // spaces and the comma). |
266 | 90 | unsigned MaxItems = Style.ColumnLimit / 3; |
267 | 90 | SmallVector<unsigned> MinSizeInColumn; |
268 | 90 | MinSizeInColumn.reserve(MaxItems); |
269 | 1.04k | for (unsigned Columns = 1; Columns <= MaxItems; ++Columns959 ) { |
270 | 1.03k | ColumnFormat Format; |
271 | 1.03k | Format.Columns = Columns; |
272 | 1.03k | Format.ColumnSizes.resize(Columns); |
273 | 1.03k | MinSizeInColumn.assign(Columns, UINT_MAX); |
274 | 1.03k | Format.LineCount = 1; |
275 | 1.03k | bool HasRowWithSufficientColumns = false; |
276 | 1.03k | unsigned Column = 0; |
277 | 21.8k | for (unsigned i = 0, e = ItemLengths.size(); i != e; ++i20.7k ) { |
278 | 20.7k | assert(i < MustBreakBeforeItem.size()); |
279 | 20.7k | if (MustBreakBeforeItem[i] || Column == Columns20.2k ) { |
280 | 3.80k | ++Format.LineCount; |
281 | 3.80k | Column = 0; |
282 | 3.80k | } |
283 | 20.7k | if (Column == Columns - 1) |
284 | 3.68k | HasRowWithSufficientColumns = true; |
285 | 20.7k | unsigned Length = |
286 | 20.7k | (Column == Columns - 1) ? EndOfLineItemLength[i]3.68k : ItemLengths[i]17.1k ; |
287 | 20.7k | Format.ColumnSizes[Column] = std::max(Format.ColumnSizes[Column], Length); |
288 | 20.7k | MinSizeInColumn[Column] = std::min(MinSizeInColumn[Column], Length); |
289 | 20.7k | ++Column; |
290 | 20.7k | } |
291 | | // If all rows are terminated early (e.g. by trailing comments), we don't |
292 | | // need to look further. |
293 | 1.03k | if (!HasRowWithSufficientColumns) |
294 | 78 | break; |
295 | 959 | Format.TotalWidth = Columns - 1; // Width of the N-1 spaces. |
296 | | |
297 | 8.76k | for (unsigned i = 0; i < Columns; ++i7.80k ) |
298 | 7.80k | Format.TotalWidth += Format.ColumnSizes[i]; |
299 | | |
300 | | // Don't use this Format, if the difference between the longest and shortest |
301 | | // element in a column exceeds a threshold to avoid excessive spaces. |
302 | 959 | if ([&] { |
303 | 7.44k | for (unsigned i = 0; i < Columns - 1; ++i6.49k ) |
304 | 6.61k | if (Format.ColumnSizes[i] - MinSizeInColumn[i] > 10) |
305 | 129 | return true; |
306 | 830 | return false; |
307 | 959 | }()) { |
308 | 129 | continue; |
309 | 129 | } |
310 | | |
311 | | // Ignore layouts that are bound to violate the column limit. |
312 | 830 | if (Format.TotalWidth > Style.ColumnLimit && Columns > 1234 ) |
313 | 234 | continue; |
314 | | |
315 | 596 | Formats.push_back(Format); |
316 | 596 | } |
317 | 90 | } |
318 | | |
319 | | const CommaSeparatedList::ColumnFormat * |
320 | 15.5k | CommaSeparatedList::getColumnFormat(unsigned RemainingCharacters) const { |
321 | 15.5k | const ColumnFormat *BestFormat = nullptr; |
322 | 15.5k | for (const ColumnFormat &Format : llvm::reverse(Formats)) { |
323 | 1.83k | if (Format.TotalWidth <= RemainingCharacters || Format.Columns == 1485 ) { |
324 | 1.34k | if (BestFormat && Format.LineCount > BestFormat->LineCount923 ) |
325 | 424 | break; |
326 | 923 | BestFormat = &Format; |
327 | 923 | } |
328 | 1.83k | } |
329 | 15.5k | return BestFormat; |
330 | 15.5k | } |
331 | | |
332 | | } // namespace format |
333 | | } // namespace clang |