1 //===--- BreakableToken.h - Format C++ code -------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// \brief Declares BreakableToken, BreakableStringLiteral, and
12 /// BreakableBlockComment classes, that contain token type-specific logic to
13 /// break long lines in tokens.
15 //===----------------------------------------------------------------------===//
17 #ifndef LLVM_CLANG_FORMAT_BREAKABLETOKEN_H
18 #define LLVM_CLANG_FORMAT_BREAKABLETOKEN_H
20 #include "TokenAnnotator.h"
21 #include "WhitespaceManager.h"
27 class BreakableToken {
29 BreakableToken(const SourceManager &SourceMgr, const FormatToken &Tok,
31 : Tok(Tok), StartColumn(StartColumn),
32 TokenText(SourceMgr.getCharacterData(Tok.getStartOfNonWhitespace()),
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;
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,
46 WhitespaceManager &Whitespaces) = 0;
47 virtual void trimLine(unsigned LineIndex, unsigned TailOffset,
48 unsigned InPPDirective,
49 WhitespaceManager &Whitespaces) {}
51 const FormatToken &Tok;
56 class BreakableStringLiteral : public BreakableToken {
58 BreakableStringLiteral(const SourceManager &SourceMgr, const FormatToken &Tok,
60 : BreakableToken(SourceMgr, Tok, StartColumn) {
61 assert(TokenText.startswith("\"") && TokenText.endswith("\""));
64 virtual unsigned getLineCount() const { return 1; }
66 virtual unsigned getLineSize(unsigned Index) const {
67 return Tok.TokenLength - 2; // Should be in sync with getLine
70 virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
71 unsigned TailOffset) const {
72 return getDecorationLength() + getLine().size() - TailOffset;
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)
91 return Split(SplitPoint, 0);
92 return Split(StringRef::npos, 0);
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);
104 StringRef getLine() const {
105 // Get string without quotes.
106 // FIXME: Handle string prefixes.
107 return TokenText.substr(1, TokenText.size() - 2);
110 unsigned getDecorationLength() const { return StartColumn + 2; }
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)
120 NextEscape = Text.find('\\', NextEscape + SequenceLength);
125 static unsigned getEscapeSequenceLength(StringRef Text) {
126 assert(Text[0] == '\\');
136 return getHexLength(Text);
138 if (Text[1] >= '0' && Text[1] <= '7')
139 return getOctalLength(Text);
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'))) {
154 static unsigned getOctalLength(StringRef Text) {
156 while (I < Text.size() && I < 4 && (Text[I] >= '0' && Text[I] <= '7')) {
164 class BreakableComment : public BreakableToken {
166 virtual unsigned getLineSize(unsigned Index) const {
167 return getLine(Index).size();
170 virtual unsigned getLineCount() const { return Lines.size(); }
172 virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
173 unsigned TailOffset) const {
174 return getContentStartColumn(LineIndex, TailOffset) +
175 getLine(LineIndex).size() - TailOffset;
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);
184 BreakableComment(const SourceManager &SourceMgr, const FormatToken &Tok,
185 unsigned StartColumn)
186 : BreakableToken(SourceMgr, Tok, StartColumn) {}
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];
195 unsigned getContentStartColumn(unsigned LineIndex,
196 unsigned TailOffset) const {
197 return (TailOffset == 0 && LineIndex == 0)
199 : IndentAtLineBreak + Decoration.size();
202 unsigned IndentAtLineBreak;
203 StringRef Decoration;
204 SmallVector<StringRef, 16> Lines;
207 class BreakableBlockComment : public BreakableComment {
209 BreakableBlockComment(const SourceManager &SourceMgr,
210 const AnnotatedToken &Token, unsigned StartColumn);
212 void alignLines(WhitespaceManager &Whitespaces);
214 virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
215 unsigned TailOffset) const {
216 return BreakableComment::getLineLengthAfterSplit(LineIndex, TailOffset) +
217 (LineIndex + 1 < Lines.size() ? 0 : 2);
220 virtual void trimLine(unsigned LineIndex, unsigned TailOffset,
221 unsigned InPPDirective, WhitespaceManager &Whitespaces);
224 unsigned OriginalStartColumn;
225 unsigned CommonPrefixLength;
228 class BreakableLineComment : public BreakableComment {
230 BreakableLineComment(const SourceManager &SourceMgr,
231 const AnnotatedToken &Token, unsigned StartColumn);
234 static StringRef getLineCommentPrefix(StringRef Comment);
237 } // namespace format
240 #endif // LLVM_CLANG_FORMAT_BREAKABLETOKEN_H