Coverage Report

Created: 2020-02-15 09:57

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