Coverage Report

Created: 2021-01-23 06:44

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Format/BreakableToken.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- BreakableToken.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
/// Contains implementation of BreakableToken class and classes derived
11
/// from it.
12
///
13
//===----------------------------------------------------------------------===//
14
15
#include "BreakableToken.h"
16
#include "ContinuationIndenter.h"
17
#include "clang/Basic/CharInfo.h"
18
#include "clang/Format/Format.h"
19
#include "llvm/ADT/STLExtras.h"
20
#include "llvm/Support/Debug.h"
21
#include <algorithm>
22
23
#define DEBUG_TYPE "format-token-breaker"
24
25
namespace clang {
26
namespace format {
27
28
static const char *const Blanks = " \t\v\f\r";
29
5.71k
static bool IsBlank(char C) {
30
5.71k
  switch (C) {
31
475
  case ' ':
32
483
  case '\t':
33
483
  case '\v':
34
483
  case '\f':
35
483
  case '\r':
36
483
    return true;
37
5.23k
  default:
38
5.23k
    return false;
39
5.71k
  }
40
5.71k
}
41
42
static StringRef getLineCommentIndentPrefix(StringRef Comment,
43
9.77k
                                            const FormatStyle &Style) {
44
9.77k
  static const char *const KnownCStylePrefixes[] = {"///<", "//!<", "///",
45
9.77k
                                                    "//",   "//!",  "//:"};
46
9.77k
  static const char *const KnownTextProtoPrefixes[] = {"//", "#", "##", "###",
47
9.77k
                                                       "####"};
48
9.77k
  ArrayRef<const char *> KnownPrefixes(KnownCStylePrefixes);
49
9.77k
  if (Style.Language == FormatStyle::LK_TextProto)
50
252
    KnownPrefixes = KnownTextProtoPrefixes;
51
52
9.77k
  StringRef LongestPrefix;
53
58.3k
  for (StringRef KnownPrefix : KnownPrefixes) {
54
58.3k
    if (Comment.startswith(KnownPrefix)) {
55
9.89k
      size_t PrefixLength = KnownPrefix.size();
56
17.9k
      while (PrefixLength < Comment.size() && 
Comment[PrefixLength] == ' '16.3k
)
57
8.06k
        ++PrefixLength;
58
9.89k
      if (PrefixLength > LongestPrefix.size())
59
9.83k
        LongestPrefix = Comment.substr(0, PrefixLength);
60
9.89k
    }
61
58.3k
  }
62
9.77k
  return LongestPrefix;
63
9.77k
}
64
65
static BreakableToken::Split
66
getCommentSplit(StringRef Text, unsigned ContentStartColumn,
67
                unsigned ColumnLimit, unsigned TabWidth,
68
                encoding::Encoding Encoding, const FormatStyle &Style,
69
3.08k
                bool DecorationEndsWithStar = false) {
70
3.08k
  LLVM_DEBUG(llvm::dbgs() << "Comment split: \"" << Text
71
3.08k
                          << "\", Column limit: " << ColumnLimit
72
3.08k
                          << ", Content start: " << ContentStartColumn << "\n");
73
3.08k
  if (ColumnLimit <= ContentStartColumn + 1)
74
691
    return BreakableToken::Split(StringRef::npos, 0);
75
76
2.39k
  unsigned MaxSplit = ColumnLimit - ContentStartColumn + 1;
77
2.39k
  unsigned MaxSplitBytes = 0;
78
79
2.39k
  for (unsigned NumChars = 0;
80
48.9k
       NumChars < MaxSplit && 
MaxSplitBytes < Text.size()46.5k
;) {
81
46.5k
    unsigned BytesInChar =
82
46.5k
        encoding::getCodePointNumBytes(Text[MaxSplitBytes], Encoding);
83
46.5k
    NumChars +=
84
46.5k
        encoding::columnWidthWithTabs(Text.substr(MaxSplitBytes, BytesInChar),
85
46.5k
                                      ContentStartColumn, TabWidth, Encoding);
86
46.5k
    MaxSplitBytes += BytesInChar;
87
46.5k
  }
88
89
  // In JavaScript, some @tags can be followed by {, and machinery that parses
90
  // these comments will fail to understand the comment if followed by a line
91
  // break. So avoid ever breaking before a {.
92
2.39k
  if (Style.Language == FormatStyle::LK_JavaScript) {
93
111
    StringRef::size_type SpaceOffset =
94
111
        Text.find_first_of(Blanks, MaxSplitBytes);
95
111
    if (SpaceOffset != StringRef::npos && 
SpaceOffset + 1 < Text.size()51
&&
96
38
        Text[SpaceOffset + 1] == '{') {
97
18
      MaxSplitBytes = SpaceOffset + 1;
98
18
    }
99
111
  }
100
101
2.39k
  StringRef::size_type SpaceOffset = Text.find_last_of(Blanks, MaxSplitBytes);
102
103
2.39k
  static const auto kNumberedListRegexp = llvm::Regex("^[1-9][0-9]?\\.");
104
  // Some spaces are unacceptable to break on, rewind past them.
105
2.51k
  while (SpaceOffset != StringRef::npos) {
106
    // If a line-comment ends with `\`, the next line continues the comment,
107
    // whether or not it starts with `//`. This is confusing and triggers
108
    // -Wcomment.
109
    // Avoid introducing multiline comments by not allowing a break right
110
    // after '\'.
111
1.65k
    if (Style.isCpp()) {
112
1.47k
      StringRef::size_type LastNonBlank =
113
1.47k
          Text.find_last_not_of(Blanks, SpaceOffset);
114
1.47k
      if (LastNonBlank != StringRef::npos && 
Text[LastNonBlank] == '\\'1.45k
) {
115
38
        SpaceOffset = Text.find_last_of(Blanks, LastNonBlank);
116
38
        continue;
117
38
      }
118
1.61k
    }
119
120
    // Do not split before a number followed by a dot: this would be interpreted
121
    // as a numbered list, which would prevent re-flowing in subsequent passes.
122
1.61k
    if (kNumberedListRegexp.match(Text.substr(SpaceOffset).ltrim(Blanks))) {
123
4
      SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
124
4
      continue;
125
4
    }
126
127
    // Avoid ever breaking before a @tag or a { in JavaScript.
128
1.61k
    if (Style.Language == FormatStyle::LK_JavaScript &&
129
129
        SpaceOffset + 1 < Text.size() &&
130
119
        (Text[SpaceOffset + 1] == '{' || 
Text[SpaceOffset + 1] == '@'57
)) {
131
79
      SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
132
79
      continue;
133
79
    }
134
135
1.53k
    break;
136
1.53k
  }
137
138
2.39k
  if (SpaceOffset == StringRef::npos ||
139
      // Don't break at leading whitespace.
140
1.53k
      Text.find_last_not_of(Blanks, SpaceOffset) == StringRef::npos) {
141
    // Make sure that we don't break at leading whitespace that
142
    // reaches past MaxSplit.
143
889
    StringRef::size_type FirstNonWhitespace = Text.find_first_not_of(Blanks);
144
889
    if (FirstNonWhitespace == StringRef::npos)
145
      // If the comment is only whitespace, we cannot split.
146
10
      return BreakableToken::Split(StringRef::npos, 0);
147
879
    SpaceOffset = Text.find_first_of(
148
879
        Blanks, std::max<unsigned>(MaxSplitBytes, FirstNonWhitespace));
149
879
  }
150
2.38k
  if (SpaceOffset != StringRef::npos && 
SpaceOffset != 01.89k
) {
151
    // adaptStartOfLine will break after lines starting with /** if the comment
152
    // is broken anywhere. Avoid emitting this break twice here.
153
    // Example: in /** longtextcomesherethatbreaks */ (with ColumnLimit 20) will
154
    // insert a break after /**, so this code must not insert the same break.
155
1.89k
    if (SpaceOffset == 1 && 
Text[SpaceOffset - 1] == '*'3
)
156
2
      return BreakableToken::Split(StringRef::npos, 0);
157
1.88k
    StringRef BeforeCut = Text.substr(0, SpaceOffset).rtrim(Blanks);
158
1.88k
    StringRef AfterCut = Text.substr(SpaceOffset);
159
    // Don't trim the leading blanks if it would create a */ after the break.
160
1.88k
    if (!DecorationEndsWithStar || 
AfterCut.size() <= 16
||
AfterCut[1] != '/'6
)
161
1.88k
      AfterCut = AfterCut.ltrim(Blanks);
162
1.88k
    return BreakableToken::Split(BeforeCut.size(),
163
1.88k
                                 AfterCut.begin() - BeforeCut.end());
164
1.88k
  }
165
494
  return BreakableToken::Split(StringRef::npos, 0);
166
494
}
167
168
static BreakableToken::Split
169
getStringSplit(StringRef Text, unsigned UsedColumns, unsigned ColumnLimit,
170
403
               unsigned TabWidth, encoding::Encoding Encoding) {
171
  // FIXME: Reduce unit test case.
172
403
  if (Text.empty())
173
0
    return BreakableToken::Split(StringRef::npos, 0);
174
403
  if (ColumnLimit <= UsedColumns)
175
5
    return BreakableToken::Split(StringRef::npos, 0);
176
398
  unsigned MaxSplit = ColumnLimit - UsedColumns;
177
398
  StringRef::size_type SpaceOffset = 0;
178
398
  StringRef::size_type SlashOffset = 0;
179
398
  StringRef::size_type WordStartOffset = 0;
180
398
  StringRef::size_type SplitPoint = 0;
181
6.11k
  for (unsigned Chars = 0;;) {
182
6.11k
    unsigned Advance;
183
6.11k
    if (Text[0] == '\\') {
184
35
      Advance = encoding::getEscapeSequenceLength(Text);
185
35
      Chars += Advance;
186
6.08k
    } else {
187
6.08k
      Advance = encoding::getCodePointNumBytes(Text[0], Encoding);
188
6.08k
      Chars += encoding::columnWidthWithTabs(
189
6.08k
          Text.substr(0, Advance), UsedColumns + Chars, TabWidth, Encoding);
190
6.08k
    }
191
192
6.11k
    if (Chars > MaxSplit || 
Text.size() <= Advance5.76k
)
193
398
      break;
194
195
5.71k
    if (IsBlank(Text[0]))
196
483
      SpaceOffset = SplitPoint;
197
5.71k
    if (Text[0] == '/')
198
22
      SlashOffset = SplitPoint;
199
5.71k
    if (Advance == 1 && 
!isAlphanumeric(Text[0])5.59k
)
200
577
      WordStartOffset = SplitPoint;
201
202
5.71k
    SplitPoint += Advance;
203
5.71k
    Text = Text.substr(Advance);
204
5.71k
  }
205
206
398
  if (SpaceOffset != 0)
207
214
    return BreakableToken::Split(SpaceOffset + 1, 0);
208
184
  if (SlashOffset != 0)
209
12
    return BreakableToken::Split(SlashOffset + 1, 0);
210
172
  if (WordStartOffset != 0)
211
4
    return BreakableToken::Split(WordStartOffset + 1, 0);
212
168
  if (SplitPoint != 0)
213
152
    return BreakableToken::Split(SplitPoint, 0);
214
16
  return BreakableToken::Split(StringRef::npos, 0);
215
16
}
216
217
10.0k
bool switchesFormatting(const FormatToken &Token) {
218
10.0k
  assert((Token.is(TT_BlockComment) || Token.is(TT_LineComment)) &&
219
10.0k
         "formatting regions are switched by comment tokens");
220
10.0k
  StringRef Content = Token.TokenText.substr(2).ltrim();
221
10.0k
  return Content.startswith("clang-format on") ||
222
10.0k
         Content.startswith("clang-format off");
223
10.0k
}
224
225
unsigned
226
BreakableToken::getLengthAfterCompression(unsigned RemainingTokenColumns,
227
1.29k
                                          Split Split) const {
228
  // Example: consider the content
229
  // lala  lala
230
  // - RemainingTokenColumns is the original number of columns, 10;
231
  // - Split is (4, 2), denoting the two spaces between the two words;
232
  //
233
  // We compute the number of columns when the split is compressed into a single
234
  // space, like:
235
  // lala lala
236
  //
237
  // FIXME: Correctly measure the length of whitespace in Split.second so it
238
  // works with tabs.
239
1.29k
  return RemainingTokenColumns + 1 - Split.second;
240
1.29k
}
241
242
6.63k
unsigned BreakableStringLiteral::getLineCount() const { return 1; }
243
244
unsigned BreakableStringLiteral::getRangeLength(unsigned LineIndex,
245
                                                unsigned Offset,
246
                                                StringRef::size_type Length,
247
0
                                                unsigned StartColumn) const {
248
0
  llvm_unreachable("Getting the length of a part of the string literal "
249
0
                   "indicates that the code tries to reflow it.");
250
0
}
251
252
unsigned
253
BreakableStringLiteral::getRemainingLength(unsigned LineIndex, unsigned Offset,
254
3.68k
                                           unsigned StartColumn) const {
255
3.68k
  return UnbreakableTailLength + Postfix.size() +
256
3.68k
         encoding::columnWidthWithTabs(Line.substr(Offset, StringRef::npos),
257
3.68k
                                       StartColumn, Style.TabWidth, Encoding);
258
3.68k
}
259
260
unsigned BreakableStringLiteral::getContentStartColumn(unsigned LineIndex,
261
3.68k
                                                       bool Break) const {
262
3.68k
  return StartColumn + Prefix.size();
263
3.68k
}
264
265
BreakableStringLiteral::BreakableStringLiteral(
266
    const FormatToken &Tok, unsigned StartColumn, StringRef Prefix,
267
    StringRef Postfix, unsigned UnbreakableTailLength, bool InPPDirective,
268
    encoding::Encoding Encoding, const FormatStyle &Style)
269
    : BreakableToken(Tok, InPPDirective, Encoding, Style),
270
      StartColumn(StartColumn), Prefix(Prefix), Postfix(Postfix),
271
3.33k
      UnbreakableTailLength(UnbreakableTailLength) {
272
3.33k
  assert(Tok.TokenText.startswith(Prefix) && Tok.TokenText.endswith(Postfix));
273
3.33k
  Line = Tok.TokenText.substr(
274
3.33k
      Prefix.size(), Tok.TokenText.size() - Prefix.size() - Postfix.size());
275
3.33k
}
276
277
BreakableToken::Split BreakableStringLiteral::getSplit(
278
    unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit,
279
403
    unsigned ContentStartColumn, const llvm::Regex &CommentPragmasRegex) const {
280
403
  return getStringSplit(Line.substr(TailOffset), ContentStartColumn,
281
403
                        ColumnLimit - Postfix.size(), Style.TabWidth, Encoding);
282
403
}
283
284
void BreakableStringLiteral::insertBreak(unsigned LineIndex,
285
                                         unsigned TailOffset, Split Split,
286
                                         unsigned ContentIndent,
287
97
                                         WhitespaceManager &Whitespaces) const {
288
97
  Whitespaces.replaceWhitespaceInToken(
289
97
      Tok, Prefix.size() + TailOffset + Split.first, Split.second, Postfix,
290
97
      Prefix, InPPDirective, 1, StartColumn);
291
97
}
292
293
BreakableComment::BreakableComment(const FormatToken &Token,
294
                                   unsigned StartColumn, bool InPPDirective,
295
                                   encoding::Encoding Encoding,
296
                                   const FormatStyle &Style)
297
    : BreakableToken(Token, InPPDirective, Encoding, Style),
298
9.53k
      StartColumn(StartColumn) {}
299
300
18.7k
unsigned BreakableComment::getLineCount() const { return Lines.size(); }
301
302
BreakableToken::Split
303
BreakableComment::getSplit(unsigned LineIndex, unsigned TailOffset,
304
                           unsigned ColumnLimit, unsigned ContentStartColumn,
305
2.06k
                           const llvm::Regex &CommentPragmasRegex) const {
306
  // Don't break lines matching the comment pragmas regex.
307
2.06k
  if (CommentPragmasRegex.match(Content[LineIndex]))
308
0
    return Split(StringRef::npos, 0);
309
2.06k
  return getCommentSplit(Content[LineIndex].substr(TailOffset),
310
2.06k
                         ContentStartColumn, ColumnLimit, Style.TabWidth,
311
2.06k
                         Encoding, Style);
312
2.06k
}
313
314
void BreakableComment::compressWhitespace(
315
    unsigned LineIndex, unsigned TailOffset, Split Split,
316
30
    WhitespaceManager &Whitespaces) const {
317
30
  StringRef Text = Content[LineIndex].substr(TailOffset);
318
  // Text is relative to the content line, but Whitespaces operates relative to
319
  // the start of the corresponding token, so compute the start of the Split
320
  // that needs to be compressed into a single space relative to the start of
321
  // its token.
322
30
  unsigned BreakOffsetInToken =
323
30
      Text.data() - tokenAt(LineIndex).TokenText.data() + Split.first;
324
30
  unsigned CharsToRemove = Split.second;
325
30
  Whitespaces.replaceWhitespaceInToken(
326
30
      tokenAt(LineIndex), BreakOffsetInToken, CharsToRemove, "", "",
327
30
      /*InPPDirective=*/false, /*Newlines=*/0, /*Spaces=*/1);
328
30
}
329
330
2.87k
const FormatToken &BreakableComment::tokenAt(unsigned LineIndex) const {
331
1.88k
  return Tokens[LineIndex] ? 
*Tokens[LineIndex]993
: Tok;
332
2.87k
}
333
334
641
static bool mayReflowContent(StringRef Content) {
335
641
  Content = Content.trim(Blanks);
336
  // Lines starting with '@' commonly have special meaning.
337
  // Lines starting with '-', '-#', '+' or '*' are bulleted/numbered lists.
338
641
  bool hasSpecialMeaningPrefix = false;
339
641
  for (StringRef Prefix :
340
4.99k
       {"@", "TODO", "FIXME", "XXX", "-# ", "- ", "+ ", "* "}) {
341
4.99k
    if (Content.startswith(Prefix)) {
342
30
      hasSpecialMeaningPrefix = true;
343
30
      break;
344
30
    }
345
4.99k
  }
346
347
  // Numbered lists may also start with a number followed by '.'
348
  // To avoid issues if a line starts with a number which is actually the end
349
  // of a previous line, we only consider numbers with up to 2 digits.
350
641
  static const auto kNumberedListRegexp = llvm::Regex("^[1-9][0-9]?\\. ");
351
641
  hasSpecialMeaningPrefix =
352
641
      hasSpecialMeaningPrefix || 
kNumberedListRegexp.match(Content)611
;
353
354
  // Simple heuristic for what to reflow: content should contain at least two
355
  // characters and either the first or second character must be
356
  // non-punctuation.
357
641
  return Content.size() >= 2 && 
!hasSpecialMeaningPrefix522
&&
358
490
         !Content.endswith("\\") &&
359
         // Note that this is UTF-8 safe, since if isPunctuation(Content[0]) is
360
         // true, then the first code point must be 1 byte long.
361
490
         (!isPunctuation(Content[0]) || 
!isPunctuation(Content[1])6
);
362
641
}
363
364
BreakableBlockComment::BreakableBlockComment(
365
    const FormatToken &Token, unsigned StartColumn,
366
    unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective,
367
    encoding::Encoding Encoding, const FormatStyle &Style, bool UseCRLF)
368
    : BreakableComment(Token, StartColumn, InPPDirective, Encoding, Style),
369
      DelimitersOnNewline(false),
370
1.52k
      UnbreakableTailLength(Token.UnbreakableTailLength) {
371
1.52k
  assert(Tok.is(TT_BlockComment) &&
372
1.52k
         "block comment section must start with a block comment");
373
374
1.52k
  StringRef TokenText(Tok.TokenText);
375
1.52k
  assert(TokenText.startswith("/*") && TokenText.endswith("*/"));
376
1.52k
  TokenText.substr(2, TokenText.size() - 4)
377
1.51k
      .split(Lines, UseCRLF ? 
"\r\n"8
: "\n");
378
379
1.52k
  int IndentDelta = StartColumn - OriginalStartColumn;
380
1.52k
  Content.resize(Lines.size());
381
1.52k
  Content[0] = Lines[0];
382
1.52k
  ContentColumn.resize(Lines.size());
383
  // Account for the initial '/*'.
384
1.52k
  ContentColumn[0] = StartColumn + 2;
385
1.52k
  Tokens.resize(Lines.size());
386
2.39k
  for (size_t i = 1; i < Lines.size(); 
++i875
)
387
875
    adjustWhitespace(i, IndentDelta);
388
389
  // Align decorations with the column of the star on the first line,
390
  // that is one column after the start "/*".
391
1.52k
  DecorationColumn = StartColumn + 1;
392
393
  // Account for comment decoration patterns like this:
394
  //
395
  // /*
396
  // ** blah blah blah
397
  // */
398
1.52k
  if (Lines.size() >= 2 && 
Content[1].startswith("**")471
&&
399
10
      static_cast<unsigned>(ContentColumn[1]) == StartColumn) {
400
6
    DecorationColumn = StartColumn;
401
6
  }
402
403
1.52k
  Decoration = "* ";
404
1.52k
  if (Lines.size() == 1 && 
!FirstInLine1.05k
) {
405
    // Comments for which FirstInLine is false can start on arbitrary column,
406
    // and available horizontal space can be too small to align consecutive
407
    // lines with the first one.
408
    // FIXME: We could, probably, align them to current indentation level, but
409
    // now we just wrap them without stars.
410
842
    Decoration = "";
411
842
  }
412
2.08k
  for (size_t i = 1, e = Lines.size(); i < e && 
!Decoration.empty()851
;
++i559
) {
413
    // If the last line is empty, the closing "*/" will have a star.
414
766
    if (i + 1 == e && 
Content[i].empty()386
)
415
207
      break;
416
559
    if (!Content[i].empty() && 
i + 1 != e545
&&
Decoration.startswith(Content[i])366
)
417
19
      continue;
418
918
    
while (540
!Content[i].startswith(Decoration))
419
378
      Decoration = Decoration.substr(0, Decoration.size() - 1);
420
540
  }
421
422
1.52k
  LastLineNeedsDecoration = true;
423
1.52k
  IndentAtLineBreak = ContentColumn[0] + 1;
424
2.39k
  for (size_t i = 1, e = Lines.size(); i < e; 
++i875
) {
425
875
    if (Content[i].empty()) {
426
299
      if (i + 1 == e) {
427
        // Empty last line means that we already have a star as a part of the
428
        // trailing */. We also need to preserve whitespace, so that */ is
429
        // correctly indented.
430
283
        LastLineNeedsDecoration = false;
431
        // Align the star in the last '*/' with the stars on the previous lines.
432
283
        if (e >= 2 && !Decoration.empty()) {
433
207
          ContentColumn[i] = DecorationColumn;
434
207
        }
435
16
      } else if (Decoration.empty()) {
436
        // For all other lines, set the start column to 0 if they're empty, so
437
        // we do not insert trailing whitespace anywhere.
438
16
        ContentColumn[i] = 0;
439
16
      }
440
299
      continue;
441
299
    }
442
443
    // The first line already excludes the star.
444
    // The last line excludes the star if LastLineNeedsDecoration is false.
445
    // For all other lines, adjust the line to exclude the star and
446
    // (optionally) the first whitespace.
447
576
    unsigned DecorationSize = Decoration.startswith(Content[i])
448
21
                                  ? Content[i].size()
449
555
                                  : Decoration.size();
450
576
    if (DecorationSize) {
451
379
      ContentColumn[i] = DecorationColumn + DecorationSize;
452
379
    }
453
576
    Content[i] = Content[i].substr(DecorationSize);
454
576
    if (!Decoration.startswith(Content[i]))
455
547
      IndentAtLineBreak =
456
547
          std::min<int>(IndentAtLineBreak, std::max(0, ContentColumn[i]));
457
576
  }
458
1.52k
  IndentAtLineBreak = std::max<unsigned>(IndentAtLineBreak, Decoration.size());
459
460
  // Detect a multiline jsdoc comment and set DelimitersOnNewline in that case.
461
1.52k
  if (Style.Language == FormatStyle::LK_JavaScript ||
462
1.34k
      Style.Language == FormatStyle::LK_Java) {
463
196
    if ((Lines[0] == "*" || 
Lines[0].startswith("* ")106
) &&
Lines.size() > 1150
) {
464
      // This is a multiline jsdoc comment.
465
102
      DelimitersOnNewline = true;
466
94
    } else if (Lines[0].startswith("* ") && 
Lines.size() == 148
) {
467
      // Detect a long single-line comment, like:
468
      // /** long long long */
469
      // Below, '2' is the width of '*/'.
470
48
      unsigned EndColumn =
471
48
          ContentColumn[0] +
472
48
          encoding::columnWidthWithTabs(Lines[0], ContentColumn[0],
473
48
                                        Style.TabWidth, Encoding) +
474
48
          2;
475
48
      DelimitersOnNewline = EndColumn > Style.ColumnLimit;
476
48
    }
477
196
  }
478
479
1.52k
  LLVM_DEBUG({
480
1.52k
    llvm::dbgs() << "IndentAtLineBreak " << IndentAtLineBreak << "\n";
481
1.52k
    llvm::dbgs() << "DelimitersOnNewline " << DelimitersOnNewline << "\n";
482
1.52k
    for (size_t i = 0; i < Lines.size(); ++i) {
483
1.52k
      llvm::dbgs() << i << " |" << Content[i] << "| "
484
1.52k
                   << "CC=" << ContentColumn[i] << "| "
485
1.52k
                   << "IN=" << (Content[i].data() - Lines[i].data()) << "\n";
486
1.52k
    }
487
1.52k
  });
488
1.52k
}
489
490
BreakableToken::Split BreakableBlockComment::getSplit(
491
    unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit,
492
1.02k
    unsigned ContentStartColumn, const llvm::Regex &CommentPragmasRegex) const {
493
  // Don't break lines matching the comment pragmas regex.
494
1.02k
  if (CommentPragmasRegex.match(Content[LineIndex]))
495
6
    return Split(StringRef::npos, 0);
496
1.02k
  return getCommentSplit(Content[LineIndex].substr(TailOffset),
497
1.02k
                         ContentStartColumn, ColumnLimit, Style.TabWidth,
498
1.02k
                         Encoding, Style, Decoration.endswith("*"));
499
1.02k
}
500
501
void BreakableBlockComment::adjustWhitespace(unsigned LineIndex,
502
875
                                             int IndentDelta) {
503
  // When in a preprocessor directive, the trailing backslash in a block comment
504
  // is not needed, but can serve a purpose of uniformity with necessary escaped
505
  // newlines outside the comment. In this case we remove it here before
506
  // trimming the trailing whitespace. The backslash will be re-added later when
507
  // inserting a line break.
508
875
  size_t EndOfPreviousLine = Lines[LineIndex - 1].size();
509
875
  if (InPPDirective && 
Lines[LineIndex - 1].endswith("\\")22
)
510
14
    --EndOfPreviousLine;
511
512
  // Calculate the end of the non-whitespace text in the previous line.
513
875
  EndOfPreviousLine =
514
875
      Lines[LineIndex - 1].find_last_not_of(Blanks, EndOfPreviousLine);
515
875
  if (EndOfPreviousLine == StringRef::npos)
516
158
    EndOfPreviousLine = 0;
517
717
  else
518
717
    ++EndOfPreviousLine;
519
  // Calculate the start of the non-whitespace text in the current line.
520
875
  size_t StartOfLine = Lines[LineIndex].find_first_not_of(Blanks);
521
875
  if (StartOfLine == StringRef::npos)
522
299
    StartOfLine = Lines[LineIndex].size();
523
524
875
  StringRef Whitespace = Lines[LineIndex].substr(0, StartOfLine);
525
  // Adjust Lines to only contain relevant text.
526
875
  size_t PreviousContentOffset =
527
875
      Content[LineIndex - 1].data() - Lines[LineIndex - 1].data();
528
875
  Content[LineIndex - 1] = Lines[LineIndex - 1].substr(
529
875
      PreviousContentOffset, EndOfPreviousLine - PreviousContentOffset);
530
875
  Content[LineIndex] = Lines[LineIndex].substr(StartOfLine);
531
532
  // Adjust the start column uniformly across all lines.
533
875
  ContentColumn[LineIndex] =
534
875
      encoding::columnWidthWithTabs(Whitespace, 0, Style.TabWidth, Encoding) +
535
875
      IndentDelta;
536
875
}
537
538
unsigned BreakableBlockComment::getRangeLength(unsigned LineIndex,
539
                                               unsigned Offset,
540
                                               StringRef::size_type Length,
541
3.80k
                                               unsigned StartColumn) const {
542
3.80k
  unsigned LineLength =
543
3.80k
      encoding::columnWidthWithTabs(Content[LineIndex].substr(Offset, Length),
544
3.80k
                                    StartColumn, Style.TabWidth, Encoding);
545
  // FIXME: This should go into getRemainingLength instead, but we currently
546
  // break tests when putting it there. Investigate how to fix those tests.
547
  // The last line gets a "*/" postfix.
548
3.80k
  if (LineIndex + 1 == Lines.size()) {
549
2.23k
    LineLength += 2;
550
    // We never need a decoration when breaking just the trailing "*/" postfix.
551
    // Note that checking that Length == 0 is not enough, since Length could
552
    // also be StringRef::npos.
553
2.23k
    if (Content[LineIndex].substr(Offset, StringRef::npos).empty()) {
554
475
      LineLength -= Decoration.size();
555
475
    }
556
2.23k
  }
557
3.80k
  return LineLength;
558
3.80k
}
559
560
unsigned BreakableBlockComment::getRemainingLength(unsigned LineIndex,
561
                                                   unsigned Offset,
562
3.27k
                                                   unsigned StartColumn) const {
563
3.27k
  return UnbreakableTailLength +
564
3.27k
         getRangeLength(LineIndex, Offset, StringRef::npos, StartColumn);
565
3.27k
}
566
567
unsigned BreakableBlockComment::getContentStartColumn(unsigned LineIndex,
568
2.77k
                                                      bool Break) const {
569
2.77k
  if (Break)
570
453
    return IndentAtLineBreak;
571
2.32k
  return std::max(0, ContentColumn[LineIndex]);
572
2.32k
}
573
574
const llvm::StringSet<>
575
    BreakableBlockComment::ContentIndentingJavadocAnnotations = {
576
        "@param", "@return",     "@returns", "@throws",  "@type", "@template",
577
        "@see",   "@deprecated", "@define",  "@exports", "@mods", "@private",
578
};
579
580
490
unsigned BreakableBlockComment::getContentIndent(unsigned LineIndex) const {
581
490
  if (Style.Language != FormatStyle::LK_Java &&
582
468
      Style.Language != FormatStyle::LK_JavaScript)
583
403
    return 0;
584
  // The content at LineIndex 0 of a comment like:
585
  // /** line 0 */
586
  // is "* line 0", so we need to skip over the decoration in that case.
587
87
  StringRef ContentWithNoDecoration = Content[LineIndex];
588
87
  if (LineIndex == 0 && 
ContentWithNoDecoration.startswith("*")35
) {
589
35
    ContentWithNoDecoration = ContentWithNoDecoration.substr(1).ltrim(Blanks);
590
35
  }
591
87
  StringRef FirstWord = ContentWithNoDecoration.substr(
592
87
      0, ContentWithNoDecoration.find_first_of(Blanks));
593
87
  if (ContentIndentingJavadocAnnotations.find(FirstWord) !=
594
87
      ContentIndentingJavadocAnnotations.end())
595
56
    return Style.ContinuationIndentWidth;
596
31
  return 0;
597
31
}
598
599
void BreakableBlockComment::insertBreak(unsigned LineIndex, unsigned TailOffset,
600
                                        Split Split, unsigned ContentIndent,
601
164
                                        WhitespaceManager &Whitespaces) const {
602
164
  StringRef Text = Content[LineIndex].substr(TailOffset);
603
164
  StringRef Prefix = Decoration;
604
  // We need this to account for the case when we have a decoration "* " for all
605
  // the lines except for the last one, where the star in "*/" acts as a
606
  // decoration.
607
164
  unsigned LocalIndentAtLineBreak = IndentAtLineBreak;
608
164
  if (LineIndex + 1 == Lines.size() &&
609
69
      Text.size() == Split.first + Split.second) {
610
    // For the last line we need to break before "*/", but not to add "* ".
611
17
    Prefix = "";
612
17
    if (LocalIndentAtLineBreak >= 2)
613
17
      LocalIndentAtLineBreak -= 2;
614
17
  }
615
  // The split offset is from the beginning of the line. Convert it to an offset
616
  // from the beginning of the token text.
617
164
  unsigned BreakOffsetInToken =
618
164
      Text.data() - tokenAt(LineIndex).TokenText.data() + Split.first;
619
164
  unsigned CharsToRemove = Split.second;
620
164
  assert(LocalIndentAtLineBreak >= Prefix.size());
621
164
  std::string PrefixWithTrailingIndent = std::string(Prefix);
622
164
  PrefixWithTrailingIndent.append(ContentIndent, ' ');
623
164
  Whitespaces.replaceWhitespaceInToken(
624
164
      tokenAt(LineIndex), BreakOffsetInToken, CharsToRemove, "",
625
164
      PrefixWithTrailingIndent, InPPDirective, /*Newlines=*/1,
626
164
      /*Spaces=*/LocalIndentAtLineBreak + ContentIndent -
627
164
          PrefixWithTrailingIndent.size());
628
164
}
629
630
BreakableToken::Split BreakableBlockComment::getReflowSplit(
631
208
    unsigned LineIndex, const llvm::Regex &CommentPragmasRegex) const {
632
208
  if (!mayReflow(LineIndex, CommentPragmasRegex))
633
119
    return Split(StringRef::npos, 0);
634
635
  // If we're reflowing into a line with content indent, only reflow the next
636
  // line if its starting whitespace matches the content indent.
637
89
  size_t Trimmed = Content[LineIndex].find_first_not_of(Blanks);
638
89
  if (LineIndex) {
639
89
    unsigned PreviousContentIndent = getContentIndent(LineIndex - 1);
640
89
    if (PreviousContentIndent && 
Trimmed != StringRef::npos6
&&
641
6
        Trimmed != PreviousContentIndent)
642
4
      return Split(StringRef::npos, 0);
643
85
  }
644
645
85
  return Split(0, Trimmed != StringRef::npos ? Trimmed : 
00
);
646
85
}
647
648
1.52k
bool BreakableBlockComment::introducesBreakBeforeToken() const {
649
  // A break is introduced when we want delimiters on newline.
650
1.52k
  return DelimitersOnNewline &&
651
125
         Lines[0].substr(1).find_first_not_of(Blanks) != StringRef::npos;
652
1.52k
}
653
654
void BreakableBlockComment::reflow(unsigned LineIndex,
655
29
                                   WhitespaceManager &Whitespaces) const {
656
29
  StringRef TrimmedContent = Content[LineIndex].ltrim(Blanks);
657
  // Here we need to reflow.
658
29
  assert(Tokens[LineIndex - 1] == Tokens[LineIndex] &&
659
29
         "Reflowing whitespace within a token");
660
  // This is the offset of the end of the last line relative to the start of
661
  // the token text in the token.
662
29
  unsigned WhitespaceOffsetInToken = Content[LineIndex - 1].data() +
663
29
                                     Content[LineIndex - 1].size() -
664
29
                                     tokenAt(LineIndex).TokenText.data();
665
29
  unsigned WhitespaceLength = TrimmedContent.data() -
666
29
                              tokenAt(LineIndex).TokenText.data() -
667
29
                              WhitespaceOffsetInToken;
668
29
  Whitespaces.replaceWhitespaceInToken(
669
29
      tokenAt(LineIndex), WhitespaceOffsetInToken,
670
29
      /*ReplaceChars=*/WhitespaceLength, /*PreviousPostfix=*/"",
671
29
      /*CurrentPrefix=*/ReflowPrefix, InPPDirective, /*Newlines=*/0,
672
29
      /*Spaces=*/0);
673
29
}
674
675
void BreakableBlockComment::adaptStartOfLine(
676
965
    unsigned LineIndex, WhitespaceManager &Whitespaces) const {
677
965
  if (LineIndex == 0) {
678
615
    if (DelimitersOnNewline) {
679
      // Since we're breaking at index 1 below, the break position and the
680
      // break length are the same.
681
      // Note: this works because getCommentSplit is careful never to split at
682
      // the beginning of a line.
683
55
      size_t BreakLength = Lines[0].substr(1).find_first_not_of(Blanks);
684
55
      if (BreakLength != StringRef::npos)
685
12
        insertBreak(LineIndex, 0, Split(1, BreakLength), /*ContentIndent=*/0,
686
12
                    Whitespaces);
687
55
    }
688
615
    return;
689
615
  }
690
  // Here no reflow with the previous line will happen.
691
  // Fix the decoration of the line at LineIndex.
692
350
  StringRef Prefix = Decoration;
693
350
  if (Content[LineIndex].empty()) {
694
141
    if (LineIndex + 1 == Lines.size()) {
695
124
      if (!LastLineNeedsDecoration) {
696
        // If the last line was empty, we don't need a prefix, as the */ will
697
        // line up with the decoration (if it exists).
698
123
        Prefix = "";
699
123
      }
700
17
    } else if (!Decoration.empty()) {
701
      // For other empty lines, if we do have a decoration, adapt it to not
702
      // contain a trailing whitespace.
703
9
      Prefix = Prefix.substr(0, 1);
704
9
    }
705
209
  } else {
706
209
    if (ContentColumn[LineIndex] == 1) {
707
      // This line starts immediately after the decorating *.
708
9
      Prefix = Prefix.substr(0, 1);
709
9
    }
710
209
  }
711
  // This is the offset of the end of the last line relative to the start of the
712
  // token text in the token.
713
350
  unsigned WhitespaceOffsetInToken = Content[LineIndex - 1].data() +
714
350
                                     Content[LineIndex - 1].size() -
715
350
                                     tokenAt(LineIndex).TokenText.data();
716
350
  unsigned WhitespaceLength = Content[LineIndex].data() -
717
350
                              tokenAt(LineIndex).TokenText.data() -
718
350
                              WhitespaceOffsetInToken;
719
350
  Whitespaces.replaceWhitespaceInToken(
720
350
      tokenAt(LineIndex), WhitespaceOffsetInToken, WhitespaceLength, "", Prefix,
721
350
      InPPDirective, /*Newlines=*/1, ContentColumn[LineIndex] - Prefix.size());
722
350
}
723
724
BreakableToken::Split
725
1.52k
BreakableBlockComment::getSplitAfterLastLine(unsigned TailOffset) const {
726
1.52k
  if (DelimitersOnNewline) {
727
    // Replace the trailing whitespace of the last line with a newline.
728
    // In case the last line is empty, the ending '*/' is already on its own
729
    // line.
730
125
    StringRef Line = Content.back().substr(TailOffset);
731
125
    StringRef TrimmedLine = Line.rtrim(Blanks);
732
125
    if (!TrimmedLine.empty())
733
12
      return Split(TrimmedLine.size(), Line.size() - TrimmedLine.size());
734
1.51k
  }
735
1.51k
  return Split(StringRef::npos, 0);
736
1.51k
}
737
738
bool BreakableBlockComment::mayReflow(
739
208
    unsigned LineIndex, const llvm::Regex &CommentPragmasRegex) const {
740
  // Content[LineIndex] may exclude the indent after the '*' decoration. In that
741
  // case, we compute the start of the comment pragma manually.
742
208
  StringRef IndentContent = Content[LineIndex];
743
208
  if (Lines[LineIndex].ltrim(Blanks).startswith("*")) {
744
91
    IndentContent = Lines[LineIndex].ltrim(Blanks).substr(1);
745
91
  }
746
208
  return LineIndex > 0 && !CommentPragmasRegex.match(IndentContent) &&
747
206
         mayReflowContent(Content[LineIndex]) && 
!Tok.Finalized89
&&
748
89
         !switchesFormatting(tokenAt(LineIndex));
749
208
}
750
751
BreakableLineCommentSection::BreakableLineCommentSection(
752
    const FormatToken &Token, unsigned StartColumn,
753
    unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective,
754
    encoding::Encoding Encoding, const FormatStyle &Style)
755
8.00k
    : BreakableComment(Token, StartColumn, InPPDirective, Encoding, Style) {
756
8.00k
  assert(Tok.is(TT_LineComment) &&
757
8.00k
         "line comment section must start with a line comment");
758
8.00k
  FormatToken *LineTok = nullptr;
759
8.00k
  for (const FormatToken *CurrentTok = &Tok;
760
13.3k
       CurrentTok && 
CurrentTok->is(TT_LineComment)9.76k
;
761
9.76k
       
CurrentTok = CurrentTok->Next5.31k
) {
762
9.76k
    LastLineTok = LineTok;
763
9.76k
    StringRef TokenText(CurrentTok->TokenText);
764
9.76k
    assert((TokenText.startswith("//") || TokenText.startswith("#")) &&
765
9.76k
           "unsupported line comment prefix, '//' and '#' are supported");
766
9.76k
    size_t FirstLineIndex = Lines.size();
767
9.76k
    TokenText.split(Lines, "\n");
768
9.76k
    Content.resize(Lines.size());
769
9.76k
    ContentColumn.resize(Lines.size());
770
9.76k
    OriginalContentColumn.resize(Lines.size());
771
9.76k
    Tokens.resize(Lines.size());
772
9.76k
    Prefix.resize(Lines.size());
773
9.76k
    OriginalPrefix.resize(Lines.size());
774
19.5k
    for (size_t i = FirstLineIndex, e = Lines.size(); i < e; 
++i9.77k
) {
775
9.77k
      Lines[i] = Lines[i].ltrim(Blanks);
776
9.77k
      StringRef IndentPrefix = getLineCommentIndentPrefix(Lines[i], Style);
777
9.77k
      assert((TokenText.startswith("//") || TokenText.startswith("#")) &&
778
9.77k
             "unsupported line comment prefix, '//' and '#' are supported");
779
9.77k
      OriginalPrefix[i] = Prefix[i] = IndentPrefix;
780
9.77k
      if (Lines[i].size() > Prefix[i].size() &&
781
8.15k
          isAlphanumeric(Lines[i][Prefix[i].size()])) {
782
7.83k
        if (Prefix[i] == "//")
783
17
          Prefix[i] = "// ";
784
7.81k
        else if (Prefix[i] == "///")
785
8
          Prefix[i] = "/// ";
786
7.80k
        else if (Prefix[i] == "//!")
787
6
          Prefix[i] = "//! ";
788
7.80k
        else if (Prefix[i] == "///<")
789
0
          Prefix[i] = "///< ";
790
7.80k
        else if (Prefix[i] == "//!<")
791
0
          Prefix[i] = "//!< ";
792
7.80k
        else if (Prefix[i] == "#")
793
22
          Prefix[i] = "# ";
794
7.78k
        else if (Prefix[i] == "##")
795
4
          Prefix[i] = "## ";
796
7.77k
        else if (Prefix[i] == "###")
797
4
          Prefix[i] = "### ";
798
7.77k
        else if (Prefix[i] == "####")
799
4
          Prefix[i] = "#### ";
800
7.83k
      }
801
802
9.77k
      Tokens[i] = LineTok;
803
9.77k
      Content[i] = Lines[i].substr(IndentPrefix.size());
804
9.77k
      OriginalContentColumn[i] =
805
9.77k
          StartColumn + encoding::columnWidthWithTabs(OriginalPrefix[i],
806
9.77k
                                                      StartColumn,
807
9.77k
                                                      Style.TabWidth, Encoding);
808
9.77k
      ContentColumn[i] =
809
9.77k
          StartColumn + encoding::columnWidthWithTabs(Prefix[i], StartColumn,
810
9.77k
                                                      Style.TabWidth, Encoding);
811
812
      // Calculate the end of the non-whitespace text in this line.
813
9.77k
      size_t EndOfLine = Content[i].find_last_not_of(Blanks);
814
9.77k
      if (EndOfLine == StringRef::npos)
815
1.61k
        EndOfLine = Content[i].size();
816
8.15k
      else
817
8.15k
        ++EndOfLine;
818
9.77k
      Content[i] = Content[i].substr(0, EndOfLine);
819
9.77k
    }
820
9.76k
    LineTok = CurrentTok->Next;
821
9.76k
    if (CurrentTok->Next && 
!CurrentTok->Next->ContinuesLineCommentSection6.21k
) {
822
      // A line comment section needs to broken by a line comment that is
823
      // preceded by at least two newlines. Note that we put this break here
824
      // instead of breaking at a previous stage during parsing, since that
825
      // would split the contents of the enum into two unwrapped lines in this
826
      // example, which is undesirable:
827
      // enum A {
828
      //   a, // comment about a
829
      //
830
      //   // comment about b
831
      //   b
832
      // };
833
      //
834
      // FIXME: Consider putting separate line comment sections as children to
835
      // the unwrapped line instead.
836
4.45k
      break;
837
4.45k
    }
838
9.76k
  }
839
8.00k
}
840
841
unsigned
842
BreakableLineCommentSection::getRangeLength(unsigned LineIndex, unsigned Offset,
843
                                            StringRef::size_type Length,
844
11.5k
                                            unsigned StartColumn) const {
845
11.5k
  return encoding::columnWidthWithTabs(
846
11.5k
      Content[LineIndex].substr(Offset, Length), StartColumn, Style.TabWidth,
847
11.5k
      Encoding);
848
11.5k
}
849
850
unsigned BreakableLineCommentSection::getContentStartColumn(unsigned LineIndex,
851
9.16k
                                                            bool Break) const {
852
9.16k
  if (Break)
853
793
    return OriginalContentColumn[LineIndex];
854
8.37k
  return ContentColumn[LineIndex];
855
8.37k
}
856
857
void BreakableLineCommentSection::insertBreak(
858
    unsigned LineIndex, unsigned TailOffset, Split Split,
859
335
    unsigned ContentIndent, WhitespaceManager &Whitespaces) const {
860
335
  StringRef Text = Content[LineIndex].substr(TailOffset);
861
  // Compute the offset of the split relative to the beginning of the token
862
  // text.
863
335
  unsigned BreakOffsetInToken =
864
335
      Text.data() - tokenAt(LineIndex).TokenText.data() + Split.first;
865
335
  unsigned CharsToRemove = Split.second;
866
  // Compute the size of the new indent, including the size of the new prefix of
867
  // the newly broken line.
868
335
  unsigned IndentAtLineBreak = OriginalContentColumn[LineIndex] +
869
335
                               Prefix[LineIndex].size() -
870
335
                               OriginalPrefix[LineIndex].size();
871
335
  assert(IndentAtLineBreak >= Prefix[LineIndex].size());
872
335
  Whitespaces.replaceWhitespaceInToken(
873
335
      tokenAt(LineIndex), BreakOffsetInToken, CharsToRemove, "",
874
335
      Prefix[LineIndex], InPPDirective, /*Newlines=*/1,
875
335
      /*Spaces=*/IndentAtLineBreak - Prefix[LineIndex].size());
876
335
}
877
878
BreakableComment::Split BreakableLineCommentSection::getReflowSplit(
879
435
    unsigned LineIndex, const llvm::Regex &CommentPragmasRegex) const {
880
435
  if (!mayReflow(LineIndex, CommentPragmasRegex))
881
46
    return Split(StringRef::npos, 0);
882
883
389
  size_t Trimmed = Content[LineIndex].find_first_not_of(Blanks);
884
885
  // In a line comment section each line is a separate token; thus, after a
886
  // split we replace all whitespace before the current line comment token
887
  // (which does not need to be included in the split), plus the start of the
888
  // line up to where the content starts.
889
389
  return Split(0, Trimmed != StringRef::npos ? Trimmed : 
00
);
890
389
}
891
892
void BreakableLineCommentSection::reflow(unsigned LineIndex,
893
170
                                         WhitespaceManager &Whitespaces) const {
894
170
  if (LineIndex > 0 && Tokens[LineIndex] != Tokens[LineIndex - 1]) {
895
    // Reflow happens between tokens. Replace the whitespace between the
896
    // tokens by the empty string.
897
169
    Whitespaces.replaceWhitespace(
898
169
        *Tokens[LineIndex], /*Newlines=*/0, /*Spaces=*/0,
899
169
        /*StartOfTokenColumn=*/StartColumn, /*IsAligned=*/true,
900
169
        /*InPPDirective=*/false);
901
1
  } else if (LineIndex > 0) {
902
    // In case we're reflowing after the '\' in:
903
    //
904
    //   // line comment \
905
    //   // line 2
906
    //
907
    // the reflow happens inside the single comment token (it is a single line
908
    // comment with an unescaped newline).
909
    // Replace the whitespace between the '\' and '//' with the empty string.
910
    //
911
    // Offset points to after the '\' relative to start of the token.
912
1
    unsigned Offset = Lines[LineIndex - 1].data() +
913
1
                      Lines[LineIndex - 1].size() -
914
1
                      tokenAt(LineIndex - 1).TokenText.data();
915
    // WhitespaceLength is the number of chars between the '\' and the '//' on
916
    // the next line.
917
1
    unsigned WhitespaceLength =
918
1
        Lines[LineIndex].data() - tokenAt(LineIndex).TokenText.data() - Offset;
919
1
    Whitespaces.replaceWhitespaceInToken(*Tokens[LineIndex], Offset,
920
1
                                         /*ReplaceChars=*/WhitespaceLength,
921
1
                                         /*PreviousPostfix=*/"",
922
1
                                         /*CurrentPrefix=*/"",
923
1
                                         /*InPPDirective=*/false,
924
1
                                         /*Newlines=*/0,
925
1
                                         /*Spaces=*/0);
926
1
  }
927
  // Replace the indent and prefix of the token with the reflow prefix.
928
170
  unsigned Offset =
929
170
      Lines[LineIndex].data() - tokenAt(LineIndex).TokenText.data();
930
170
  unsigned WhitespaceLength =
931
170
      Content[LineIndex].data() - Lines[LineIndex].data();
932
170
  Whitespaces.replaceWhitespaceInToken(*Tokens[LineIndex], Offset,
933
170
                                       /*ReplaceChars=*/WhitespaceLength,
934
170
                                       /*PreviousPostfix=*/"",
935
170
                                       /*CurrentPrefix=*/ReflowPrefix,
936
170
                                       /*InPPDirective=*/false,
937
170
                                       /*Newlines=*/0,
938
170
                                       /*Spaces=*/0);
939
170
}
940
941
void BreakableLineCommentSection::adaptStartOfLine(
942
2.41k
    unsigned LineIndex, WhitespaceManager &Whitespaces) const {
943
  // If this is the first line of a token, we need to inform Whitespace Manager
944
  // about it: either adapt the whitespace range preceding it, or mark it as an
945
  // untouchable token.
946
  // This happens for instance here:
947
  // // line 1 \
948
  // // line 2
949
2.41k
  if (LineIndex > 0 && 
Tokens[LineIndex] != Tokens[LineIndex - 1]293
) {
950
    // This is the first line for the current token, but no reflow with the
951
    // previous token is necessary. However, we still may need to adjust the
952
    // start column. Note that ContentColumn[LineIndex] is the expected
953
    // content column after a possible update to the prefix, hence the prefix
954
    // length change is included.
955
290
    unsigned LineColumn =
956
290
        ContentColumn[LineIndex] -
957
290
        (Content[LineIndex].data() - Lines[LineIndex].data()) +
958
290
        (OriginalPrefix[LineIndex].size() - Prefix[LineIndex].size());
959
960
    // We always want to create a replacement instead of adding an untouchable
961
    // token, even if LineColumn is the same as the original column of the
962
    // token. This is because WhitespaceManager doesn't align trailing
963
    // comments if they are untouchable.
964
290
    Whitespaces.replaceWhitespace(*Tokens[LineIndex],
965
290
                                  /*Newlines=*/1,
966
290
                                  /*Spaces=*/LineColumn,
967
290
                                  /*StartOfTokenColumn=*/LineColumn,
968
290
                                  /*IsAligned=*/true,
969
290
                                  /*InPPDirective=*/false);
970
290
  }
971
2.41k
  if (OriginalPrefix[LineIndex] != Prefix[LineIndex]) {
972
    // Adjust the prefix if necessary.
973
974
    // Take care of the space possibly introduced after a decoration.
975
24
    assert(Prefix[LineIndex] == (OriginalPrefix[LineIndex] + " ").str() &&
976
24
           "Expecting a line comment prefix to differ from original by at most "
977
24
           "a space");
978
24
    Whitespaces.replaceWhitespaceInToken(
979
24
        tokenAt(LineIndex), OriginalPrefix[LineIndex].size(), 0, "", "",
980
24
        /*InPPDirective=*/false, /*Newlines=*/0, /*Spaces=*/1);
981
24
  }
982
2.41k
}
983
984
7.69k
void BreakableLineCommentSection::updateNextToken(LineState &State) const {
985
7.69k
  if (LastLineTok) {
986
487
    State.NextToken = LastLineTok->Next;
987
487
  }
988
7.69k
}
989
990
bool BreakableLineCommentSection::mayReflow(
991
435
    unsigned LineIndex, const llvm::Regex &CommentPragmasRegex) const {
992
  // Line comments have the indent as part of the prefix, so we need to
993
  // recompute the start of the line.
994
435
  StringRef IndentContent = Content[LineIndex];
995
435
  if (Lines[LineIndex].startswith("//")) {
996
425
    IndentContent = Lines[LineIndex].substr(2);
997
425
  }
998
  // FIXME: Decide whether we want to reflow non-regular indents:
999
  // Currently, we only reflow when the OriginalPrefix[LineIndex] matches the
1000
  // OriginalPrefix[LineIndex-1]. That means we don't reflow
1001
  // // text that protrudes
1002
  // //    into text with different indent
1003
  // We do reflow in that case in block comments.
1004
435
  return LineIndex > 0 && !CommentPragmasRegex.match(IndentContent) &&
1005
435
         mayReflowContent(Content[LineIndex]) && 
!Tok.Finalized399
&&
1006
399
         !switchesFormatting(tokenAt(LineIndex)) &&
1007
399
         OriginalPrefix[LineIndex] == OriginalPrefix[LineIndex - 1];
1008
435
}
1009
1010
} // namespace format
1011
} // namespace clang