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