Coverage Report

Created: 2022-01-22 13:19

/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
303k
bool FormatToken::isSimpleTypeSpecifier() const {
40
303k
  switch (Tok.getKind()) {
41
17
  case tok::kw_short:
42
357
  case tok::kw_long:
43
357
  case tok::kw___int64:
44
357
  case tok::kw___int128:
45
357
  case tok::kw_signed:
46
985
  case tok::kw_unsigned:
47
11.7k
  case tok::kw_void:
48
12.3k
  case tok::kw_char:
49
40.3k
  case tok::kw_int:
50
40.3k
  case tok::kw_half:
51
40.6k
  case tok::kw_float:
52
41.0k
  case tok::kw_double:
53
41.0k
  case tok::kw___bf16:
54
41.0k
  case tok::kw__Float16:
55
41.0k
  case tok::kw___float128:
56
41.0k
  case tok::kw___ibm128:
57
41.0k
  case tok::kw_wchar_t:
58
42.1k
  case tok::kw_bool:
59
42.1k
  case tok::kw___underlying_type:
60
42.1k
  case tok::annot_typename:
61
42.1k
  case tok::kw_char8_t:
62
42.1k
  case tok::kw_char16_t:
63
42.1k
  case tok::kw_char32_t:
64
42.2k
  case tok::kw_typeof:
65
42.3k
  case tok::kw_decltype:
66
42.4k
  case tok::kw__Atomic:
67
42.4k
    return true;
68
260k
  default:
69
260k
    return false;
70
303k
  }
71
303k
}
72
73
7.71k
bool FormatToken::isTypeOrIdentifier() const {
74
7.71k
  return isSimpleTypeSpecifier() || 
Tok.isOneOf(tok::kw_auto, tok::identifier)5.04k
;
75
7.71k
}
76
77
13.0k
TokenRole::~TokenRole() {}
78
79
0
void TokenRole::precomputeFormattingInfos(const FormatToken *Token) {}
80
81
unsigned CommaSeparatedList::formatAfterToken(LineState &State,
82
                                              ContinuationIndenter *Indenter,
83
138k
                                              bool DryRun) {
84
138k
  if (State.NextToken == nullptr || 
!State.NextToken->Previous138k
)
85
1
    return 0;
86
87
138k
  if (Formats.size() == 1)
88
108
    return 0; // Handled by formatFromToken
89
90
  // Ensure that we start on the opening brace.
91
138k
  const FormatToken *LBrace =
92
138k
      State.NextToken->Previous->getPreviousNonComment();
93
138k
  if (!LBrace || !LBrace->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
94
138k
      
LBrace->is(BK_Block)13.9k
||
LBrace->is(TT_DictLiteral)13.4k
||
95
138k
      
LBrace->Next->is(TT_DesignatedInitializerPeriod)12.9k
)
96
125k
    return 0;
97
98
  // Calculate the number of code points we have to format this list. As the
99
  // first token is already placed, we have to subtract it.
100
12.9k
  unsigned RemainingCodePoints =
101
12.9k
      Style.ColumnLimit - State.Column + State.NextToken->Previous->ColumnWidth;
102
103
  // Find the best ColumnFormat, i.e. the best number of columns to use.
104
12.9k
  const ColumnFormat *Format = getColumnFormat(RemainingCodePoints);
105
106
  // If no ColumnFormat can be used, the braced list would generally be
107
  // bin-packed. Add a severe penalty to this so that column layouts are
108
  // preferred if possible.
109
12.9k
  if (!Format)
110
12.4k
    return 10000;
111
112
  // Format the entire list.
113
424
  unsigned Penalty = 0;
114
424
  unsigned Column = 0;
115
424
  unsigned Item = 0;
116
20.1k
  while (State.NextToken != LBrace->MatchingParen) {
117
19.7k
    bool NewLine = false;
118
19.7k
    unsigned ExtraSpaces = 0;
119
120
    // If the previous token was one of our commas, we are now on the next item.
121
19.7k
    if (Item < Commas.size() && 
State.NextToken->Previous == Commas[Item]19.1k
) {
122
6.63k
      if (!State.NextToken->isTrailingComment()) {
123
6.42k
        ExtraSpaces += Format->ColumnSizes[Column] - ItemLengths[Item];
124
6.42k
        ++Column;
125
6.42k
      }
126
6.63k
      ++Item;
127
6.63k
    }
128
129
19.7k
    if (Column == Format->Columns || 
State.NextToken->MustBreakBefore19.1k
) {
130
851
      Column = 0;
131
851
      NewLine = true;
132
851
    }
133
134
    // Place token using the continuation indenter and store the penalty.
135
19.7k
    Penalty += Indenter->addTokenToState(State, NewLine, DryRun, ExtraSpaces);
136
19.7k
  }
137
424
  return Penalty;
138
12.9k
}
139
140
unsigned CommaSeparatedList::formatFromToken(LineState &State,
141
                                             ContinuationIndenter *Indenter,
142
85.2k
                                             bool DryRun) {
143
  // Formatting with 1 Column isn't really a column layout, so we don't need the
144
  // special logic here. We can just avoid bin packing any of the parameters.
145
85.2k
  if (Formats.size() == 1 || 
HasNestedBracedList85.1k
)
146
1.67k
    State.Stack.back().AvoidBinPacking = true;
147
85.2k
  return 0;
148
85.2k
}
149
150
// Returns the lengths in code points between Begin and End (both included),
151
// assuming that the entire sequence is put on a single line.
152
static unsigned CodePointsBetween(const FormatToken *Begin,
153
11.5k
                                  const FormatToken *End) {
154
11.5k
  assert(End->TotalLength >= Begin->TotalLength);
155
0
  return End->TotalLength - Begin->TotalLength + Begin->ColumnWidth;
156
11.5k
}
157
158
5.52k
void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
159
  // FIXME: At some point we might want to do this for other lists, too.
