1 //===--- FormatToken.h - Format C++ code ------------------------*- C++ -*-===//
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 This file contains the declaration of the FormatToken, a wrapper
12 /// around Token with additional information related to formatting.
13 ///
14 //===----------------------------------------------------------------------===//
15 
16 #ifndef LLVM_CLANG_FORMAT_FORMAT_TOKEN_H
17 #define LLVM_CLANG_FORMAT_FORMAT_TOKEN_H
18 
19 #include "clang/Basic/OperatorPrecedence.h"
20 #include "clang/Lex/Lexer.h"
21 
22 namespace clang {
23 namespace format {
24 
25 enum TokenType {
26   TT_BinaryOperator,
27   TT_BlockComment,
28   TT_CastRParen,
29   TT_ConditionalExpr,
30   TT_CtorInitializerColon,
31   TT_DesignatedInitializerPeriod,
32   TT_ImplicitStringLiteral,
33   TT_InlineASMColon,
34   TT_InheritanceColon,
35   TT_FunctionTypeLParen,
36   TT_LineComment,
37   TT_ObjCArrayLiteral,
38   TT_ObjCBlockLParen,
39   TT_ObjCDecl,
40   TT_ObjCDictLiteral,
41   TT_ObjCForIn,
42   TT_ObjCMethodExpr,
43   TT_ObjCMethodSpecifier,
44   TT_ObjCProperty,
45   TT_ObjCSelectorName,
46   TT_OverloadedOperator,
47   TT_OverloadedOperatorLParen,
48   TT_PointerOrReference,
49   TT_PureVirtualSpecifier,
50   TT_RangeBasedForLoopColon,
51   TT_StartOfName,
52   TT_TemplateCloser,
53   TT_TemplateOpener,
54   TT_TrailingUnaryOperator,
55   TT_UnaryOperator,
56   TT_Unknown
57 };
58 
59 /// \brief A wrapper around a \c Token storing information about the
60 /// whitespace characters preceeding it.
61 struct FormatToken {
62   FormatToken()
63       : NewlinesBefore(0), HasUnescapedNewline(false), LastNewlineOffset(0),
64         CodePointCount(0), IsFirst(false), MustBreakBefore(false),
65         Type(TT_Unknown), SpacesRequiredBefore(0), CanBreakBefore(false),
66         ClosesTemplateDeclaration(false), ParameterCount(0), TotalLength(0),
67         UnbreakableTailLength(0), BindingStrength(0), SplitPenalty(0),
68         LongestObjCSelectorName(0), FakeRParens(0), LastInChainOfCalls(false),
69         PartOfMultiVariableDeclStmt(false), MatchingParen(NULL), Previous(NULL),
70         Next(NULL) {}
71 
72   /// \brief The \c Token.
73   Token Tok;
74 
75   /// \brief The number of newlines immediately before the \c Token.
76   ///
77   /// This can be used to determine what the user wrote in the original code
78   /// and thereby e.g. leave an empty line between two function definitions.
79   unsigned NewlinesBefore;
80 
81   /// \brief Whether there is at least one unescaped newline before the \c
82   /// Token.
83   bool HasUnescapedNewline;
84 
85   /// \brief The range of the whitespace immediately preceeding the \c Token.
86   SourceRange WhitespaceRange;
87 
88   /// \brief The offset just past the last '\n' in this token's leading
89   /// whitespace (relative to \c WhiteSpaceStart). 0 if there is no '\n'.
90   unsigned LastNewlineOffset;
91 
92   /// \brief The length of the non-whitespace parts of the token in CodePoints.
93   /// We need this to correctly measure number of columns a token spans.
94   unsigned CodePointCount;
95 
96   /// \brief Indicates that this is the first token.
97   bool IsFirst;
98 
99   /// \brief Whether there must be a line break before this token.
100   ///
101   /// This happens for example when a preprocessor directive ended directly
102   /// before the token.
103   bool MustBreakBefore;
104 
105   /// \brief Returns actual token start location without leading escaped
106   /// newlines and whitespace.
107   ///
108   /// This can be different to Tok.getLocation(), which includes leading escaped
109   /// newlines.
110   SourceLocation getStartOfNonWhitespace() const {
111     return WhitespaceRange.getEnd();
112   }
113 
114   /// \brief The raw text of the token.
115   ///
116   /// Contains the raw token text without leading whitespace and without leading
117   /// escaped newlines.
118   StringRef TokenText;
119 
120   TokenType Type;
121 
122   unsigned SpacesRequiredBefore;
123   bool CanBreakBefore;
124 
125   bool ClosesTemplateDeclaration;
126 
127   /// \brief Number of parameters, if this is "(", "[" or "<".
128   ///
129   /// This is initialized to 1 as we don't need to distinguish functions with
130   /// 0 parameters from functions with 1 parameter. Thus, we can simply count
131   /// the number of commas.
132   unsigned ParameterCount;
133 
134   /// \brief The total length of the line up to and including this token.
135   unsigned TotalLength;
136 
137   /// \brief The length of following tokens until the next natural split point,
138   /// or the next token that can be broken.
139   unsigned UnbreakableTailLength;
140 
141   // FIXME: Come up with a 'cleaner' concept.
142   /// \brief The binding strength of a token. This is a combined value of
143   /// operator precedence, parenthesis nesting, etc.
144   unsigned BindingStrength;
145 
146   /// \brief Penalty for inserting a line break before this token.
147   unsigned SplitPenalty;
148 
149   /// \brief If this is the first ObjC selector name in an ObjC method
150   /// definition or call, this contains the length of the longest name.
151   unsigned LongestObjCSelectorName;
152 
153   /// \brief Stores the number of required fake parentheses and the
154   /// corresponding operator precedence.
155   ///
156   /// If multiple fake parentheses start at a token, this vector stores them in
157   /// reverse order, i.e. inner fake parenthesis first.
158   SmallVector<prec::Level, 4> FakeLParens;
159   /// \brief Insert this many fake ) after this token for correct indentation.
160   unsigned FakeRParens;
161 
162   /// \brief Is this the last "." or "->" in a builder-type call?
163   bool LastInChainOfCalls;
164 
165   /// \brief Is this token part of a \c DeclStmt defining multiple variables?
166   ///
167   /// Only set if \c Type == \c TT_StartOfName.
168   bool PartOfMultiVariableDeclStmt;
169 
170   bool is(tok::TokenKind Kind) const { return Tok.is(Kind); }
171 
172   bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const {
173     return is(K1) || is(K2);
174   }
175 
176   bool isOneOf(tok::TokenKind K1, tok::TokenKind K2, tok::TokenKind K3) const {
177     return is(K1) || is(K2) || is(K3);
178   }
179 
180   bool isOneOf(tok::TokenKind K1, tok::TokenKind K2, tok::TokenKind K3,
181                tok::TokenKind K4, tok::TokenKind K5 = tok::NUM_TOKENS,
182                tok::TokenKind K6 = tok::NUM_TOKENS,
183                tok::TokenKind K7 = tok::NUM_TOKENS,
184                tok::TokenKind K8 = tok::NUM_TOKENS,
185                tok::TokenKind K9 = tok::NUM_TOKENS,
186                tok::TokenKind K10 = tok::NUM_TOKENS,
187                tok::TokenKind K11 = tok::NUM_TOKENS,
188                tok::TokenKind K12 = tok::NUM_TOKENS) const {
189     return is(K1) || is(K2) || is(K3) || is(K4) || is(K5) || is(K6) || is(K7) ||
190            is(K8) || is(K9) || is(K10) || is(K11) || is(K12);
191   }
192 
193   bool isNot(tok::TokenKind Kind) const { return Tok.isNot(Kind); }
194 
195   bool isObjCAtKeyword(tok::ObjCKeywordKind Kind) const {
196     return Tok.isObjCAtKeyword(Kind);
197   }
198 
199   bool isAccessSpecifier(bool ColonRequired = true) const {
200     return isOneOf(tok::kw_public, tok::kw_protected, tok::kw_private) &&
201            (!ColonRequired || (Next && Next->is(tok::colon)));
202   }
203 
204   bool isObjCAccessSpecifier() const {
205     return is(tok::at) && Next && (Next->isObjCAtKeyword(tok::objc_public) ||
206                                    Next->isObjCAtKeyword(tok::objc_protected) ||
207                                    Next->isObjCAtKeyword(tok::objc_package) ||
208                                    Next->isObjCAtKeyword(tok::objc_private));
209   }
210 
211   /// \brief Returns whether \p Tok is ([{ or a template opening <.
212   bool opensScope() const {
213     return isOneOf(tok::l_paren, tok::l_brace, tok::l_square) ||
214            Type == TT_TemplateOpener;
215 
216   }
217   /// \brief Returns whether \p Tok is )]} or a template opening >.
218   bool closesScope() const {
219     return isOneOf(tok::r_paren, tok::r_brace, tok::r_square) ||
220            Type == TT_TemplateCloser;
221   }
222 
223   bool isUnaryOperator() const {
224     switch (Tok.getKind()) {
225     case tok::plus:
226     case tok::plusplus:
227     case tok::minus:
228     case tok::minusminus:
229     case tok::exclaim:
230     case tok::tilde:
231     case tok::kw_sizeof:
232     case tok::kw_alignof:
233       return true;
234     default:
235       return false;
236     }
237   }
238   bool isBinaryOperator() const {
239     // Comma is a binary operator, but does not behave as such wrt. formatting.
240     return getPrecedence() > prec::Comma;
241   }
242   bool isTrailingComment() const {
243     return is(tok::comment) && (!Next || Next->NewlinesBefore > 0);
244   }
245 
246   prec::Level getPrecedence() const {
247     return getBinOpPrecedence(Tok.getKind(), true, true);
248   }
249 
250   /// \brief Returns the previous token ignoring comments.
251   FormatToken *getPreviousNoneComment() const {
252     FormatToken *Tok = Previous;
253     while (Tok != NULL && Tok->is(tok::comment))
254       Tok = Tok->Previous;
255     return Tok;
256   }
257 
258   /// \brief Returns the next token ignoring comments.
259   const FormatToken *getNextNoneComment() const {
260     const FormatToken *Tok = Next;
261     while (Tok != NULL && Tok->is(tok::comment))
262       Tok = Tok->Next;
263     return Tok;
264   }
265 
266   FormatToken *MatchingParen;
267 
268   FormatToken *Previous;
269   FormatToken *Next;
270 
271 private:
272   // Disallow copying.
273   FormatToken(const FormatToken &);
274   void operator=(const FormatToken &);
275 };
276 
277 } // namespace format
278 } // namespace clang
279 
280 #endif // LLVM_CLANG_FORMAT_FORMAT_TOKEN_H
281