annotate clang/lib/Format/BreakableToken.cpp @ 173:0572611fdcc8 llvm10 llvm12

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