]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/llvm/tools/clang/lib/Format/BreakableToken.h
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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, and
12 /// BreakableBlockComment classes, that contain token type-specific logic to
13 /// break long lines in tokens.
14 ///
15 //===----------------------------------------------------------------------===//
16
17 #ifndef LLVM_CLANG_FORMAT_BREAKABLETOKEN_H
18 #define LLVM_CLANG_FORMAT_BREAKABLETOKEN_H
19
20 #include "TokenAnnotator.h"
21 #include "WhitespaceManager.h"
22 #include <utility>
23
24 namespace clang {
25 namespace format {
26
27 class BreakableToken {
28 public:
29   BreakableToken(const SourceManager &SourceMgr, const FormatToken &Tok,
30                  unsigned StartColumn)
31       : Tok(Tok), StartColumn(StartColumn),
32         TokenText(SourceMgr.getCharacterData(Tok.getStartOfNonWhitespace()),
33                   Tok.TokenLength) {}
34   virtual ~BreakableToken() {}
35   virtual unsigned getLineCount() const = 0;
36   virtual unsigned getLineSize(unsigned Index) const = 0;
37   virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
38                                            unsigned TailOffset) const = 0;
39
40   // Contains starting character index and length of split.
41   typedef std::pair<StringRef::size_type, unsigned> Split;
42   virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
43                          unsigned ColumnLimit) const = 0;
44   virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
45                            bool InPPDirective,
46                            WhitespaceManager &Whitespaces) = 0;
47   virtual void trimLine(unsigned LineIndex, unsigned TailOffset,
48                         unsigned InPPDirective,
49                         WhitespaceManager &Whitespaces) {}
50 protected:
51   const FormatToken &Tok;
52   unsigned StartColumn;
53   StringRef TokenText;
54 };
55
56 class BreakableStringLiteral : public BreakableToken {
57 public:
58   BreakableStringLiteral(const SourceManager &SourceMgr, const FormatToken &Tok,
59                          unsigned StartColumn)
60       : BreakableToken(SourceMgr, Tok, StartColumn) {
61     assert(TokenText.startswith("\"") && TokenText.endswith("\""));
62   }
63
64   virtual unsigned getLineCount() const { return 1; }
65
66   virtual unsigned getLineSize(unsigned Index) const {
67     return Tok.TokenLength - 2; // Should be in sync with getLine
68   }
69
70   virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
71                                            unsigned TailOffset) const {
72     return getDecorationLength() + getLine().size() - TailOffset;
73   }
74
75   virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
76                          unsigned ColumnLimit) const {
77     StringRef Text = getLine().substr(TailOffset);
78     if (ColumnLimit <= getDecorationLength())
79       return Split(StringRef::npos, 0);
80     unsigned MaxSplit = ColumnLimit - getDecorationLength();
81     assert(MaxSplit < Text.size());
82     StringRef::size_type SpaceOffset = Text.rfind(' ', MaxSplit);
83     if (SpaceOffset != StringRef::npos && SpaceOffset != 0)
84       return Split(SpaceOffset + 1, 0);
85     StringRef::size_type SlashOffset = Text.rfind('/', MaxSplit);
86     if (SlashOffset != StringRef::npos && SlashOffset != 0)
87       return Split(SlashOffset + 1, 0);
88     StringRef::size_type SplitPoint = getStartOfCharacter(Text, MaxSplit);
89     if (SplitPoint != StringRef::npos && SplitPoint > 1)
90       // Do not split at 0.
91       return Split(SplitPoint, 0);
92     return Split(StringRef::npos, 0);
93   }
94
95   virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
96                            bool InPPDirective, WhitespaceManager &Whitespaces) {
97     unsigned WhitespaceStartColumn = StartColumn + Split.first + 2;
98     Whitespaces.breakToken(Tok, 1 + TailOffset + Split.first, Split.second,
99                            "\"", "\"", InPPDirective, StartColumn,
100                            WhitespaceStartColumn);
101   }
102
103 private:
104   StringRef getLine() const {
105     // Get string without quotes.
106     // FIXME: Handle string prefixes.
107     return TokenText.substr(1, TokenText.size() - 2);
108   }
109
110   unsigned getDecorationLength() const { return StartColumn + 2; }
111
112   static StringRef::size_type getStartOfCharacter(StringRef Text,
113                                                   StringRef::size_type Offset) {
114     StringRef::size_type NextEscape = Text.find('\\');
115     while (NextEscape != StringRef::npos && NextEscape < Offset) {
116       StringRef::size_type SequenceLength =
117           getEscapeSequenceLength(Text.substr(NextEscape));
118       if (Offset < NextEscape + SequenceLength)
119         return NextEscape;
120       NextEscape = Text.find('\\', NextEscape + SequenceLength);
121     }
122     return Offset;
123   }
124
125   static unsigned getEscapeSequenceLength(StringRef Text) {
126     assert(Text[0] == '\\');
127     if (Text.size() < 2)
128       return 1;
129
130     switch (Text[1]) {
131     case 'u':
132       return 6;
133     case 'U':
134       return 10;
135     case 'x':
136       return getHexLength(Text);
137     default:
138       if (Text[1] >= '0' && Text[1] <= '7')
139         return getOctalLength(Text);
140       return 2;
141     }
142   }
143
144   static unsigned getHexLength(StringRef Text) {
145     unsigned I = 2; // Point after '\x'.
146     while (I < Text.size() && ((Text[I] >= '0' && Text[I] <= '9') ||
147                                (Text[I] >= 'a' && Text[I] <= 'f') ||
148                                (Text[I] >= 'A' && Text[I] <= 'F'))) {
149       ++I;
150     }
151     return I;
152   }
153
154   static unsigned getOctalLength(StringRef Text) {
155     unsigned I = 1;
156     while (I < Text.size() && I < 4 && (Text[I] >= '0' && Text[I] <= '7')) {
157       ++I;
158     }
159     return I;
160   }
161
162 };
163
164 class BreakableComment : public BreakableToken {
165 public:
166   virtual unsigned getLineSize(unsigned Index) const {
167     return getLine(Index).size();
168   }
169
170   virtual unsigned getLineCount() const { return Lines.size(); }
171
172   virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
173                                            unsigned TailOffset) const {
174     return getContentStartColumn(LineIndex, TailOffset) +
175            getLine(LineIndex).size() - TailOffset;
176   }
177
178   virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
179                          unsigned ColumnLimit) const;
180   virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
181                            bool InPPDirective, WhitespaceManager &Whitespaces);
182
183 protected:
184   BreakableComment(const SourceManager &SourceMgr, const FormatToken &Tok,
185                    unsigned StartColumn)
186       : BreakableToken(SourceMgr, Tok, StartColumn) {}
187
188   // Get comment lines without /* */, common prefix and trailing whitespace.
189   // Last line is not trimmed, as it is terminated by */, so its trailing
190   // whitespace is not really trailing.
191   StringRef getLine(unsigned Index) const {
192     return Index < Lines.size() - 1 ? Lines[Index].rtrim() : Lines[Index];
193   }
194
195   unsigned getContentStartColumn(unsigned LineIndex,
196                                  unsigned TailOffset) const {
197     return (TailOffset == 0 && LineIndex == 0)
198                ? StartColumn
199                : IndentAtLineBreak + Decoration.size();
200   }
201
202   unsigned IndentAtLineBreak;
203   StringRef Decoration;
204   SmallVector<StringRef, 16> Lines;
205 };
206
207 class BreakableBlockComment : public BreakableComment {
208 public:
209   BreakableBlockComment(const SourceManager &SourceMgr,
210                         const AnnotatedToken &Token, unsigned StartColumn);
211
212   void alignLines(WhitespaceManager &Whitespaces);
213
214   virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
215                                            unsigned TailOffset) const {
216     return BreakableComment::getLineLengthAfterSplit(LineIndex, TailOffset) +
217            (LineIndex + 1 < Lines.size() ? 0 : 2);
218   }
219
220   virtual void trimLine(unsigned LineIndex, unsigned TailOffset,
221                         unsigned InPPDirective, WhitespaceManager &Whitespaces);
222
223 private:
224   unsigned OriginalStartColumn;
225   unsigned CommonPrefixLength;
226 };
227
228 class BreakableLineComment : public BreakableComment {
229 public:
230   BreakableLineComment(const SourceManager &SourceMgr,
231                        const AnnotatedToken &Token, unsigned StartColumn);
232
233 private:
234   static StringRef getLineCommentPrefix(StringRef Comment);
235 };
236
237 } // namespace format
238 } // namespace clang
239
240 #endif // LLVM_CLANG_FORMAT_BREAKABLETOKEN_H