160
5.52k
  if (!Token->MatchingParen ||
161
5.52k
      
!Token->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)5.50k
)
162
3.56k
    return;
163
164
  // In C++11 braced list style, we should not format in columns unless they
165
  // have many items (20 or more) or we allow bin-packing of function call
166
  // arguments.
167
1.95k
  if (Style.Cpp11BracedListStyle && 
!Style.BinPackArguments1.78k
&&
168
1.95k
      
Commas.size() < 1934
)
169
31
    return;
170
171
  // Limit column layout for JavaScript array initializers to 20 or more items
172
  // for now to introduce it carefully. We can become more aggressive if this
173
  // necessary.
174
1.92k
  if (Token->is(TT_ArrayInitializerLSquare) && 
Commas.size() < 19149
)
175
145
    return;
176
177
  // Column format doesn't really make sense if we don't align after brackets.
178
1.77k
  if (Style.AlignAfterOpenBracket == FormatStyle::BAS_DontAlign)
179
18
    return;
180
181
1.76k
  FormatToken *ItemBegin = Token->Next;
182
1.80k
  while (ItemBegin->isTrailingComment())
183
42
    ItemBegin = ItemBegin->Next;
184
1.76k
  SmallVector<bool, 8> MustBreakBeforeItem;
185
186
  // The lengths of an item if it is put at the end of the line. This includes
187
  // trailing comments which are otherwise ignored for column alignment.
188
1.76k
  SmallVector<unsigned, 8> EndOfLineItemLength;
189
190
1.76k
  bool HasSeparatingComment = false;
191
7.16k
  for (unsigned i = 0, e = Commas.size() + 1; i != e; 
++i5.40k
) {
192
    // Skip comments on their own line.
193
5.82k
    while (ItemBegin->HasUnescapedNewline && 
ItemBegin->isTrailingComment()846
) {
194
43
      ItemBegin = ItemBegin->Next;
195
43
      HasSeparatingComment = i > 0;
196
43
    }
197
198
5.78k
    MustBreakBeforeItem.push_back(ItemBegin->MustBreakBefore);
199
5.78k
    if (ItemBegin->is(tok::l_brace))
200
543
      HasNestedBracedList = true;
201
5.78k
    const FormatToken *ItemEnd = nullptr;
202
5.78k
    if (i == Commas.size()) {
203
1.53k
      ItemEnd = Token->MatchingParen;
204
1.53k
      const FormatToken *NonCommentEnd = ItemEnd->getPreviousNonComment();
205
1.53k
      ItemLengths.push_back(CodePointsBetween(ItemBegin, NonCommentEnd));
206
1.53k
      if (Style.Cpp11BracedListStyle &&
207
1.53k
          
!ItemEnd->Previous->isTrailingComment()1.41k
) {
208
        // In Cpp11 braced list style, the } and possibly other subsequent
209
        // tokens will need to stay on a line with the last element.
210
2.98k
        while (ItemEnd->Next && 
!ItemEnd->Next->CanBreakBefore2.06k
)
211
1.60k
          ItemEnd = ItemEnd->Next;
212
1.37k
      } else {
213
        // In other braced lists styles, the "}" can be wrapped to the new line.
214
156
        ItemEnd = Token->MatchingParen->Previous;
215
156
      }
216
4.25k
    } else {
217
4.25k
      ItemEnd = Commas[i];
218
      // The comma is counted as part of the item when calculating the length.
219
4.25k
      ItemLengths.push_back(CodePointsBetween(ItemBegin, ItemEnd));
220
221
      // Consume trailing comments so the are included in EndOfLineItemLength.
222
4.25k
      if (ItemEnd->Next && !ItemEnd->Next->HasUnescapedNewline &&
223
4.25k
          
ItemEnd->Next->isTrailingComment()3.74k
)
224
132
        ItemEnd = ItemEnd->Next;
225
4.25k
    }
226
5.78k
    EndOfLineItemLength.push_back(CodePointsBetween(ItemBegin, ItemEnd));
227
    // If there is a trailing comma in the list, the next item will start at the
228
    // closing brace. Don't create an extra item for this.
229
5.78k
    if (ItemEnd->getNextNonComment() == Token->MatchingParen)
230
383
      break;
231
5.40k
    ItemBegin = ItemEnd->Next;
232
5.40k
  }
