clang  6.0.0svn
BreakableToken.cpp
Go to the documentation of this file.
1 //===--- BreakableToken.cpp - Format C++ code -----------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief Contains implementation of BreakableToken class and classes derived
12 /// from it.
13 ///
14 //===----------------------------------------------------------------------===//
15 
16 #include "BreakableToken.h"
17 #include "ContinuationIndenter.h"
18 #include "clang/Basic/CharInfo.h"
19 #include "clang/Format/Format.h"
20 #include "llvm/ADT/STLExtras.h"
21 #include "llvm/Support/Debug.h"
22 #include <algorithm>
23 
24 #define DEBUG_TYPE "format-token-breaker"
25 
26 namespace clang {
27 namespace format {
28 
29 static const char *const Blanks = " \t\v\f\r";
30 static bool IsBlank(char C) {
31  switch (C) {
32  case ' ':
33  case '\t':
34  case '\v':
35  case '\f':
36  case '\r':
37  return true;
38  default:
39  return false;
40  }
41 }
42 
43 static StringRef getLineCommentIndentPrefix(StringRef Comment) {
44  static const char *const KnownPrefixes[] = {"///<", "//!<", "///", "//",
45  "//!"};
46  StringRef LongestPrefix;
47  for (StringRef KnownPrefix : KnownPrefixes) {
48  if (Comment.startswith(KnownPrefix)) {
49  size_t PrefixLength = KnownPrefix.size();
50  while (PrefixLength < Comment.size() && Comment[PrefixLength] == ' ')
51  ++PrefixLength;
52  if (PrefixLength > LongestPrefix.size())
53  LongestPrefix = Comment.substr(0, PrefixLength);
54  }
55  }
56  return LongestPrefix;
57 }
58 
59 static BreakableToken::Split getCommentSplit(StringRef Text,
60  unsigned ContentStartColumn,
61  unsigned ColumnLimit,
62  unsigned TabWidth,
64  if (ColumnLimit <= ContentStartColumn + 1)
65  return BreakableToken::Split(StringRef::npos, 0);
66 
67  unsigned MaxSplit = ColumnLimit - ContentStartColumn + 1;
68  unsigned MaxSplitBytes = 0;
69 
70  for (unsigned NumChars = 0;
71  NumChars < MaxSplit && MaxSplitBytes < Text.size();) {
72  unsigned BytesInChar =
73  encoding::getCodePointNumBytes(Text[MaxSplitBytes], Encoding);
74  NumChars +=
75  encoding::columnWidthWithTabs(Text.substr(MaxSplitBytes, BytesInChar),
76  ContentStartColumn, TabWidth, Encoding);
77  MaxSplitBytes += BytesInChar;
78  }
79 
80  StringRef::size_type SpaceOffset = Text.find_last_of(Blanks, MaxSplitBytes);
81 
82  // Do not split before a number followed by a dot: this would be interpreted
83  // as a numbered list, which would prevent re-flowing in subsequent passes.
84  static llvm::Regex kNumberedListRegexp = llvm::Regex("^[1-9][0-9]?\\.");
85  if (SpaceOffset != StringRef::npos &&
86  kNumberedListRegexp.match(Text.substr(SpaceOffset).ltrim(Blanks)))
87  SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
88 
89  if (SpaceOffset == StringRef::npos ||
90  // Don't break at leading whitespace.
91  Text.find_last_not_of(Blanks, SpaceOffset) == StringRef::npos) {
92  // Make sure that we don't break at leading whitespace that
93  // reaches past MaxSplit.
94  StringRef::size_type FirstNonWhitespace = Text.find_first_not_of(Blanks);
95  if (FirstNonWhitespace == StringRef::npos)
96  // If the comment is only whitespace, we cannot split.
97  return BreakableToken::Split(StringRef::npos, 0);
98  SpaceOffset = Text.find_first_of(
99  Blanks, std::max<unsigned>(MaxSplitBytes, FirstNonWhitespace));
100  }
101  if (SpaceOffset != StringRef::npos && SpaceOffset != 0) {
102  StringRef BeforeCut = Text.substr(0, SpaceOffset).rtrim(Blanks);
103  StringRef AfterCut = Text.substr(SpaceOffset).ltrim(Blanks);
104  return BreakableToken::Split(BeforeCut.size(),
105  AfterCut.begin() - BeforeCut.end());
106  }
107  return BreakableToken::Split(StringRef::npos, 0);
108 }
109 
110 static BreakableToken::Split
111 getStringSplit(StringRef Text, unsigned UsedColumns, unsigned ColumnLimit,
112  unsigned TabWidth, encoding::Encoding Encoding) {
113  // FIXME: Reduce unit test case.
114  if (Text.empty())
115  return BreakableToken::Split(StringRef::npos, 0);
116  if (ColumnLimit <= UsedColumns)
117  return BreakableToken::Split(StringRef::npos, 0);
118  unsigned MaxSplit = ColumnLimit - UsedColumns;
119  StringRef::size_type SpaceOffset = 0;
120  StringRef::size_type SlashOffset = 0;
121  StringRef::size_type WordStartOffset = 0;
122  StringRef::size_type SplitPoint = 0;
123  for (unsigned Chars = 0;;) {
124  unsigned Advance;
125  if (Text[0] == '\\') {
126  Advance = encoding::getEscapeSequenceLength(Text);
127  Chars += Advance;
128  } else {
129  Advance = encoding::getCodePointNumBytes(Text[0], Encoding);
131  Text.substr(0, Advance), UsedColumns + Chars, TabWidth, Encoding);
132  }
133 
134  if (Chars > MaxSplit || Text.size() <= Advance)
135  break;
136 
137  if (IsBlank(Text[0]))
138  SpaceOffset = SplitPoint;
139  if (Text[0] == '/')
140  SlashOffset = SplitPoint;
141  if (Advance == 1 && !isAlphanumeric(Text[0]))
142  WordStartOffset = SplitPoint;
143 
144  SplitPoint += Advance;
145  Text = Text.substr(Advance);
146  }
147 
148  if (SpaceOffset != 0)
149  return BreakableToken::Split(SpaceOffset + 1, 0);
150  if (SlashOffset != 0)
151  return BreakableToken::Split(SlashOffset + 1, 0);
152  if (WordStartOffset != 0)
153  return BreakableToken::Split(WordStartOffset + 1, 0);
154  if (SplitPoint != 0)
155  return BreakableToken::Split(SplitPoint, 0);
156  return BreakableToken::Split(StringRef::npos, 0);
157 }
158 
160  assert((Token.is(TT_BlockComment) || Token.is(TT_LineComment)) &&
161  "formatting regions are switched by comment tokens");
162  StringRef Content = Token.TokenText.substr(2).ltrim();
163  return Content.startswith("clang-format on") ||
164  Content.startswith("clang-format off");
165 }
166 
167 unsigned
168 BreakableToken::getLineLengthAfterCompression(unsigned RemainingTokenColumns,
169  Split Split) const {
170  // Example: consider the content
171  // lala lala
172  // - RemainingTokenColumns is the original number of columns, 10;
173  // - Split is (4, 2), denoting the two spaces between the two words;
174  //
175  // We compute the number of columns when the split is compressed into a single
176  // space, like:
177  // lala lala
178  return RemainingTokenColumns + 1 - Split.second;
179 }
180 
181 unsigned BreakableSingleLineToken::getLineCount() const { return 1; }
182 
184  unsigned LineIndex, unsigned TailOffset,
185  StringRef::size_type Length) const {
186  return StartColumn + Prefix.size() + Postfix.size() +
187  encoding::columnWidthWithTabs(Line.substr(TailOffset, Length),
188  StartColumn + Prefix.size(),
190 }
191 
193  const FormatToken &Tok, unsigned StartColumn, StringRef Prefix,
195  const FormatStyle &Style)
196  : BreakableToken(Tok, InPPDirective, Encoding, Style),
197  StartColumn(StartColumn), Prefix(Prefix), Postfix(Postfix) {
198  assert(Tok.TokenText.startswith(Prefix) && Tok.TokenText.endswith(Postfix));
199  Line = Tok.TokenText.substr(
200  Prefix.size(), Tok.TokenText.size() - Prefix.size() - Postfix.size());
201 }
202 
204  const FormatToken &Tok, unsigned StartColumn, StringRef Prefix,
206  const FormatStyle &Style)
207  : BreakableSingleLineToken(Tok, StartColumn, Prefix, Postfix, InPPDirective,
208  Encoding, Style) {}
209 
210 BreakableToken::Split
211 BreakableStringLiteral::getSplit(unsigned LineIndex, unsigned TailOffset,
212  unsigned ColumnLimit,
213  llvm::Regex &CommentPragmasRegex) const {
214  return getStringSplit(Line.substr(TailOffset),
215  StartColumn + Prefix.size() + Postfix.size(),
216  ColumnLimit, Style.TabWidth, Encoding);
217 }
218 
219 void BreakableStringLiteral::insertBreak(unsigned LineIndex,
220  unsigned TailOffset, Split Split,
221  WhitespaceManager &Whitespaces) {
222  Whitespaces.replaceWhitespaceInToken(
223  Tok, Prefix.size() + TailOffset + Split.first, Split.second, Postfix,
225 }
226 
228  unsigned StartColumn, bool InPPDirective,
230  const FormatStyle &Style)
231  : BreakableToken(Token, InPPDirective, Encoding, Style),
232  StartColumn(StartColumn) {}
233 
234 unsigned BreakableComment::getLineCount() const { return Lines.size(); }
235 
236 BreakableToken::Split
237 BreakableComment::getSplit(unsigned LineIndex, unsigned TailOffset,
238  unsigned ColumnLimit,
239  llvm::Regex &CommentPragmasRegex) const {
240  // Don't break lines matching the comment pragmas regex.
241  if (CommentPragmasRegex.match(Content[LineIndex]))
242  return Split(StringRef::npos, 0);
243  return getCommentSplit(Content[LineIndex].substr(TailOffset),
244  getContentStartColumn(LineIndex, TailOffset),
245  ColumnLimit, Style.TabWidth, Encoding);
246 }
247 
248 void BreakableComment::compressWhitespace(unsigned LineIndex,
249  unsigned TailOffset, Split Split,
250  WhitespaceManager &Whitespaces) {
251  StringRef Text = Content[LineIndex].substr(TailOffset);
252  // Text is relative to the content line, but Whitespaces operates relative to
253  // the start of the corresponding token, so compute the start of the Split
254  // that needs to be compressed into a single space relative to the start of
255  // its token.
256  unsigned BreakOffsetInToken =
257  Text.data() - tokenAt(LineIndex).TokenText.data() + Split.first;
258  unsigned CharsToRemove = Split.second;
259  Whitespaces.replaceWhitespaceInToken(
260  tokenAt(LineIndex), BreakOffsetInToken, CharsToRemove, "", "",
261  /*InPPDirective=*/false, /*Newlines=*/0, /*Spaces=*/1);
262 }
263 
264 BreakableToken::Split
266  unsigned PreviousEndColumn,
267  unsigned ColumnLimit) const {
268  unsigned ReflowStartColumn = PreviousEndColumn + ReflowPrefix.size();
269  StringRef TrimmedText = Text.rtrim(Blanks);
270  // This is the width of the resulting line in case the full line of Text gets
271  // reflown up starting at ReflowStartColumn.
272  unsigned FullWidth = ReflowStartColumn + encoding::columnWidthWithTabs(
273  TrimmedText, ReflowStartColumn,
275  // If the full line fits up, we return a reflow split after it,
276  // otherwise we compute the largest piece of text that fits after
277  // ReflowStartColumn.
278  Split ReflowSplit =
279  FullWidth <= ColumnLimit
280  ? Split(TrimmedText.size(), Text.size() - TrimmedText.size())
281  : getCommentSplit(Text, ReflowStartColumn, ColumnLimit,
283 
284  // We need to be extra careful here, because while it's OK to keep a long line
285  // if it can't be broken into smaller pieces (like when the first word of a
286  // long line is longer than the column limit), it's not OK to reflow that long
287  // word up. So we recompute the size of the previous line after reflowing and
288  // only return the reflow split if that's under the line limit.
289  if (ReflowSplit.first != StringRef::npos &&
290  // Check if the width of the newly reflown line is under the limit.
291  PreviousEndColumn + ReflowPrefix.size() +
292  encoding::columnWidthWithTabs(Text.substr(0, ReflowSplit.first),
293  PreviousEndColumn +
294  ReflowPrefix.size(),
295  Style.TabWidth, Encoding) <=
296  ColumnLimit) {
297  return ReflowSplit;
298  }
299  return Split(StringRef::npos, 0);
300 }
301 
302 const FormatToken &BreakableComment::tokenAt(unsigned LineIndex) const {
303  return Tokens[LineIndex] ? *Tokens[LineIndex] : Tok;
304 }
305 
306 static bool mayReflowContent(StringRef Content) {
307  Content = Content.trim(Blanks);
308  // Lines starting with '@' commonly have special meaning.
309  // Lines starting with '-', '-#', '+' or '*' are bulleted/numbered lists.
310  static const SmallVector<StringRef, 8> kSpecialMeaningPrefixes = {
311  "@", "TODO", "FIXME", "XXX", "-# ", "- ", "+ ", "* "};
312  bool hasSpecialMeaningPrefix = false;
313  for (StringRef Prefix : kSpecialMeaningPrefixes) {
314  if (Content.startswith(Prefix)) {
315  hasSpecialMeaningPrefix = true;
316  break;
317  }
318  }
319 
320  // Numbered lists may also start with a number followed by '.'
321  // To avoid issues if a line starts with a number which is actually the end
322  // of a previous line, we only consider numbers with up to 2 digits.
323  static llvm::Regex kNumberedListRegexp = llvm::Regex("^[1-9][0-9]?\\. ");
324  hasSpecialMeaningPrefix =
325  hasSpecialMeaningPrefix || kNumberedListRegexp.match(Content);
326 
327  // Simple heuristic for what to reflow: content should contain at least two
328  // characters and either the first or second character must be
329  // non-punctuation.
330  return Content.size() >= 2 && !hasSpecialMeaningPrefix &&
331  !Content.endswith("\\") &&
332  // Note that this is UTF-8 safe, since if isPunctuation(Content[0]) is
333  // true, then the first code point must be 1 byte long.
334  (!isPunctuation(Content[0]) || !isPunctuation(Content[1]));
335 }
336 
338  const FormatToken &Token, unsigned StartColumn,
339  unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective,
341  : BreakableComment(Token, StartColumn, InPPDirective, Encoding, Style),
342  DelimitersOnNewline(false) {
343  assert(Tok.is(TT_BlockComment) &&
344  "block comment section must start with a block comment");
345 
346  StringRef TokenText(Tok.TokenText);
347  assert(TokenText.startswith("/*") && TokenText.endswith("*/"));
348  TokenText.substr(2, TokenText.size() - 4).split(Lines, "\n");
349 
350  int IndentDelta = StartColumn - OriginalStartColumn;
351  Content.resize(Lines.size());
352  Content[0] = Lines[0];
353  ContentColumn.resize(Lines.size());
354  // Account for the initial '/*'.
355  ContentColumn[0] = StartColumn + 2;
356  Tokens.resize(Lines.size());
357  for (size_t i = 1; i < Lines.size(); ++i)
358  adjustWhitespace(i, IndentDelta);
359 
360  // Align decorations with the column of the star on the first line,
361  // that is one column after the start "/*".
362  DecorationColumn = StartColumn + 1;
363 
364  // Account for comment decoration patterns like this:
365  //
366  // /*
367  // ** blah blah blah
368  // */
369  if (Lines.size() >= 2 && Content[1].startswith("**") &&
370  static_cast<unsigned>(ContentColumn[1]) == StartColumn) {
371  DecorationColumn = StartColumn;
372  }
373 
374  Decoration = "* ";
375  if (Lines.size() == 1 && !FirstInLine) {
376  // Comments for which FirstInLine is false can start on arbitrary column,
377  // and available horizontal space can be too small to align consecutive
378  // lines with the first one.
379  // FIXME: We could, probably, align them to current indentation level, but
380  // now we just wrap them without stars.
381  Decoration = "";
382  }
383  for (size_t i = 1, e = Lines.size(); i < e && !Decoration.empty(); ++i) {
384  // If the last line is empty, the closing "*/" will have a star.
385  if (i + 1 == e && Content[i].empty())
386  break;
387  if (!Content[i].empty() && i + 1 != e && Decoration.startswith(Content[i]))
388  continue;
389  while (!Content[i].startswith(Decoration))
390  Decoration = Decoration.substr(0, Decoration.size() - 1);
391  }
392 
393  LastLineNeedsDecoration = true;
394  IndentAtLineBreak = ContentColumn[0] + 1;
395  for (size_t i = 1, e = Lines.size(); i < e; ++i) {
396  if (Content[i].empty()) {
397  if (i + 1 == e) {
398  // Empty last line means that we already have a star as a part of the
399  // trailing */. We also need to preserve whitespace, so that */ is
400  // correctly indented.
401  LastLineNeedsDecoration = false;
402  // Align the star in the last '*/' with the stars on the previous lines.
403  if (e >= 2 && !Decoration.empty()) {
404  ContentColumn[i] = DecorationColumn;
405  }
406  } else if (Decoration.empty()) {
407  // For all other lines, set the start column to 0 if they're empty, so
408  // we do not insert trailing whitespace anywhere.
409  ContentColumn[i] = 0;
410  }
411  continue;
412  }
413 
414  // The first line already excludes the star.
415  // The last line excludes the star if LastLineNeedsDecoration is false.
416  // For all other lines, adjust the line to exclude the star and
417  // (optionally) the first whitespace.
418  unsigned DecorationSize = Decoration.startswith(Content[i])
419  ? Content[i].size()
420  : Decoration.size();
421  if (DecorationSize) {
422  ContentColumn[i] = DecorationColumn + DecorationSize;
423  }
424  Content[i] = Content[i].substr(DecorationSize);
425  if (!Decoration.startswith(Content[i]))
426  IndentAtLineBreak =
427  std::min<int>(IndentAtLineBreak, std::max(0, ContentColumn[i]));
428  }
429  IndentAtLineBreak = std::max<unsigned>(IndentAtLineBreak, Decoration.size());
430 
431  // Detect a multiline jsdoc comment and set DelimitersOnNewline in that case.
432  if (Style.Language == FormatStyle::LK_JavaScript ||
433  Style.Language == FormatStyle::LK_Java) {
434  if ((Lines[0] == "*" || Lines[0].startswith("* ")) && Lines.size() > 1) {
435  // This is a multiline jsdoc comment.
436  DelimitersOnNewline = true;
437  } else if (Lines[0].startswith("* ") && Lines.size() == 1) {
438  // Detect a long single-line comment, like:
439  // /** long long long */
440  // Below, '2' is the width of '*/'.
441  unsigned EndColumn =
442  ContentColumn[0] +
444  Style.TabWidth, Encoding) +
445  2;
446  DelimitersOnNewline = EndColumn > Style.ColumnLimit;
447  }
448  }
449 
450  DEBUG({
451  llvm::dbgs() << "IndentAtLineBreak " << IndentAtLineBreak << "\n";
452  llvm::dbgs() << "DelimitersOnNewline " << DelimitersOnNewline << "\n";
453  for (size_t i = 0; i < Lines.size(); ++i) {
454  llvm::dbgs() << i << " |" << Content[i] << "| "
455  << "CC=" << ContentColumn[i] << "| "
456  << "IN=" << (Content[i].data() - Lines[i].data()) << "\n";
457  }
458  });
459 }
460 
461 void BreakableBlockComment::adjustWhitespace(unsigned LineIndex,
462  int IndentDelta) {
463  // When in a preprocessor directive, the trailing backslash in a block comment
464  // is not needed, but can serve a purpose of uniformity with necessary escaped
465  // newlines outside the comment. In this case we remove it here before
466  // trimming the trailing whitespace. The backslash will be re-added later when
467  // inserting a line break.
468  size_t EndOfPreviousLine = Lines[LineIndex - 1].size();
469  if (InPPDirective && Lines[LineIndex - 1].endswith("\\"))
470  --EndOfPreviousLine;
471 
472  // Calculate the end of the non-whitespace text in the previous line.
473  EndOfPreviousLine =
474  Lines[LineIndex - 1].find_last_not_of(Blanks, EndOfPreviousLine);
475  if (EndOfPreviousLine == StringRef::npos)
476  EndOfPreviousLine = 0;
477  else
478  ++EndOfPreviousLine;
479  // Calculate the start of the non-whitespace text in the current line.
480  size_t StartOfLine = Lines[LineIndex].find_first_not_of(Blanks);
481  if (StartOfLine == StringRef::npos)
482  StartOfLine = Lines[LineIndex].rtrim("\r\n").size();
483 
484  StringRef Whitespace = Lines[LineIndex].substr(0, StartOfLine);
485  // Adjust Lines to only contain relevant text.
486  size_t PreviousContentOffset =
487  Content[LineIndex - 1].data() - Lines[LineIndex - 1].data();
488  Content[LineIndex - 1] = Lines[LineIndex - 1].substr(
489  PreviousContentOffset, EndOfPreviousLine - PreviousContentOffset);
490  Content[LineIndex] = Lines[LineIndex].substr(StartOfLine);
491 
492  // Adjust the start column uniformly across all lines.
493  ContentColumn[LineIndex] =
495  IndentDelta;
496 }
497 
499  unsigned LineIndex, unsigned TailOffset,
500  StringRef::size_type Length) const {
501  unsigned ContentStartColumn = getContentStartColumn(LineIndex, TailOffset);
502  unsigned LineLength =
503  ContentStartColumn + encoding::columnWidthWithTabs(
504  Content[LineIndex].substr(TailOffset, Length),
505  ContentStartColumn, Style.TabWidth, Encoding);
506  // The last line gets a "*/" postfix.
507  if (LineIndex + 1 == Lines.size()) {
508  LineLength += 2;
509  // We never need a decoration when breaking just the trailing "*/" postfix.
510  // Note that checking that Length == 0 is not enough, since Length could
511  // also be StringRef::npos.
512  if (Content[LineIndex].substr(TailOffset, Length).empty()) {
513  LineLength -= Decoration.size();
514  }
515  }
516  return LineLength;
517 }
518 
519 void BreakableBlockComment::insertBreak(unsigned LineIndex, unsigned TailOffset,
520  Split Split,
521  WhitespaceManager &Whitespaces) {
522  StringRef Text = Content[LineIndex].substr(TailOffset);
523  StringRef Prefix = Decoration;
524  // We need this to account for the case when we have a decoration "* " for all
525  // the lines except for the last one, where the star in "*/" acts as a
526  // decoration.
527  unsigned LocalIndentAtLineBreak = IndentAtLineBreak;
528  if (LineIndex + 1 == Lines.size() &&
529  Text.size() == Split.first + Split.second) {
530  // For the last line we need to break before "*/", but not to add "* ".
531  Prefix = "";
532  if (LocalIndentAtLineBreak >= 2)
533  LocalIndentAtLineBreak -= 2;
534  }
535  // The split offset is from the beginning of the line. Convert it to an offset
536  // from the beginning of the token text.
537  unsigned BreakOffsetInToken =
538  Text.data() - tokenAt(LineIndex).TokenText.data() + Split.first;
539  unsigned CharsToRemove = Split.second;
540  assert(LocalIndentAtLineBreak >= Prefix.size());
541  Whitespaces.replaceWhitespaceInToken(
542  tokenAt(LineIndex), BreakOffsetInToken, CharsToRemove, "", Prefix,
543  InPPDirective, /*Newlines=*/1,
544  /*Spaces=*/LocalIndentAtLineBreak - Prefix.size());
545 }
546 
548  unsigned LineIndex, unsigned PreviousEndColumn, unsigned ColumnLimit,
549  llvm::Regex &CommentPragmasRegex) const {
550  if (!mayReflow(LineIndex, CommentPragmasRegex))
551  return Split(StringRef::npos, 0);
552  StringRef TrimmedContent = Content[LineIndex].ltrim(Blanks);
553  Split Result = getReflowSplit(TrimmedContent, ReflowPrefix, PreviousEndColumn,
554  ColumnLimit);
555  // Result is relative to TrimmedContent. Adapt it relative to
556  // Content[LineIndex].
557  if (Result.first != StringRef::npos)
558  Result.first += Content[LineIndex].size() - TrimmedContent.size();
559  return Result;
560 }
561 
562 unsigned
563 BreakableBlockComment::getReflownColumn(StringRef Content, unsigned LineIndex,
564  unsigned PreviousEndColumn) const {
565  unsigned StartColumn = PreviousEndColumn + ReflowPrefix.size();
566  // If this is the last line, it will carry around its '*/' postfix.
567  unsigned PostfixLength = (LineIndex + 1 == Lines.size() ? 2 : 0);
568  // The line is composed of previous text, reflow prefix, reflown text and
569  // postfix.
570  unsigned ReflownColumn = StartColumn +
572  Content, StartColumn, Style.TabWidth, Encoding) +
573  PostfixLength;
574  return ReflownColumn;
575 }
576 
578  unsigned LineIndex, unsigned TailOffset, unsigned PreviousEndColumn,
579  unsigned ColumnLimit, Split SplitBefore) const {
580  if (SplitBefore.first == StringRef::npos ||
581  // Block comment line contents contain the trailing whitespace after the
582  // decoration, so the need of left trim. Note that this behavior is
583  // consistent with the breaking of block comments where the indentation of
584  // a broken line is uniform across all the lines of the block comment.
585  SplitBefore.first + SplitBefore.second <
586  Content[LineIndex].ltrim().size()) {
587  // A piece of line, not the whole, gets reflown.
588  return getLineLengthAfterSplit(LineIndex, TailOffset, StringRef::npos);
589  } else {
590  // The whole line gets reflown, need to check if we need to insert a break
591  // for the postfix or not.
592  StringRef TrimmedContent = Content[LineIndex].ltrim(Blanks);
593  unsigned ReflownColumn =
594  getReflownColumn(TrimmedContent, LineIndex, PreviousEndColumn);
595  if (ReflownColumn <= ColumnLimit) {
596  return ReflownColumn;
597  }
598  return getLineLengthAfterSplit(LineIndex, TailOffset, StringRef::npos);
599  }
600 }
601 
603  unsigned LineIndex, unsigned PreviousEndColumn, unsigned ColumnLimit,
604  Split SplitBefore, WhitespaceManager &Whitespaces) {
605  if (LineIndex == 0) {
606  if (DelimitersOnNewline) {
607  // Since we're breaking af index 1 below, the break position and the
608  // break length are the same.
609  size_t BreakLength = Lines[0].substr(1).find_first_not_of(Blanks);
610  if (BreakLength != StringRef::npos) {
611  insertBreak(LineIndex, 0, Split(1, BreakLength), Whitespaces);
612  DelimitersOnNewline = true;
613  }
614  }
615  return;
616  }
617  StringRef TrimmedContent = Content[LineIndex].ltrim(Blanks);
618  if (SplitBefore.first != StringRef::npos) {
619  // Here we need to reflow.
620  assert(Tokens[LineIndex - 1] == Tokens[LineIndex] &&
621  "Reflowing whitespace within a token");
622  // This is the offset of the end of the last line relative to the start of
623  // the token text in the token.
624  unsigned WhitespaceOffsetInToken = Content[LineIndex - 1].data() +
625  Content[LineIndex - 1].size() -
626  tokenAt(LineIndex).TokenText.data();
627  unsigned WhitespaceLength = TrimmedContent.data() -
628  tokenAt(LineIndex).TokenText.data() -
629  WhitespaceOffsetInToken;
630  Whitespaces.replaceWhitespaceInToken(
631  tokenAt(LineIndex), WhitespaceOffsetInToken,
632  /*ReplaceChars=*/WhitespaceLength, /*PreviousPostfix=*/"",
633  /*CurrentPrefix=*/ReflowPrefix, InPPDirective, /*Newlines=*/0,
634  /*Spaces=*/0);
635  // Check if we need to also insert a break at the whitespace range.
636  // Note that we don't need a penalty for this break, since it doesn't change
637  // the total number of lines.
638  unsigned ReflownColumn =
639  getReflownColumn(TrimmedContent, LineIndex, PreviousEndColumn);
640  if (ReflownColumn > ColumnLimit)
641  insertBreak(LineIndex, 0, SplitBefore, Whitespaces);
642  return;
643  }
644 
645  // Here no reflow with the previous line will happen.
646  // Fix the decoration of the line at LineIndex.
647  StringRef Prefix = Decoration;
648  if (Content[LineIndex].empty()) {
649  if (LineIndex + 1 == Lines.size()) {
650  if (!LastLineNeedsDecoration) {
651  // If the last line was empty, we don't need a prefix, as the */ will
652  // line up with the decoration (if it exists).
653  Prefix = "";
654  }
655  } else if (!Decoration.empty()) {
656  // For other empty lines, if we do have a decoration, adapt it to not
657  // contain a trailing whitespace.
658  Prefix = Prefix.substr(0, 1);
659  }
660  } else {
661  if (ContentColumn[LineIndex] == 1) {
662  // This line starts immediately after the decorating *.
663  Prefix = Prefix.substr(0, 1);
664  }
665  }
666  // This is the offset of the end of the last line relative to the start of the
667  // token text in the token.
668  unsigned WhitespaceOffsetInToken = Content[LineIndex - 1].data() +
669  Content[LineIndex - 1].size() -
670  tokenAt(LineIndex).TokenText.data();
671  unsigned WhitespaceLength = Content[LineIndex].data() -
672  tokenAt(LineIndex).TokenText.data() -
673  WhitespaceOffsetInToken;
674  Whitespaces.replaceWhitespaceInToken(
675  tokenAt(LineIndex), WhitespaceOffsetInToken, WhitespaceLength, "", Prefix,
676  InPPDirective, /*Newlines=*/1, ContentColumn[LineIndex] - Prefix.size());
677 }
678 
679 BreakableToken::Split
681  unsigned ColumnLimit) const {
682  if (DelimitersOnNewline) {
683  // Replace the trailing whitespace of the last line with a newline.
684  // In case the last line is empty, the ending '*/' is already on its own
685  // line.
686  StringRef Line = Content.back().substr(TailOffset);
687  StringRef TrimmedLine = Line.rtrim(Blanks);
688  if (!TrimmedLine.empty())
689  return Split(TrimmedLine.size(), Line.size() - TrimmedLine.size());
690  }
691  return Split(StringRef::npos, 0);
692 }
693 
694 bool BreakableBlockComment::mayReflow(unsigned LineIndex,
695  llvm::Regex &CommentPragmasRegex) const {
696  // Content[LineIndex] may exclude the indent after the '*' decoration. In that
697  // case, we compute the start of the comment pragma manually.
698  StringRef IndentContent = Content[LineIndex];
699  if (Lines[LineIndex].ltrim(Blanks).startswith("*")) {
700  IndentContent = Lines[LineIndex].ltrim(Blanks).substr(1);
701  }
702  return LineIndex > 0 && !CommentPragmasRegex.match(IndentContent) &&
703  mayReflowContent(Content[LineIndex]) && !Tok.Finalized &&
704  !switchesFormatting(tokenAt(LineIndex));
705 }
706 
707 unsigned
708 BreakableBlockComment::getContentStartColumn(unsigned LineIndex,
709  unsigned TailOffset) const {
710  // If we break, we always break at the predefined indent.
711  if (TailOffset != 0)
712  return IndentAtLineBreak;
713  return std::max(0, ContentColumn[LineIndex]);
714 }
715 
717  const FormatToken &Token, unsigned StartColumn,
718  unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective,
720  : BreakableComment(Token, StartColumn, InPPDirective, Encoding, Style) {
721  assert(Tok.is(TT_LineComment) &&
722  "line comment section must start with a line comment");
723  FormatToken *LineTok = nullptr;
724  for (const FormatToken *CurrentTok = &Tok;
725  CurrentTok && CurrentTok->is(TT_LineComment);
726  CurrentTok = CurrentTok->Next) {
727  LastLineTok = LineTok;
728  StringRef TokenText(CurrentTok->TokenText);
729  assert(TokenText.startswith("//"));
730  size_t FirstLineIndex = Lines.size();
731  TokenText.split(Lines, "\n");
732  Content.resize(Lines.size());
733  ContentColumn.resize(Lines.size());
734  OriginalContentColumn.resize(Lines.size());
735  Tokens.resize(Lines.size());
736  Prefix.resize(Lines.size());
737  OriginalPrefix.resize(Lines.size());
738  for (size_t i = FirstLineIndex, e = Lines.size(); i < e; ++i) {
739  // We need to trim the blanks in case this is not the first line in a
740  // multiline comment. Then the indent is included in Lines[i].
741  StringRef IndentPrefix =
742  getLineCommentIndentPrefix(Lines[i].ltrim(Blanks));
743  assert(IndentPrefix.startswith("//"));
744  OriginalPrefix[i] = Prefix[i] = IndentPrefix;
745  if (Lines[i].size() > Prefix[i].size() &&
746  isAlphanumeric(Lines[i][Prefix[i].size()])) {
747  if (Prefix[i] == "//")
748  Prefix[i] = "// ";
749  else if (Prefix[i] == "///")
750  Prefix[i] = "/// ";
751  else if (Prefix[i] == "//!")
752  Prefix[i] = "//! ";
753  else if (Prefix[i] == "///<")
754  Prefix[i] = "///< ";
755  else if (Prefix[i] == "//!<")
756  Prefix[i] = "//!< ";
757  }
758 
759  Tokens[i] = LineTok;
760  Content[i] = Lines[i].substr(IndentPrefix.size());
761  OriginalContentColumn[i] =
762  StartColumn + encoding::columnWidthWithTabs(OriginalPrefix[i],
763  StartColumn,
764  Style.TabWidth, Encoding);
765  ContentColumn[i] =
766  StartColumn + encoding::columnWidthWithTabs(Prefix[i], StartColumn,
767  Style.TabWidth, Encoding);
768 
769  // Calculate the end of the non-whitespace text in this line.
770  size_t EndOfLine = Content[i].find_last_not_of(Blanks);
771  if (EndOfLine == StringRef::npos)
772  EndOfLine = Content[i].size();
773  else
774  ++EndOfLine;
775  Content[i] = Content[i].substr(0, EndOfLine);
776  }
777  LineTok = CurrentTok->Next;
778  if (CurrentTok->Next && !CurrentTok->Next->ContinuesLineCommentSection) {
779  // A line comment section needs to broken by a line comment that is
780  // preceded by at least two newlines. Note that we put this break here
781  // instead of breaking at a previous stage during parsing, since that
782  // would split the contents of the enum into two unwrapped lines in this
783  // example, which is undesirable:
784  // enum A {
785  // a, // comment about a
786  //
787  // // comment about b
788  // b
789  // };
790  //
791  // FIXME: Consider putting separate line comment sections as children to
792  // the unwrapped line instead.
793  break;
794  }
795  }
796 }
797 
799  unsigned LineIndex, unsigned TailOffset,
800  StringRef::size_type Length) const {
801  unsigned ContentStartColumn =
802  (TailOffset == 0 ? ContentColumn[LineIndex]
803  : OriginalContentColumn[LineIndex]);
804  return ContentStartColumn + encoding::columnWidthWithTabs(
805  Content[LineIndex].substr(TailOffset, Length),
806  ContentStartColumn, Style.TabWidth, Encoding);
807 }
808 
810  unsigned TailOffset, Split Split,
811  WhitespaceManager &Whitespaces) {
812  StringRef Text = Content[LineIndex].substr(TailOffset);
813  // Compute the offset of the split relative to the beginning of the token
814  // text.
815  unsigned BreakOffsetInToken =
816  Text.data() - tokenAt(LineIndex).TokenText.data() + Split.first;
817  unsigned CharsToRemove = Split.second;
818  // Compute the size of the new indent, including the size of the new prefix of
819  // the newly broken line.
820  unsigned IndentAtLineBreak = OriginalContentColumn[LineIndex] +
821  Prefix[LineIndex].size() -
822  OriginalPrefix[LineIndex].size();
823  assert(IndentAtLineBreak >= Prefix[LineIndex].size());
824  Whitespaces.replaceWhitespaceInToken(
825  tokenAt(LineIndex), BreakOffsetInToken, CharsToRemove, "",
826  Prefix[LineIndex], InPPDirective, /*Newlines=*/1,
827  /*Spaces=*/IndentAtLineBreak - Prefix[LineIndex].size());
828 }
829 
831  unsigned LineIndex, unsigned PreviousEndColumn, unsigned ColumnLimit,
832  llvm::Regex &CommentPragmasRegex) const {
833  if (!mayReflow(LineIndex, CommentPragmasRegex))
834  return Split(StringRef::npos, 0);
835  return getReflowSplit(Content[LineIndex], ReflowPrefix, PreviousEndColumn,
836  ColumnLimit);
837 }
838 
840  unsigned LineIndex, unsigned TailOffset, unsigned PreviousEndColumn,
841  unsigned ColumnLimit, Split SplitBefore) const {
842  if (SplitBefore.first == StringRef::npos ||
843  SplitBefore.first + SplitBefore.second < Content[LineIndex].size()) {
844  // A piece of line, not the whole line, gets reflown.
845  return getLineLengthAfterSplit(LineIndex, TailOffset, StringRef::npos);
846  } else {
847  // The whole line gets reflown.
848  unsigned StartColumn = PreviousEndColumn + ReflowPrefix.size();
849  return StartColumn +
850  encoding::columnWidthWithTabs(Content[LineIndex], StartColumn,
852  }
853 }
854 
856  unsigned LineIndex, unsigned PreviousEndColumn, unsigned ColumnLimit,
857  Split SplitBefore, WhitespaceManager &Whitespaces) {
858  // If this is the first line of a token, we need to inform Whitespace Manager
859  // about it: either adapt the whitespace range preceding it, or mark it as an
860  // untouchable token.
861  // This happens for instance here:
862  // // line 1 \
863  // // line 2
864  if (LineIndex > 0 && Tokens[LineIndex] != Tokens[LineIndex - 1]) {
865  if (SplitBefore.first != StringRef::npos) {
866  // Reflow happens between tokens. Replace the whitespace between the
867  // tokens by the empty string.
868  Whitespaces.replaceWhitespace(
869  *Tokens[LineIndex], /*Newlines=*/0, /*Spaces=*/0,
870  /*StartOfTokenColumn=*/StartColumn, /*InPPDirective=*/false);
871  // Replace the indent and prefix of the token with the reflow prefix.
872  unsigned WhitespaceLength =
873  Content[LineIndex].data() - tokenAt(LineIndex).TokenText.data();
874  Whitespaces.replaceWhitespaceInToken(*Tokens[LineIndex],
875  /*Offset=*/0,
876  /*ReplaceChars=*/WhitespaceLength,
877  /*PreviousPostfix=*/"",
878  /*CurrentPrefix=*/ReflowPrefix,
879  /*InPPDirective=*/false,
880  /*Newlines=*/0,
881  /*Spaces=*/0);
882  } else {
883  // This is the first line for the current token, but no reflow with the
884  // previous token is necessary. However, we still may need to adjust the
885  // start column. Note that ContentColumn[LineIndex] is the expected
886  // content column after a possible update to the prefix, hence the prefix
887  // length change is included.
888  unsigned LineColumn =
889  ContentColumn[LineIndex] -
890  (Content[LineIndex].data() - Lines[LineIndex].data()) +
891  (OriginalPrefix[LineIndex].size() - Prefix[LineIndex].size());
892 
893  // We always want to create a replacement instead of adding an untouchable
894  // token, even if LineColumn is the same as the original column of the
895  // token. This is because WhitespaceManager doesn't align trailing
896  // comments if they are untouchable.
897  Whitespaces.replaceWhitespace(*Tokens[LineIndex],
898  /*Newlines=*/1,
899  /*Spaces=*/LineColumn,
900  /*StartOfTokenColumn=*/LineColumn,
901  /*InPPDirective=*/false);
902  }
903  }
904  if (OriginalPrefix[LineIndex] != Prefix[LineIndex]) {
905  // Adjust the prefix if necessary.
906 
907  // Take care of the space possibly introduced after a decoration.
908  assert(Prefix[LineIndex] == (OriginalPrefix[LineIndex] + " ").str() &&
909  "Expecting a line comment prefix to differ from original by at most "
910  "a space");
911  Whitespaces.replaceWhitespaceInToken(
912  tokenAt(LineIndex), OriginalPrefix[LineIndex].size(), 0, "", "",
913  /*InPPDirective=*/false, /*Newlines=*/0, /*Spaces=*/1);
914  }
915  // Add a break after a reflow split has been introduced, if necessary.
916  // Note that this break doesn't need to be penalized, since it doesn't change
917  // the number of lines.
918  if (SplitBefore.first != StringRef::npos &&
919  SplitBefore.first + SplitBefore.second < Content[LineIndex].size()) {
920  insertBreak(LineIndex, 0, SplitBefore, Whitespaces);
921  }
922 }
923 
925  if (LastLineTok) {
926  State.NextToken = LastLineTok->Next;
927  }
928 }
929 
931  unsigned LineIndex, llvm::Regex &CommentPragmasRegex) const {
932  // Line comments have the indent as part of the prefix, so we need to
933  // recompute the start of the line.
934  StringRef IndentContent = Content[LineIndex];
935  if (Lines[LineIndex].startswith("//")) {
936  IndentContent = Lines[LineIndex].substr(2);
937  }
938  return LineIndex > 0 && !CommentPragmasRegex.match(IndentContent) &&
939  mayReflowContent(Content[LineIndex]) && !Tok.Finalized &&
940  !switchesFormatting(tokenAt(LineIndex)) &&
941  OriginalPrefix[LineIndex] == OriginalPrefix[LineIndex - 1];
942 }
943 
944 unsigned
945 BreakableLineCommentSection::getContentStartColumn(unsigned LineIndex,
946  unsigned TailOffset) const {
947  if (TailOffset != 0) {
948  return OriginalContentColumn[LineIndex];
949  }
950  return ContentColumn[LineIndex];
951 }
952 
953 } // namespace format
954 } // namespace clang
unsigned getLineCount() const override
bool switchesFormatting(const FormatToken &Token)
Checks if Token switches formatting, like /* clang-format off.
unsigned getLineLengthAfterCompression(unsigned RemainingTokenColumns, Split Split) const
Returns the number of columns required to format the piece of line at LineIndex, from byte offset Tai...
Declares BreakableToken, BreakableStringLiteral, BreakableComment, BreakableBlockComment and Breakabl...
void replaceWhitespaceBefore(unsigned LineIndex, unsigned PreviousEndColumn, unsigned ColumnLimit, Split SplitBefore, WhitespaceManager &Whitespaces) override
static const char *const Blanks
static StringRef getLineCommentIndentPrefix(StringRef Comment)
const FormatToken & tokenAt(unsigned LineIndex) const
BreakableBlockComment(const FormatToken &Token, unsigned StartColumn, unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style)
FormatToken * Next
The next token in the unwrapped line.
Definition: FormatToken.h:283
void replaceWhitespaceInToken(const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars, StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective, unsigned Newlines, int Spaces)
Inserts or replaces whitespace in the middle of a token.
SmallVector< int, 16 > ContentColumn
LineState State
Should be used for Java.
Definition: Format.h:1168
void updateNextToken(LineState &State) const override
Token - This structure provides full information about a lexed token.
Definition: Token.h:35
unsigned getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset, StringRef::size_type Length) const override
unsigned columnWidthWithTabs(StringRef Text, unsigned StartColumn, unsigned TabWidth, Encoding Encoding)
Returns the number of columns required to display the Text, starting from the StartColumn on a termin...
Definition: Encoding.h:62
Split getSplitAfterLastLine(unsigned TailOffset, unsigned ColumnLimit) const override
Manages the whitespaces around tokens and their replacements.
BreakableStringLiteral(const FormatToken &Tok, unsigned StartColumn, StringRef Prefix, StringRef Postfix, bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style)
Creates a breakable token for a single line string literal.
const FormatToken & Tok
bool mayReflow(unsigned LineIndex, llvm::Regex &CommentPragmasRegex) const override
Base class for single line tokens that can be broken.
Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, llvm::Regex &CommentPragmasRegex) const override
unsigned getLineCount() const override
unsigned ColumnLimit
The column limit.
Definition: Format.h:840
The current state when indenting a unwrapped line.
SmallVector< StringRef, 16 > Content
Should be used for JavaScript.
Definition: Format.h:1170
const AnnotatedLine * Line
unsigned getEscapeSequenceLength(StringRef Text)
Gets the length of an escape sequence inside a C++ string literal.
Definition: Encoding.h:97
A wrapper around a Token storing information about the whitespace characters preceding it...
Definition: FormatToken.h:120
unsigned getCodePointNumBytes(char FirstChar, Encoding Encoding)
Gets the number of bytes in a sequence representing a single codepoint and starting with FirstChar in...
Definition: Encoding.h:78
void replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces, unsigned StartOfTokenColumn, bool InPPDirective=false)
Replaces the whitespace in front of Tok.
SmallVector< FormatToken *, 16 > Tokens
#define false
Definition: stdbool.h:33
static LLVM_READONLY bool isAlphanumeric(unsigned char c)
Return true if this character is an ASCII letter or digit: [a-zA-Z0-9].
Definition: CharInfo.h:118
bool is(tok::TokenKind Kind) const
Definition: FormatToken.h:297
const bool InPPDirective
Various functions to configurably format source code.
void replaceWhitespaceBefore(unsigned LineIndex, unsigned PreviousEndColumn, unsigned ColumnLimit, Split SplitBefore, WhitespaceManager &Whitespaces) override
BreakableComment(const FormatToken &Token, unsigned StartColumn, bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style)
Creates a breakable token for a comment.
static LLVM_READONLY bool isPunctuation(unsigned char c)
Return true if this character is an ASCII punctuation character.
Definition: CharInfo.h:132
void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, WhitespaceManager &Whitespaces) override
StringRef TokenText
The raw text of the token.
Definition: FormatToken.h:168
Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, llvm::Regex &CommentPragmasRegex) const override
BreakableLineCommentSection(const FormatToken &Token, unsigned StartColumn, unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style)
Split getSplitBefore(unsigned LineIndex, unsigned PreviousEndColumn, unsigned ColumnLimit, llvm::Regex &CommentPragmasRegex) const override
The FormatStyle is used to configure the formatting to follow specific guidelines.
Definition: Format.h:46
void compressWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split, WhitespaceManager &Whitespaces) override
static bool mayReflowContent(StringRef Content)
unsigned getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset, StringRef::size_type Length) const override
LanguageKind Language
Language, this format style is targeted at.
Definition: Format.h:1185
unsigned getLineLengthAfterSplitBefore(unsigned LineIndex, unsigned TailOffset, unsigned PreviousEndColumn, unsigned ColumnLimit, Split SplitBefore) const override
Dataflow Directional Tag Classes.
Split getSplitBefore(unsigned LineIndex, unsigned PreviousEndColumn, unsigned ColumnLimit, llvm::Regex &CommentPragmasRegex) const override
Split getReflowSplit(StringRef Text, StringRef ReflowPrefix, unsigned PreviousEndColumn, unsigned ColumnLimit) const
bool Finalized
If true, this token has been fully formatted (indented and potentially re-formatted inside)...
Definition: FormatToken.h:295
unsigned getLineLengthAfterSplitBefore(unsigned LineIndex, unsigned TailOffset, unsigned PreviousEndColumn, unsigned ColumnLimit, Split SplitBefore) const override
unsigned TabWidth
The number of columns used for tab stops.
Definition: Format.h:1505
char __ovld __cnfn max(char x, char y)
Returns y if x < y, otherwise it returns x.
bool mayReflow(unsigned LineIndex, llvm::Regex &CommentPragmasRegex) const override
void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, WhitespaceManager &Whitespaces) override
static bool IsBlank(char C)
BreakableSingleLineToken(const FormatToken &Tok, unsigned StartColumn, StringRef Prefix, StringRef Postfix, bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style)
unsigned getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset, StringRef::size_type Length) const override
static BreakableToken::Split getStringSplit(StringRef Text, unsigned UsedColumns, unsigned ColumnLimit, unsigned TabWidth, encoding::Encoding Encoding)
void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, WhitespaceManager &Whitespaces) override
virtual unsigned getContentStartColumn(unsigned LineIndex, unsigned TailOffset) const =0
BreakableToken(const FormatToken &Tok, bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style)
StringRef Text
Definition: Format.cpp:1316
FormatToken * NextToken
The token that needs to be next formatted.
static BreakableToken::Split getCommentSplit(StringRef Text, unsigned ContentStartColumn, unsigned ColumnLimit, unsigned TabWidth, encoding::Encoding Encoding)
This file implements an indenter that manages the indentation of continuations.
SmallVector< StringRef, 16 > Lines
const encoding::Encoding Encoding
const FormatStyle & Style