]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/Format/BreakableToken.h
Merge ^/head r317281 through r317502.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / Format / BreakableToken.h
1 //===--- BreakableToken.h - Format C++ code -------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief Declares BreakableToken, BreakableStringLiteral, BreakableComment,
12 /// BreakableBlockComment and BreakableLineCommentSection classes, that contain
13 /// token type-specific logic to break long lines in tokens and reflow content
14 /// between tokens.
15 ///
16 //===----------------------------------------------------------------------===//
17
18 #ifndef LLVM_CLANG_LIB_FORMAT_BREAKABLETOKEN_H
19 #define LLVM_CLANG_LIB_FORMAT_BREAKABLETOKEN_H
20
21 #include "Encoding.h"
22 #include "TokenAnnotator.h"
23 #include "WhitespaceManager.h"
24 #include "llvm/Support/Regex.h"
25 #include <utility>
26
27 namespace clang {
28 namespace format {
29
30 /// \brief Checks if \p Token switches formatting, like /* clang-format off */.
31 /// \p Token must be a comment.
32 bool switchesFormatting(const FormatToken &Token);
33
34 struct FormatStyle;
35
36 /// \brief Base class for strategies on how to break tokens.
37 ///
38 /// This is organised around the concept of a \c Split, which is a whitespace
39 /// range that signifies a position of the content of a token where a
40 /// reformatting might be done. Operating with splits is divided into 3
41 /// operations:
42 /// - getSplit, for finding a split starting at a position,
43 /// - getLineLengthAfterSplit, for calculating the size in columns of the rest
44 ///   of the content after a split has been used for breaking, and
45 /// - insertBreak, for executing the split using a whitespace manager.
46 ///
47 /// There is a pair of operations that are used to compress a long whitespace
48 /// range with a single space if that will bring the line lenght under the
49 /// column limit:
50 /// - getLineLengthAfterCompression, for calculating the size in columns of the
51 ///   line after a whitespace range has been compressed, and
52 /// - compressWhitespace, for executing the whitespace compression using a
53 ///   whitespace manager; note that the compressed whitespace may be in the
54 ///   middle of the original line and of the reformatted line.
55 ///
56 /// For tokens where the whitespace before each line needs to be also
57 /// reformatted, for example for tokens supporting reflow, there are analogous
58 /// operations that might be executed before the main line breaking occurs:
59 /// - getSplitBefore, for finding a split such that the content preceding it
60 ///   needs to be specially reflown,
61 /// - getLineLengthAfterSplitBefore, for calculating the line length in columns
62 ///   of the remainder of the content after the beginning of the content has
63 ///   been reformatted, and
64 /// - replaceWhitespaceBefore, for executing the reflow using a whitespace
65 ///   manager.
66 ///
67 /// FIXME: The interface seems set in stone, so we might want to just pull the
68 /// strategy into the class, instead of controlling it from the outside.
69 class BreakableToken {
70 public:
71   /// \brief Contains starting character index and length of split.
72   typedef std::pair<StringRef::size_type, unsigned> Split;
73
74   virtual ~BreakableToken() {}
75
76   /// \brief Returns the number of lines in this token in the original code.
77   virtual unsigned getLineCount() const = 0;
78
79   /// \brief Returns the number of columns required to format the piece of line
80   /// at \p LineIndex, from byte offset \p TailOffset with length \p Length.
81   ///
82   /// Note that previous breaks are not taken into account. \p TailOffset is
83   /// always specified from the start of the (original) line.
84   /// \p Length can be set to StringRef::npos, which means "to the end of line".
85   virtual unsigned
86   getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset,
87                           StringRef::size_type Length) const = 0;
88
89   /// \brief Returns a range (offset, length) at which to break the line at
90   /// \p LineIndex, if previously broken at \p TailOffset. If possible, do not
91   /// violate \p ColumnLimit.
92   virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
93                          unsigned ColumnLimit,
94                          llvm::Regex &CommentPragmasRegex) const = 0;
95
96   /// \brief Emits the previously retrieved \p Split via \p Whitespaces.
97   virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
98                            WhitespaceManager &Whitespaces) = 0;
99
100   /// \brief Returns the number of columns required to format the piece of line
101   /// at \p LineIndex, from byte offset \p TailOffset after the whitespace range
102   /// \p Split has been compressed into a single space.
103   unsigned getLineLengthAfterCompression(unsigned RemainingTokenColumns,
104                                          Split Split) const;
105
106   /// \brief Replaces the whitespace range described by \p Split with a single
107   /// space.
108   virtual void compressWhitespace(unsigned LineIndex, unsigned TailOffset,
109                                   Split Split,
110                                   WhitespaceManager &Whitespaces) = 0;
111
112   /// \brief Returns a whitespace range (offset, length) of the content at
113   /// \p LineIndex such that the content preceding this range needs to be
114   /// reformatted before any breaks are made to this line.
115   ///
116   /// \p PreviousEndColumn is the end column of the previous line after
117   /// formatting.
118   ///
119   /// A result having offset == StringRef::npos means that no piece of the line
120   /// needs to be reformatted before any breaks are made.
121   virtual Split getSplitBefore(unsigned LineIndex, unsigned PreviousEndColumn,
122                                unsigned ColumnLimit,
123                                llvm::Regex &CommentPragmasRegex) const {
124     return Split(StringRef::npos, 0);
125   }
126
127   /// \brief Returns the number of columns required to format the piece of line
128   /// at \p LineIndex after the content preceding the whitespace range specified
129   /// \p SplitBefore has been reformatted, but before any breaks are made to
130   /// this line.
131   virtual unsigned getLineLengthAfterSplitBefore(unsigned LineIndex,
132                                                  unsigned TailOffset,
133                                                  unsigned PreviousEndColumn,
134                                                  unsigned ColumnLimit,
135                                                  Split SplitBefore) const {
136     return getLineLengthAfterSplit(LineIndex, TailOffset, StringRef::npos);
137   }
138
139   /// \brief Replaces the whitespace between \p LineIndex-1 and \p LineIndex.
140   /// Performs a reformatting of the content at \p LineIndex preceding the
141   /// whitespace range \p SplitBefore.
142   virtual void replaceWhitespaceBefore(unsigned LineIndex,
143                                        unsigned PreviousEndColumn,
144                                        unsigned ColumnLimit, Split SplitBefore,
145                                        WhitespaceManager &Whitespaces) {}
146
147   /// \brief Updates the next token of \p State to the next token after this
148   /// one. This can be used when this token manages a set of underlying tokens
149   /// as a unit and is responsible for the formatting of the them.
150   virtual void updateNextToken(LineState &State) const {}
151
152 protected:
153   BreakableToken(const FormatToken &Tok, bool InPPDirective,
154                  encoding::Encoding Encoding, const FormatStyle &Style)
155       : Tok(Tok), InPPDirective(InPPDirective), Encoding(Encoding),
156         Style(Style) {}
157
158   const FormatToken &Tok;
159   const bool InPPDirective;
160   const encoding::Encoding Encoding;
161   const FormatStyle &Style;
162 };
163
164 /// \brief Base class for single line tokens that can be broken.
165 ///
166 /// \c getSplit() needs to be implemented by child classes.
167 class BreakableSingleLineToken : public BreakableToken {
168 public:
169   unsigned getLineCount() const override;
170   unsigned getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset,
171                                    StringRef::size_type Length) const override;
172
173 protected:
174   BreakableSingleLineToken(const FormatToken &Tok, unsigned StartColumn,
175                            StringRef Prefix, StringRef Postfix,
176                            bool InPPDirective, encoding::Encoding Encoding,
177                            const FormatStyle &Style);
178
179   // The column in which the token starts.
180   unsigned StartColumn;
181   // The prefix a line needs after a break in the token.
182   StringRef Prefix;
183   // The postfix a line needs before introducing a break.
184   StringRef Postfix;
185   // The token text excluding the prefix and postfix.
186   StringRef Line;
187 };
188
189 class BreakableStringLiteral : public BreakableSingleLineToken {
190 public:
191   /// \brief Creates a breakable token for a single line string literal.
192   ///
193   /// \p StartColumn specifies the column in which the token will start
194   /// after formatting.
195   BreakableStringLiteral(const FormatToken &Tok, unsigned StartColumn,
196                          StringRef Prefix, StringRef Postfix,
197                          bool InPPDirective, encoding::Encoding Encoding,
198                          const FormatStyle &Style);
199
200   Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit,
201                  llvm::Regex &CommentPragmasRegex) const override;
202   void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
203                    WhitespaceManager &Whitespaces) override;
204   void compressWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split,
205                           WhitespaceManager &Whitespaces) override {}
206 };
207
208 class BreakableComment : public BreakableToken {
209 protected:
210   /// \brief Creates a breakable token for a comment.
211   ///
212   /// \p StartColumn specifies the column in which the comment will start after
213   /// formatting.
214   BreakableComment(const FormatToken &Token, unsigned StartColumn,
215                    bool InPPDirective, encoding::Encoding Encoding,
216                    const FormatStyle &Style);
217
218 public:
219   unsigned getLineCount() const override;
220   Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit,
221                  llvm::Regex &CommentPragmasRegex) const override;
222   void compressWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split,
223                           WhitespaceManager &Whitespaces) override;
224
225 protected:
226   virtual unsigned getContentStartColumn(unsigned LineIndex,
227                                          unsigned TailOffset) const = 0;
228
229   // Returns a split that divides Text into a left and right parts, such that
230   // the left part is suitable for reflowing after PreviousEndColumn.
231   Split getReflowSplit(StringRef Text, StringRef ReflowPrefix,
232                        unsigned PreviousEndColumn, unsigned ColumnLimit) const;
233
234   // Returns the token containing the line at LineIndex.
235   const FormatToken &tokenAt(unsigned LineIndex) const;
236
237   // Checks if the content of line LineIndex may be reflown with the previous
238   // line.
239   virtual bool mayReflow(unsigned LineIndex,
240                          llvm::Regex &CommentPragmasRegex) const = 0;
241
242   // Contains the original text of the lines of the block comment.
243   //
244   // In case of a block comments, excludes the leading /* in the first line and
245   // trailing */ in the last line. In case of line comments, excludes the
246   // leading // and spaces.
247   SmallVector<StringRef, 16> Lines;
248
249   // Contains the text of the lines excluding all leading and trailing
250   // whitespace between the lines. Note that the decoration (if present) is also
251   // not considered part of the text.
252   SmallVector<StringRef, 16> Content;
253
254   // Tokens[i] contains a reference to the token containing Lines[i] if the
255   // whitespace range before that token is managed by this block.
256   // Otherwise, Tokens[i] is a null pointer.
257   SmallVector<FormatToken *, 16> Tokens;
258
259   // ContentColumn[i] is the target column at which Content[i] should be.
260   // Note that this excludes a leading "* " or "*" in case of block comments
261   // where all lines have a "*" prefix, or the leading "// " or "//" in case of
262   // line comments.
263   //
264   // In block comments, the first line's target column is always positive. The
265   // remaining lines' target columns are relative to the first line to allow
266   // correct indentation of comments in \c WhitespaceManager. Thus they can be
267   // negative as well (in case the first line needs to be unindented more than
268   // there's actual whitespace in another line).
269   SmallVector<int, 16> ContentColumn;
270
271   // The intended start column of the first line of text from this section.
272   unsigned StartColumn;
273
274   // The prefix to use in front a line that has been reflown up.
275   // For example, when reflowing the second line after the first here:
276   // // comment 1
277   // // comment 2
278   // we expect:
279   // // comment 1 comment 2
280   // and not:
281   // // comment 1comment 2
282   StringRef ReflowPrefix = " ";
283 };
284
285 class BreakableBlockComment : public BreakableComment {
286 public:
287   BreakableBlockComment(const FormatToken &Token, unsigned StartColumn,
288                         unsigned OriginalStartColumn, bool FirstInLine,
289                         bool InPPDirective, encoding::Encoding Encoding,
290                         const FormatStyle &Style);
291
292   unsigned getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset,
293                                    StringRef::size_type Length) const override;
294   void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
295                    WhitespaceManager &Whitespaces) override;
296   Split getSplitBefore(unsigned LineIndex, unsigned PreviousEndColumn,
297                        unsigned ColumnLimit,
298                        llvm::Regex &CommentPragmasRegex) const override;
299   unsigned getLineLengthAfterSplitBefore(unsigned LineIndex,
300                                          unsigned TailOffset,
301                                          unsigned PreviousEndColumn,
302                                          unsigned ColumnLimit,
303                                          Split SplitBefore) const override;
304   void replaceWhitespaceBefore(unsigned LineIndex, unsigned PreviousEndColumn,
305                                unsigned ColumnLimit, Split SplitBefore,
306                                WhitespaceManager &Whitespaces) override;
307   bool mayReflow(unsigned LineIndex,
308                  llvm::Regex &CommentPragmasRegex) const override;
309
310 private:
311   // Rearranges the whitespace between Lines[LineIndex-1] and Lines[LineIndex].
312   //
313   // Updates Content[LineIndex-1] and Content[LineIndex] by stripping off
314   // leading and trailing whitespace.
315   //
316   // Sets ContentColumn to the intended column in which the text at
317   // Lines[LineIndex] starts (note that the decoration, if present, is not
318   // considered part of the text).
319   void adjustWhitespace(unsigned LineIndex, int IndentDelta);
320
321   // Computes the end column if the full Content from LineIndex gets reflown
322   // after PreviousEndColumn.
323   unsigned getReflownColumn(StringRef Content, unsigned LineIndex,
324                             unsigned PreviousEndColumn) const;
325
326   unsigned getContentStartColumn(unsigned LineIndex,
327                                  unsigned TailOffset) const override;
328
329   // The column at which the text of a broken line should start.
330   // Note that an optional decoration would go before that column.
331   // IndentAtLineBreak is a uniform position for all lines in a block comment,
332   // regardless of their relative position.
333   // FIXME: Revisit the decision to do this; the main reason was to support
334   // patterns like
335   // /**************//**
336   //  * Comment
337   // We could also support such patterns by special casing the first line
338   // instead.
339   unsigned IndentAtLineBreak;
340
341   // This is to distinguish between the case when the last line was empty and
342   // the case when it started with a decoration ("*" or "* ").
343   bool LastLineNeedsDecoration;
344
345   // Either "* " if all lines begin with a "*", or empty.
346   StringRef Decoration;
347
348   // If this block comment has decorations, this is the column of the start of
349   // the decorations.
350   unsigned DecorationColumn;
351 };
352
353 class BreakableLineCommentSection : public BreakableComment {
354 public:
355   BreakableLineCommentSection(const FormatToken &Token, unsigned StartColumn,
356                               unsigned OriginalStartColumn, bool FirstInLine,
357                               bool InPPDirective, encoding::Encoding Encoding,
358                               const FormatStyle &Style);
359
360   unsigned getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset,
361                                    StringRef::size_type Length) const override;
362   void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
363                    WhitespaceManager &Whitespaces) override;
364   Split getSplitBefore(unsigned LineIndex, unsigned PreviousEndColumn,
365                        unsigned ColumnLimit,
366                        llvm::Regex &CommentPragmasRegex) const override;
367   unsigned getLineLengthAfterSplitBefore(unsigned LineIndex,
368                                          unsigned TailOffset,
369                                          unsigned PreviousEndColumn,
370                                          unsigned ColumnLimit,
371                                          Split SplitBefore) const override;
372   void replaceWhitespaceBefore(unsigned LineIndex, unsigned PreviousEndColumn,
373                                unsigned ColumnLimit, Split SplitBefore,
374                                WhitespaceManager &Whitespaces) override;
375   void updateNextToken(LineState &State) const override;
376   bool mayReflow(unsigned LineIndex,
377                  llvm::Regex &CommentPragmasRegex) const override;
378
379 private:
380   unsigned getContentStartColumn(unsigned LineIndex,
381                                  unsigned TailOffset) const override;
382
383   // OriginalPrefix[i] contains the original prefix of line i, including
384   // trailing whitespace before the start of the content. The indentation
385   // preceding the prefix is not included.
386   // For example, if the line is:
387   // // content
388   // then the original prefix is "// ".
389   SmallVector<StringRef, 16> OriginalPrefix;
390
391   // Prefix[i] contains the intended leading "//" with trailing spaces to
392   // account for the indentation of content within the comment at line i after
393   // formatting. It can be different than the original prefix when the original
394   // line starts like this:
395   // //content
396   // Then the original prefix is "//", but the prefix is "// ".
397   SmallVector<StringRef, 16> Prefix;
398
399   SmallVector<unsigned, 16> OriginalContentColumn;
400
401   /// \brief The token to which the last line of this breakable token belongs
402   /// to; nullptr if that token is the initial token.
403   ///
404   /// The distinction is because if the token of the last line of this breakable
405   /// token is distinct from the initial token, this breakable token owns the
406   /// whitespace before the token of the last line, and the whitespace manager
407   /// must be able to modify it.
408   FormatToken *LastLineTok = nullptr;
409 };
410 } // namespace format
411 } // namespace clang
412
413 #endif