233
234
  // Don't use column layout for lists with few elements and in presence of
235
  // separating comments.
236
1.76k
  if (Commas.size() < 5 || 
HasSeparatingComment102
)
237
1.66k
    return;
238
239
99
  if (Token->NestingLevel != 0 && 
Token->is(tok::l_brace)14
&&
Commas.size() < 1912
)
240
9
    return;
241
242
  // We can never place more than ColumnLimit / 3 items in a row (because of the
243
  // spaces and the comma).
244
90
  unsigned MaxItems = Style.ColumnLimit / 3;
245
90
  std::vector<unsigned> MinSizeInColumn;
246
90
  MinSizeInColumn.reserve(MaxItems);
247
1.04k
  for (unsigned Columns = 1; Columns <= MaxItems; 
++Columns959
) {
248
1.03k
    ColumnFormat Format;
249
1.03k
    Format.Columns = Columns;
250
1.03k
    Format.ColumnSizes.resize(Columns);
251
1.03k
    MinSizeInColumn.assign(Columns, UINT_MAX);
252
1.03k
    Format.LineCount = 1;
253
1.03k
    bool HasRowWithSufficientColumns = false;
254
1.03k
    unsigned Column = 0;
255
21.8k
    for (unsigned i = 0, e = ItemLengths.size(); i != e; 
++i20.7k
) {
256
20.7k
      assert(i < MustBreakBeforeItem.size());
257
20.7k
      if (MustBreakBeforeItem[i] || 
Column == Columns20.2k
) {
258
3.80k
        ++Format.LineCount;
259
3.80k
        Column = 0;
260
3.80k
      }
261
20.7k
      if (Column == Columns - 1)
262
3.68k
        HasRowWithSufficientColumns = true;
263
20.7k
      unsigned Length =
264
20.7k
          (Column == Columns - 1) ? 
EndOfLineItemLength[i]3.68k
:
ItemLengths[i]17.1k
;
265
20.7k
      Format.ColumnSizes[Column] = std::max(Format.ColumnSizes[Column], Length);
266
20.7k
      MinSizeInColumn[Column] = std::min(MinSizeInColumn[Column], Length);
267
20.7k
      ++Column;
268
20.7k
    }
269
    // If all rows are terminated early (e.g. by trailing comments), we don't
270
    // need to look further.
271
1.03k
    if (!HasRowWithSufficientColumns)
272
78
      break;
273
959
    Format.TotalWidth = Columns - 1; // Width of the N-1 spaces.
274
275
8.76k
    for (unsigned i = 0; i < Columns; 
++i7.80k
)
276
7.80k
      Format.TotalWidth += Format.ColumnSizes[i];
277
278
    // Don't use this Format, if the difference between the longest and shortest
279
    // element in a column exceeds a threshold to avoid excessive spaces.
280
959
    if ([&] {
281
7.44k
          for (unsigned i = 0; i < Columns - 1; 
++i6.49k
)
282
6.61k
            if (Format.ColumnSizes[i] - MinSizeInColumn[i] > 10)
283
129
              return true;
284
830
          return false;
285
959
        }())
286
129
      continue;
287
288
    // Ignore layouts that are bound to violate the column limit.
289
830
    if (Format.TotalWidth > Style.ColumnLimit && 
Columns > 1234
)
290
234
      continue;
291
292
596
    Formats.push_back(Format);
293
596
  }
294
90
}
295
296
const CommaSeparatedList::ColumnFormat *
297
12.9k
CommaSeparatedList::getColumnFormat(unsigned RemainingCharacters) const {
298
12.9k
  const ColumnFormat *BestFormat = nullptr;
299
12.9k
  for (const ColumnFormat &Format : llvm::reverse(Formats)) {
300
1.83k
    if (Format.TotalWidth <= RemainingCharacters || 
Format.Columns == 1485
) {
301
1.34k
      if (BestFormat && 
Format.LineCount > BestFormat->LineCount923
)
302
424
        break;
303
923
      BestFormat = &Format;
304
923
    }
305
1.83k
  }
306
12.9k
  return BestFormat;
307
12.9k
}
308
309
} // namespace format
310
} // namespace clang