blob: 80089de207ac69cb76ed944d586f6dfe9d12502a [file] [log] [blame]
Daniel Jasper32d28ee2013-01-29 21:01:14 +00001//===--- TokenAnnotator.cpp - 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 This file implements a token annotator, i.e. creates
12/// \c AnnotatedTokens out of \c FormatTokens with required extra information.
13///
14//===----------------------------------------------------------------------===//
15
16#include "TokenAnnotator.h"
17#include "clang/Basic/SourceManager.h"
18#include "clang/Lex/Lexer.h"
19
20namespace clang {
21namespace format {
22
Nico Weberee0feec2013-02-05 16:21:00 +000023static bool isUnaryOperator(const AnnotatedToken &Tok) {
24 switch (Tok.FormatTok.Tok.getKind()) {
25 case tok::plus:
26 case tok::plusplus:
27 case tok::minus:
28 case tok::minusminus:
29 case tok::exclaim:
30 case tok::tilde:
31 case tok::kw_sizeof:
32 case tok::kw_alignof:
33 return true;
34 default:
35 return false;
36 }
37}
38
Daniel Jasper32d28ee2013-01-29 21:01:14 +000039static bool isBinaryOperator(const AnnotatedToken &Tok) {
40 // Comma is a binary operator, but does not behave as such wrt. formatting.
41 return getPrecedence(Tok) > prec::Comma;
42}
43
Daniel Jasper01786732013-02-04 07:21:18 +000044// Returns the previous token ignoring comments.
Nico Weber4ed7f3e2013-02-06 16:54:35 +000045static AnnotatedToken *getPreviousToken(AnnotatedToken &Tok) {
46 AnnotatedToken *PrevToken = Tok.Parent;
Daniel Jasper01786732013-02-04 07:21:18 +000047 while (PrevToken != NULL && PrevToken->is(tok::comment))
48 PrevToken = PrevToken->Parent;
49 return PrevToken;
50}
Nico Weber4ed7f3e2013-02-06 16:54:35 +000051static const AnnotatedToken *getPreviousToken(const AnnotatedToken &Tok) {
52 return getPreviousToken(const_cast<AnnotatedToken &>(Tok));
53}
Daniel Jasper01786732013-02-04 07:21:18 +000054
Daniel Jasper29f123b2013-02-08 15:28:42 +000055static bool isTrailingComment(AnnotatedToken *Tok) {
56 return Tok != NULL && Tok->is(tok::comment) &&
57 (Tok->Children.empty() ||
58 Tok->Children[0].FormatTok.NewlinesBefore > 0);
59}
60
Daniel Jasper01786732013-02-04 07:21:18 +000061// Returns the next token ignoring comments.
62static const AnnotatedToken *getNextToken(const AnnotatedToken &Tok) {
63 if (Tok.Children.empty())
64 return NULL;
65 const AnnotatedToken *NextToken = &Tok.Children[0];
66 while (NextToken->is(tok::comment)) {
67 if (NextToken->Children.empty())
68 return NULL;
69 NextToken = &NextToken->Children[0];
70 }
71 return NextToken;
72}
73
Daniel Jasper32d28ee2013-01-29 21:01:14 +000074/// \brief A parser that gathers additional information about tokens.
75///
76/// The \c TokenAnnotator tries to matches parenthesis and square brakets and
77/// store a parenthesis levels. It also tries to resolve matching "<" and ">"
78/// into template parameter lists.
79class AnnotatingParser {
80public:
Nico Weberc2e6d2a2013-02-11 15:32:15 +000081 AnnotatingParser(SourceManager &SourceMgr, Lexer &Lex, AnnotatedLine &Line,
82 IdentifierInfo &Ident_in)
Daniel Jasper01786732013-02-04 07:21:18 +000083 : SourceMgr(SourceMgr), Lex(Lex), Line(Line), CurrentToken(&Line.First),
Nico Weberc2e6d2a2013-02-11 15:32:15 +000084 KeywordVirtualFound(false), Ident_in(Ident_in) {
Daniel Jasper4e778092013-02-06 10:05:46 +000085 Contexts.push_back(Context(1, /*IsExpression=*/ false));
86 Contexts.back().LookForFunctionName = Line.MustBeDeclaration;
Daniel Jasper32d28ee2013-01-29 21:01:14 +000087 }
88
Nico Weber95e8e462013-02-12 16:17:07 +000089private:
Daniel Jasper32d28ee2013-01-29 21:01:14 +000090 bool parseAngle() {
91 if (CurrentToken == NULL)
92 return false;
Daniel Jasper4e778092013-02-06 10:05:46 +000093 ScopedContextCreator ContextCreator(*this, 10);
Daniel Jasper32d28ee2013-01-29 21:01:14 +000094 AnnotatedToken *Left = CurrentToken->Parent;
Daniel Jasper4e778092013-02-06 10:05:46 +000095 Contexts.back().IsExpression = false;
Daniel Jasper32d28ee2013-01-29 21:01:14 +000096 while (CurrentToken != NULL) {
97 if (CurrentToken->is(tok::greater)) {
98 Left->MatchingParen = CurrentToken;
99 CurrentToken->MatchingParen = Left;
100 CurrentToken->Type = TT_TemplateCloser;
101 next();
102 return true;
103 }
104 if (CurrentToken->is(tok::r_paren) || CurrentToken->is(tok::r_square) ||
105 CurrentToken->is(tok::r_brace))
106 return false;
107 if (CurrentToken->is(tok::pipepipe) || CurrentToken->is(tok::ampamp) ||
108 CurrentToken->is(tok::question) || CurrentToken->is(tok::colon))
109 return false;
110 if (CurrentToken->is(tok::comma))
111 ++Left->ParameterCount;
112 if (!consumeToken())
113 return false;
114 }
115 return false;
116 }
117
118 bool parseParens(bool LookForDecls = false) {
119 if (CurrentToken == NULL)
120 return false;
Daniel Jasper4e778092013-02-06 10:05:46 +0000121 ScopedContextCreator ContextCreator(*this, 1);
122
123 // FIXME: This is a bit of a hack. Do better.
124 Contexts.back().ColonIsForRangeExpr =
125 Contexts.size() == 2 && Contexts[0].ColonIsForRangeExpr;
126
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000127 bool StartsObjCMethodExpr = false;
128 AnnotatedToken *Left = CurrentToken->Parent;
129 if (CurrentToken->is(tok::caret)) {
130 // ^( starts a block.
131 Left->Type = TT_ObjCBlockLParen;
132 } else if (AnnotatedToken *MaybeSel = Left->Parent) {
133 // @selector( starts a selector.
134 if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Parent &&
135 MaybeSel->Parent->is(tok::at)) {
136 StartsObjCMethodExpr = true;
137 }
138 }
139
Daniel Jasper4e778092013-02-06 10:05:46 +0000140 if (StartsObjCMethodExpr) {
141 Contexts.back().ColonIsObjCMethodExpr = true;
142 Left->Type = TT_ObjCMethodExpr;
143 }
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000144
145 while (CurrentToken != NULL) {
146 // LookForDecls is set when "if (" has been seen. Check for
147 // 'identifier' '*' 'identifier' followed by not '=' -- this
148 // '*' has to be a binary operator but determineStarAmpUsage() will
149 // categorize it as an unary operator, so set the right type here.
150 if (LookForDecls && !CurrentToken->Children.empty()) {
151 AnnotatedToken &Prev = *CurrentToken->Parent;
152 AnnotatedToken &Next = CurrentToken->Children[0];
153 if (Prev.Parent->is(tok::identifier) &&
154 (Prev.is(tok::star) || Prev.is(tok::amp)) &&
155 CurrentToken->is(tok::identifier) && Next.isNot(tok::equal)) {
156 Prev.Type = TT_BinaryOperator;
157 LookForDecls = false;
158 }
159 }
160
161 if (CurrentToken->is(tok::r_paren)) {
162 Left->MatchingParen = CurrentToken;
163 CurrentToken->MatchingParen = Left;
164
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000165 if (StartsObjCMethodExpr) {
Daniel Jasper4e778092013-02-06 10:05:46 +0000166 CurrentToken->Type = TT_ObjCMethodExpr;
167 if (Contexts.back().FirstObjCSelectorName != NULL) {
168 Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
169 Contexts.back().LongestObjCSelectorName;
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000170 }
171 }
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000172
173 next();
174 return true;
175 }
176 if (CurrentToken->is(tok::r_square) || CurrentToken->is(tok::r_brace))
177 return false;
178 if (CurrentToken->is(tok::comma))
179 ++Left->ParameterCount;
180 if (!consumeToken())
181 return false;
182 }
183 return false;
184 }
185
186 bool parseSquare() {
187 if (!CurrentToken)
188 return false;
Daniel Jasper4e778092013-02-06 10:05:46 +0000189 ScopedContextCreator ContextCreator(*this, 10);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000190
191 // A '[' could be an index subscript (after an indentifier or after
Nico Weber051860e2013-02-10 02:08:05 +0000192 // ')' or ']'), it could be the start of an Objective-C method
193 // expression, or it could the the start of an Objective-C array literal.
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000194 AnnotatedToken *Left = CurrentToken->Parent;
Nico Weber4ed7f3e2013-02-06 16:54:35 +0000195 AnnotatedToken *Parent = getPreviousToken(*Left);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000196 bool StartsObjCMethodExpr =
Nico Weber4ed7f3e2013-02-06 16:54:35 +0000197 !Parent || Parent->is(tok::colon) || Parent->is(tok::l_square) ||
198 Parent->is(tok::l_paren) || Parent->is(tok::kw_return) ||
199 Parent->is(tok::kw_throw) || isUnaryOperator(*Parent) ||
Nico Weberc2e6d2a2013-02-11 15:32:15 +0000200 Parent->Type == TT_ObjCForIn ||
Nico Weber4ed7f3e2013-02-06 16:54:35 +0000201 getBinOpPrecedence(Parent->FormatTok.Tok.getKind(), true, true) >
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000202 prec::Unknown;
Nico Weber051860e2013-02-10 02:08:05 +0000203 bool StartsObjCArrayLiteral = Parent && Parent->is(tok::at);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000204
Daniel Jasper4e778092013-02-06 10:05:46 +0000205 if (StartsObjCMethodExpr) {
206 Contexts.back().ColonIsObjCMethodExpr = true;
207 Left->Type = TT_ObjCMethodExpr;
Nico Weber051860e2013-02-10 02:08:05 +0000208 } else if (StartsObjCArrayLiteral) {
209 Left->Type = TT_ObjCArrayLiteral;
Daniel Jasper4e778092013-02-06 10:05:46 +0000210 }
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000211
212 while (CurrentToken != NULL) {
213 if (CurrentToken->is(tok::r_square)) {
214 if (!CurrentToken->Children.empty() &&
215 CurrentToken->Children[0].is(tok::l_paren)) {
Nico Webere8a97982013-02-06 06:20:11 +0000216 // An ObjC method call is rarely followed by an open parenthesis.
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000217 // FIXME: Do we incorrectly label ":" with this?
218 StartsObjCMethodExpr = false;
219 Left->Type = TT_Unknown;
220 }
Daniel Jasper01786732013-02-04 07:21:18 +0000221 if (StartsObjCMethodExpr) {
Daniel Jasper4e778092013-02-06 10:05:46 +0000222 CurrentToken->Type = TT_ObjCMethodExpr;
Nico Webere8a97982013-02-06 06:20:11 +0000223 // determineStarAmpUsage() thinks that '*' '[' is allocating an
224 // array of pointers, but if '[' starts a selector then '*' is a
225 // binary operator.
Nico Weber4ed7f3e2013-02-06 16:54:35 +0000226 if (Parent != NULL &&
227 (Parent->is(tok::star) || Parent->is(tok::amp)) &&
228 Parent->Type == TT_PointerOrReference)
229 Parent->Type = TT_BinaryOperator;
Nico Weber051860e2013-02-10 02:08:05 +0000230 } else if (StartsObjCArrayLiteral) {
231 CurrentToken->Type = TT_ObjCArrayLiteral;
Daniel Jasper01786732013-02-04 07:21:18 +0000232 }
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000233 Left->MatchingParen = CurrentToken;
234 CurrentToken->MatchingParen = Left;
Daniel Jasper4e778092013-02-06 10:05:46 +0000235 if (Contexts.back().FirstObjCSelectorName != NULL)
236 Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
237 Contexts.back().LongestObjCSelectorName;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000238 next();
239 return true;
240 }
241 if (CurrentToken->is(tok::r_paren) || CurrentToken->is(tok::r_brace))
242 return false;
243 if (CurrentToken->is(tok::comma))
244 ++Left->ParameterCount;
245 if (!consumeToken())
246 return false;
247 }
248 return false;
249 }
250
251 bool parseBrace() {
252 // Lines are fine to end with '{'.
253 if (CurrentToken == NULL)
254 return true;
Daniel Jasper4e778092013-02-06 10:05:46 +0000255 ScopedContextCreator ContextCreator(*this, 1);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000256 AnnotatedToken *Left = CurrentToken->Parent;
257 while (CurrentToken != NULL) {
258 if (CurrentToken->is(tok::r_brace)) {
259 Left->MatchingParen = CurrentToken;
260 CurrentToken->MatchingParen = Left;
261 next();
262 return true;
263 }
264 if (CurrentToken->is(tok::r_paren) || CurrentToken->is(tok::r_square))
265 return false;
Daniel Jasperf343cab2013-01-31 14:59:26 +0000266 if (CurrentToken->is(tok::comma))
267 ++Left->ParameterCount;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000268 if (!consumeToken())
269 return false;
270 }
271 return true;
272 }
273
274 bool parseConditional() {
275 while (CurrentToken != NULL) {
276 if (CurrentToken->is(tok::colon)) {
277 CurrentToken->Type = TT_ConditionalExpr;
278 next();
279 return true;
280 }
281 if (!consumeToken())
282 return false;
283 }
284 return false;
285 }
286
287 bool parseTemplateDeclaration() {
288 if (CurrentToken != NULL && CurrentToken->is(tok::less)) {
289 CurrentToken->Type = TT_TemplateOpener;
290 next();
291 if (!parseAngle())
292 return false;
293 CurrentToken->Parent->ClosesTemplateDeclaration = true;
294 return true;
295 }
296 return false;
297 }
298
299 bool consumeToken() {
300 AnnotatedToken *Tok = CurrentToken;
301 next();
302 switch (Tok->FormatTok.Tok.getKind()) {
303 case tok::plus:
304 case tok::minus:
305 // At the start of the line, +/- specific ObjectiveC method
306 // declarations.
307 if (Tok->Parent == NULL)
308 Tok->Type = TT_ObjCMethodSpecifier;
309 break;
310 case tok::colon:
311 // Colons from ?: are handled in parseConditional().
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000312 if (Tok->Parent->is(tok::r_paren)) {
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000313 Tok->Type = TT_CtorInitializerColon;
Daniel Jasper4e778092013-02-06 10:05:46 +0000314 } else if (Contexts.back().ColonIsObjCMethodExpr ||
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000315 Line.First.Type == TT_ObjCMethodSpecifier) {
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000316 Tok->Type = TT_ObjCMethodExpr;
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000317 Tok->Parent->Type = TT_ObjCSelectorName;
Daniel Jasper4e778092013-02-06 10:05:46 +0000318 if (Tok->Parent->FormatTok.TokenLength >
319 Contexts.back().LongestObjCSelectorName)
320 Contexts.back().LongestObjCSelectorName =
321 Tok->Parent->FormatTok.TokenLength;
322 if (Contexts.back().FirstObjCSelectorName == NULL)
323 Contexts.back().FirstObjCSelectorName = Tok->Parent;
324 } else if (Contexts.back().ColonIsForRangeExpr) {
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000325 Tok->Type = TT_RangeBasedForLoopColon;
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000326 }
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000327 break;
328 case tok::kw_if:
329 case tok::kw_while:
330 if (CurrentToken != NULL && CurrentToken->is(tok::l_paren)) {
331 next();
332 if (!parseParens(/*LookForDecls=*/ true))
333 return false;
334 }
335 break;
336 case tok::kw_for:
Daniel Jasper4e778092013-02-06 10:05:46 +0000337 Contexts.back().ColonIsForRangeExpr = true;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000338 next();
339 if (!parseParens())
340 return false;
341 break;
342 case tok::l_paren:
343 if (!parseParens())
344 return false;
345 break;
346 case tok::l_square:
347 if (!parseSquare())
348 return false;
349 break;
350 case tok::l_brace:
351 if (!parseBrace())
352 return false;
353 break;
354 case tok::less:
355 if (parseAngle())
356 Tok->Type = TT_TemplateOpener;
357 else {
358 Tok->Type = TT_BinaryOperator;
359 CurrentToken = Tok;
360 next();
361 }
362 break;
363 case tok::r_paren:
364 case tok::r_square:
365 return false;
366 case tok::r_brace:
367 // Lines can start with '}'.
368 if (Tok->Parent != NULL)
369 return false;
370 break;
371 case tok::greater:
372 Tok->Type = TT_BinaryOperator;
373 break;
374 case tok::kw_operator:
Daniel Jasper2b4c9242013-02-11 08:01:18 +0000375 while (CurrentToken && CurrentToken->isNot(tok::l_paren)) {
376 if (CurrentToken->is(tok::star) || CurrentToken->is(tok::amp))
377 CurrentToken->Type = TT_PointerOrReference;
378 consumeToken();
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000379 }
Daniel Jasper2b4c9242013-02-11 08:01:18 +0000380 if (CurrentToken)
381 CurrentToken->Type = TT_OverloadedOperatorLParen;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000382 break;
383 case tok::question:
384 parseConditional();
385 break;
386 case tok::kw_template:
387 parseTemplateDeclaration();
388 break;
Nico Weberc2e6d2a2013-02-11 15:32:15 +0000389 case tok::identifier:
390 if (Line.First.is(tok::kw_for) &&
391 Tok->FormatTok.Tok.getIdentifierInfo() == &Ident_in)
392 Tok->Type = TT_ObjCForIn;
393 break;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000394 default:
395 break;
396 }
397 return true;
398 }
399
400 void parseIncludeDirective() {
401 next();
402 if (CurrentToken != NULL && CurrentToken->is(tok::less)) {
403 next();
404 while (CurrentToken != NULL) {
405 if (CurrentToken->isNot(tok::comment) ||
406 !CurrentToken->Children.empty())
407 CurrentToken->Type = TT_ImplicitStringLiteral;
408 next();
409 }
410 } else {
411 while (CurrentToken != NULL) {
412 next();
413 }
414 }
415 }
416
417 void parseWarningOrError() {
418 next();
419 // We still want to format the whitespace left of the first token of the
420 // warning or error.
421 next();
422 while (CurrentToken != NULL) {
423 CurrentToken->Type = TT_ImplicitStringLiteral;
424 next();
425 }
426 }
427
428 void parsePreprocessorDirective() {
429 next();
430 if (CurrentToken == NULL)
431 return;
432 // Hashes in the middle of a line can lead to any strange token
433 // sequence.
434 if (CurrentToken->FormatTok.Tok.getIdentifierInfo() == NULL)
435 return;
436 switch (CurrentToken->FormatTok.Tok.getIdentifierInfo()->getPPKeywordID()) {
437 case tok::pp_include:
438 case tok::pp_import:
439 parseIncludeDirective();
440 break;
441 case tok::pp_error:
442 case tok::pp_warning:
443 parseWarningOrError();
444 break;
445 default:
446 break;
447 }
Daniel Jasper5b7e7b02013-02-05 09:34:14 +0000448 while (CurrentToken != NULL)
449 next();
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000450 }
451
Nico Weber95e8e462013-02-12 16:17:07 +0000452public:
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000453 LineType parseLine() {
454 int PeriodsAndArrows = 0;
455 bool CanBeBuilderTypeStmt = true;
456 if (CurrentToken->is(tok::hash)) {
457 parsePreprocessorDirective();
458 return LT_PreprocessorDirective;
459 }
460 while (CurrentToken != NULL) {
461 if (CurrentToken->is(tok::kw_virtual))
462 KeywordVirtualFound = true;
463 if (CurrentToken->is(tok::period) || CurrentToken->is(tok::arrow))
464 ++PeriodsAndArrows;
465 if (getPrecedence(*CurrentToken) > prec::Assignment &&
466 CurrentToken->isNot(tok::less) && CurrentToken->isNot(tok::greater))
467 CanBeBuilderTypeStmt = false;
468 if (!consumeToken())
469 return LT_Invalid;
470 }
471 if (KeywordVirtualFound)
472 return LT_VirtualFunctionDecl;
473
474 // Assume a builder-type call if there are 2 or more "." and "->".
475 if (PeriodsAndArrows >= 2 && CanBeBuilderTypeStmt)
476 return LT_BuilderTypeCall;
477
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000478 if (Line.First.Type == TT_ObjCMethodSpecifier) {
Daniel Jasper4e778092013-02-06 10:05:46 +0000479 if (Contexts.back().FirstObjCSelectorName != NULL)
480 Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
481 Contexts.back().LongestObjCSelectorName;
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000482 return LT_ObjCMethodDecl;
483 }
484
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000485 return LT_Other;
486 }
487
Nico Weber95e8e462013-02-12 16:17:07 +0000488private:
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000489 void next() {
Daniel Jasper01786732013-02-04 07:21:18 +0000490 if (CurrentToken != NULL) {
491 determineTokenType(*CurrentToken);
Daniel Jasper4e778092013-02-06 10:05:46 +0000492 CurrentToken->BindingStrength = Contexts.back().BindingStrength;
Daniel Jasper01786732013-02-04 07:21:18 +0000493 }
494
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000495 if (CurrentToken != NULL && !CurrentToken->Children.empty())
496 CurrentToken = &CurrentToken->Children[0];
497 else
498 CurrentToken = NULL;
499 }
500
Daniel Jasper4e778092013-02-06 10:05:46 +0000501 /// \brief A struct to hold information valid in a specific context, e.g.
502 /// a pair of parenthesis.
503 struct Context {
504 Context(unsigned BindingStrength, bool IsExpression)
505 : BindingStrength(BindingStrength), LongestObjCSelectorName(0),
506 ColonIsForRangeExpr(false), ColonIsObjCMethodExpr(false),
507 FirstObjCSelectorName(NULL), IsExpression(IsExpression),
508 LookForFunctionName(false) {
509 }
Daniel Jasper01786732013-02-04 07:21:18 +0000510
Daniel Jasper4e778092013-02-06 10:05:46 +0000511 unsigned BindingStrength;
512 unsigned LongestObjCSelectorName;
513 bool ColonIsForRangeExpr;
514 bool ColonIsObjCMethodExpr;
515 AnnotatedToken *FirstObjCSelectorName;
516 bool IsExpression;
517 bool LookForFunctionName;
518 };
519
520 /// \brief Puts a new \c Context onto the stack \c Contexts for the lifetime
521 /// of each instance.
522 struct ScopedContextCreator {
523 AnnotatingParser &P;
524
525 ScopedContextCreator(AnnotatingParser &P, unsigned Increase)
526 : P(P) {
527 P.Contexts.push_back(Context(
528 P.Contexts.back().BindingStrength + Increase,
529 P.Contexts.back().IsExpression));
530 }
531
532 ~ScopedContextCreator() { P.Contexts.pop_back(); }
533 };
Daniel Jasper01786732013-02-04 07:21:18 +0000534
535 void determineTokenType(AnnotatedToken &Current) {
536 if (getPrecedence(Current) == prec::Assignment) {
Daniel Jasper4e778092013-02-06 10:05:46 +0000537 Contexts.back().IsExpression = true;
Nico Weber95e8e462013-02-12 16:17:07 +0000538 for (AnnotatedToken *Previous = Current.Parent;
539 Previous && Previous->isNot(tok::comma);
540 Previous = Previous->Parent) {
Daniel Jasper01786732013-02-04 07:21:18 +0000541 if (Previous->Type == TT_BinaryOperator &&
542 (Previous->is(tok::star) || Previous->is(tok::amp))) {
543 Previous->Type = TT_PointerOrReference;
544 }
Daniel Jasper01786732013-02-04 07:21:18 +0000545 }
Nico Weber95e8e462013-02-12 16:17:07 +0000546 } else if (Current.is(tok::kw_return) || Current.is(tok::kw_throw) ||
547 (Current.is(tok::l_paren) && !Line.MustBeDeclaration &&
548 (!Current.Parent || Current.Parent->isNot(tok::kw_for)))) {
Daniel Jasper4e778092013-02-06 10:05:46 +0000549 Contexts.back().IsExpression = true;
Nico Weber95e8e462013-02-12 16:17:07 +0000550 } else if (Current.is(tok::r_paren) || Current.is(tok::greater) ||
551 Current.is(tok::comma)) {
552 for (AnnotatedToken *Previous = Current.Parent;
553 Previous && (Previous->is(tok::star) || Previous->is(tok::amp));
554 Previous = Previous->Parent)
555 Previous->Type = TT_PointerOrReference;
556 }
Daniel Jasper01786732013-02-04 07:21:18 +0000557
558 if (Current.Type == TT_Unknown) {
Daniel Jasper4e778092013-02-06 10:05:46 +0000559 if (Contexts.back().LookForFunctionName && Current.is(tok::l_paren)) {
Daniel Jasper01786732013-02-04 07:21:18 +0000560 findFunctionName(&Current);
Daniel Jasper4e778092013-02-06 10:05:46 +0000561 Contexts.back().LookForFunctionName = false;
Daniel Jasper01786732013-02-04 07:21:18 +0000562 } else if (Current.is(tok::star) || Current.is(tok::amp)) {
Daniel Jasper4e778092013-02-06 10:05:46 +0000563 Current.Type =
564 determineStarAmpUsage(Current, Contexts.back().IsExpression);
Daniel Jasper01786732013-02-04 07:21:18 +0000565 } else if (Current.is(tok::minus) || Current.is(tok::plus) ||
566 Current.is(tok::caret)) {
567 Current.Type = determinePlusMinusCaretUsage(Current);
568 } else if (Current.is(tok::minusminus) || Current.is(tok::plusplus)) {
569 Current.Type = determineIncrementUsage(Current);
570 } else if (Current.is(tok::exclaim)) {
571 Current.Type = TT_UnaryOperator;
572 } else if (isBinaryOperator(Current)) {
573 Current.Type = TT_BinaryOperator;
574 } else if (Current.is(tok::comment)) {
575 std::string Data(Lexer::getSpelling(Current.FormatTok.Tok, SourceMgr,
576 Lex.getLangOpts()));
577 if (StringRef(Data).startswith("//"))
578 Current.Type = TT_LineComment;
579 else
580 Current.Type = TT_BlockComment;
581 } else if (Current.is(tok::r_paren) &&
582 (Current.Parent->Type == TT_PointerOrReference ||
583 Current.Parent->Type == TT_TemplateCloser) &&
584 (Current.Children.empty() ||
585 (Current.Children[0].isNot(tok::equal) &&
586 Current.Children[0].isNot(tok::semi) &&
587 Current.Children[0].isNot(tok::l_brace)))) {
588 // FIXME: We need to get smarter and understand more cases of casts.
589 Current.Type = TT_CastRParen;
590 } else if (Current.is(tok::at) && Current.Children.size()) {
591 switch (Current.Children[0].FormatTok.Tok.getObjCKeywordID()) {
592 case tok::objc_interface:
593 case tok::objc_implementation:
594 case tok::objc_protocol:
595 Current.Type = TT_ObjCDecl;
596 break;
597 case tok::objc_property:
598 Current.Type = TT_ObjCProperty;
599 break;
600 default:
601 break;
602 }
603 }
604 }
605 }
606
607 /// \brief Starting from \p Current, this searches backwards for an
608 /// identifier which could be the start of a function name and marks it.
609 void findFunctionName(AnnotatedToken *Current) {
610 AnnotatedToken *Parent = Current->Parent;
611 while (Parent != NULL && Parent->Parent != NULL) {
612 if (Parent->is(tok::identifier) &&
613 (Parent->Parent->is(tok::identifier) ||
614 Parent->Parent->Type == TT_PointerOrReference ||
615 Parent->Parent->Type == TT_TemplateCloser)) {
616 Parent->Type = TT_StartOfName;
617 break;
618 }
619 Parent = Parent->Parent;
620 }
621 }
622
623 /// \brief Return the type of the given token assuming it is * or &.
624 TokenType
625 determineStarAmpUsage(const AnnotatedToken &Tok, bool IsExpression) {
626 const AnnotatedToken *PrevToken = getPreviousToken(Tok);
627 if (PrevToken == NULL)
628 return TT_UnaryOperator;
629
630 const AnnotatedToken *NextToken = getNextToken(Tok);
631 if (NextToken == NULL)
632 return TT_Unknown;
633
Daniel Jasper01786732013-02-04 07:21:18 +0000634 if (PrevToken->is(tok::l_paren) || PrevToken->is(tok::l_square) ||
635 PrevToken->is(tok::l_brace) || PrevToken->is(tok::comma) ||
636 PrevToken->is(tok::kw_return) || PrevToken->is(tok::colon) ||
Nico Webere8a97982013-02-06 06:20:11 +0000637 PrevToken->is(tok::equal) || PrevToken->Type == TT_BinaryOperator ||
Daniel Jasper01786732013-02-04 07:21:18 +0000638 PrevToken->Type == TT_UnaryOperator || PrevToken->Type == TT_CastRParen)
639 return TT_UnaryOperator;
640
Nico Webere8a97982013-02-06 06:20:11 +0000641 if (NextToken->is(tok::l_square))
642 return TT_PointerOrReference;
643
Daniel Jasper01786732013-02-04 07:21:18 +0000644 if (PrevToken->FormatTok.Tok.isLiteral() || PrevToken->is(tok::r_paren) ||
645 PrevToken->is(tok::r_square) || NextToken->FormatTok.Tok.isLiteral() ||
Nico Weberee0feec2013-02-05 16:21:00 +0000646 isUnaryOperator(*NextToken) || NextToken->is(tok::l_paren) ||
647 NextToken->is(tok::l_square))
Daniel Jasper01786732013-02-04 07:21:18 +0000648 return TT_BinaryOperator;
649
Daniel Jasper01786732013-02-04 07:21:18 +0000650 // It is very unlikely that we are going to find a pointer or reference type
651 // definition on the RHS of an assignment.
652 if (IsExpression)
653 return TT_BinaryOperator;
654
655 return TT_PointerOrReference;
656 }
657
658 TokenType determinePlusMinusCaretUsage(const AnnotatedToken &Tok) {
659 const AnnotatedToken *PrevToken = getPreviousToken(Tok);
660 if (PrevToken == NULL)
661 return TT_UnaryOperator;
662
663 // Use heuristics to recognize unary operators.
664 if (PrevToken->is(tok::equal) || PrevToken->is(tok::l_paren) ||
665 PrevToken->is(tok::comma) || PrevToken->is(tok::l_square) ||
666 PrevToken->is(tok::question) || PrevToken->is(tok::colon) ||
667 PrevToken->is(tok::kw_return) || PrevToken->is(tok::kw_case) ||
668 PrevToken->is(tok::at) || PrevToken->is(tok::l_brace))
669 return TT_UnaryOperator;
670
Nico Weberee0feec2013-02-05 16:21:00 +0000671 // There can't be two consecutive binary operators.
Daniel Jasper01786732013-02-04 07:21:18 +0000672 if (PrevToken->Type == TT_BinaryOperator)
673 return TT_UnaryOperator;
674
675 // Fall back to marking the token as binary operator.
676 return TT_BinaryOperator;
677 }
678
679 /// \brief Determine whether ++/-- are pre- or post-increments/-decrements.
680 TokenType determineIncrementUsage(const AnnotatedToken &Tok) {
681 const AnnotatedToken *PrevToken = getPreviousToken(Tok);
682 if (PrevToken == NULL)
683 return TT_UnaryOperator;
684 if (PrevToken->is(tok::r_paren) || PrevToken->is(tok::r_square) ||
685 PrevToken->is(tok::identifier))
686 return TT_TrailingUnaryOperator;
687
688 return TT_UnaryOperator;
689 }
Daniel Jasper4e778092013-02-06 10:05:46 +0000690
691 SmallVector<Context, 8> Contexts;
692
693 SourceManager &SourceMgr;
694 Lexer &Lex;
695 AnnotatedLine &Line;
696 AnnotatedToken *CurrentToken;
697 bool KeywordVirtualFound;
Nico Weberc2e6d2a2013-02-11 15:32:15 +0000698 IdentifierInfo &Ident_in;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000699};
700
Daniel Jasper29f123b2013-02-08 15:28:42 +0000701/// \brief Parses binary expressions by inserting fake parenthesis based on
702/// operator precedence.
703class ExpressionParser {
704public:
705 ExpressionParser(AnnotatedLine &Line) : Current(&Line.First) {}
706
707 /// \brief Parse expressions with the given operatore precedence.
708 void parse(unsigned Precedence = prec::Unknown) {
709 if (Precedence > prec::PointerToMember || Current == NULL)
710 return;
711
712 // Skip over "return" until we can properly parse it.
713 if (Current->is(tok::kw_return))
714 next();
715
716 // Eagerly consume trailing comments.
717 while (isTrailingComment(Current)) {
718 next();
719 }
720
721 AnnotatedToken *Start = Current;
722 bool OperatorFound = false;
723
724 while (Current != NULL) {
725 // Consume operators with higher precedence.
726 parse(Precedence + 1);
727
728 // At the end of the line or when an operator with higher precedence is
729 // found, insert fake parenthesis and return.
730 if (Current == NULL || Current->is(tok::semi) || closesScope(*Current) ||
731 ((Current->Type == TT_BinaryOperator || Current->is(tok::comma)) &&
732 getPrecedence(*Current) < Precedence)) {
733 if (OperatorFound) {
734 ++Start->FakeLParens;
735 if (Current != NULL)
Daniel Jasper087387a2013-02-08 16:49:27 +0000736 ++Current->Parent->FakeRParens;
Daniel Jasper29f123b2013-02-08 15:28:42 +0000737 }
738 return;
739 }
740
741 // Consume scopes: (), [], <> and {}
742 if (opensScope(*Current)) {
743 while (Current != NULL && !closesScope(*Current)) {
744 next();
745 parse();
746 }
747 next();
748 } else {
749 // Operator found.
750 if (getPrecedence(*Current) == Precedence)
751 OperatorFound = true;
752
753 next();
754 }
755 }
756 }
757
758private:
759 void next() {
760 if (Current != NULL)
761 Current = Current->Children.empty() ? NULL : &Current->Children[0];
762 }
763
764 bool closesScope(const AnnotatedToken &Tok) {
765 return Current->is(tok::r_paren) || Current->Type == TT_TemplateCloser ||
766 Current->is(tok::r_brace) || Current->is(tok::r_square);
767 }
768
769 bool opensScope(const AnnotatedToken &Tok) {
770 return Current->is(tok::l_paren) || Current->Type == TT_TemplateOpener ||
771 Current->is(tok::l_brace) || Current->is(tok::l_square);
772 }
773
774 AnnotatedToken *Current;
775};
776
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000777void TokenAnnotator::annotate(AnnotatedLine &Line) {
Nico Weberc2e6d2a2013-02-11 15:32:15 +0000778 AnnotatingParser Parser(SourceMgr, Lex, Line, Ident_in);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000779 Line.Type = Parser.parseLine();
780 if (Line.Type == LT_Invalid)
781 return;
782
Daniel Jasper29f123b2013-02-08 15:28:42 +0000783 ExpressionParser ExprParser(Line);
784 ExprParser.parse();
785
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000786 if (Line.First.Type == TT_ObjCMethodSpecifier)
787 Line.Type = LT_ObjCMethodDecl;
788 else if (Line.First.Type == TT_ObjCDecl)
789 Line.Type = LT_ObjCDecl;
790 else if (Line.First.Type == TT_ObjCProperty)
791 Line.Type = LT_ObjCProperty;
792
Daniel Jasper729a7432013-02-11 12:36:37 +0000793 Line.First.SpacesRequiredBefore = 1;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000794 Line.First.MustBreakBefore = Line.First.FormatTok.MustBreakBefore;
795 Line.First.CanBreakBefore = Line.First.MustBreakBefore;
796
797 Line.First.TotalLength = Line.First.FormatTok.TokenLength;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000798}
799
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000800void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
801 if (Line.First.Children.empty())
802 return;
803 AnnotatedToken *Current = &Line.First.Children[0];
804 while (Current != NULL) {
Daniel Jasper729a7432013-02-11 12:36:37 +0000805 if (Current->Type == TT_LineComment)
806 Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments;
807 else
808 Current->SpacesRequiredBefore =
809 spaceRequiredBefore(Line, *Current) ? 1 : 0;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000810
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000811 if (Current->FormatTok.MustBreakBefore) {
812 Current->MustBreakBefore = true;
813 } else if (Current->Type == TT_LineComment) {
814 Current->MustBreakBefore = Current->FormatTok.NewlinesBefore > 0;
Daniel Jasper29f123b2013-02-08 15:28:42 +0000815 } else if (isTrailingComment(Current->Parent) ||
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000816 (Current->is(tok::string_literal) &&
817 Current->Parent->is(tok::string_literal))) {
818 Current->MustBreakBefore = true;
819 } else if (Current->is(tok::lessless) && !Current->Children.empty() &&
820 Current->Parent->is(tok::string_literal) &&
821 Current->Children[0].is(tok::string_literal)) {
822 Current->MustBreakBefore = true;
823 } else {
824 Current->MustBreakBefore = false;
825 }
826 Current->CanBreakBefore =
827 Current->MustBreakBefore || canBreakBefore(Line, *Current);
828 if (Current->MustBreakBefore)
829 Current->TotalLength = Current->Parent->TotalLength + Style.ColumnLimit;
830 else
831 Current->TotalLength =
832 Current->Parent->TotalLength + Current->FormatTok.TokenLength +
Daniel Jasper729a7432013-02-11 12:36:37 +0000833 Current->SpacesRequiredBefore;
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000834 // FIXME: Only calculate this if CanBreakBefore is true once static
835 // initializers etc. are sorted out.
836 // FIXME: Move magic numbers to a better place.
837 Current->SplitPenalty =
838 20 * Current->BindingStrength + splitPenalty(Line, *Current);
839
840 Current = Current->Children.empty() ? NULL : &Current->Children[0];
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000841 }
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000842}
843
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000844unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
845 const AnnotatedToken &Tok) {
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000846 const AnnotatedToken &Left = *Tok.Parent;
847 const AnnotatedToken &Right = Tok;
848
849 if (Left.is(tok::l_brace) && Right.isNot(tok::l_brace))
850 return 50;
851 if (Left.is(tok::equal) && Right.is(tok::l_brace))
852 return 150;
853 if (Left.is(tok::coloncolon))
854 return 500;
855
856 if (Left.Type == TT_RangeBasedForLoopColon)
857 return 5;
858
859 if (Right.is(tok::arrow) || Right.is(tok::period)) {
860 if (Left.is(tok::r_paren) && Line.Type == LT_BuilderTypeCall)
861 return 5; // Should be smaller than breaking at a nested comma.
862 return 150;
863 }
864
865 // In for-loops, prefer breaking at ',' and ';'.
866 if (Line.First.is(tok::kw_for) &&
867 (Left.isNot(tok::comma) && Left.isNot(tok::semi)))
868 return 20;
869
Daniel Jasper8159d2f2013-02-04 07:30:30 +0000870 if (Left.is(tok::semi))
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000871 return 0;
Daniel Jasper8159d2f2013-02-04 07:30:30 +0000872 if (Left.is(tok::comma))
873 return 1;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000874
875 // In Objective-C method expressions, prefer breaking before "param:" over
876 // breaking after it.
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000877 if (Right.Type == TT_ObjCSelectorName)
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000878 return 0;
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000879 if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000880 return 20;
881
Daniel Jasper01786732013-02-04 07:21:18 +0000882 if (Left.is(tok::l_paren) || Left.is(tok::l_square) ||
883 Left.Type == TT_TemplateOpener)
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000884 return 20;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000885
Daniel Jasper4e8a7b42013-02-06 21:04:05 +0000886 if (Right.is(tok::lessless)) {
887 if (Left.is(tok::string_literal)) {
888 char LastChar =
889 StringRef(Left.FormatTok.Tok.getLiteralData(),
890 Left.FormatTok.TokenLength).drop_back(1).rtrim().back();
891 if (LastChar == ':' || LastChar == '=')
892 return 100;
893 }
Daniel Jasper01786732013-02-04 07:21:18 +0000894 return prec::Shift;
Daniel Jasper4e8a7b42013-02-06 21:04:05 +0000895 }
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000896 if (Left.Type == TT_ConditionalExpr)
897 return prec::Assignment;
898 prec::Level Level = getPrecedence(Left);
899
900 if (Level != prec::Unknown)
901 return Level;
902
903 return 3;
904}
905
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000906bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
907 const AnnotatedToken &Left,
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000908 const AnnotatedToken &Right) {
909 if (Right.is(tok::hashhash))
910 return Left.is(tok::hash);
911 if (Left.is(tok::hashhash) || Left.is(tok::hash))
912 return Right.is(tok::hash);
913 if (Right.is(tok::r_paren) || Right.is(tok::semi) || Right.is(tok::comma))
914 return false;
915 if (Right.is(tok::less) &&
916 (Left.is(tok::kw_template) ||
917 (Line.Type == LT_ObjCDecl && Style.ObjCSpaceBeforeProtocolList)))
918 return true;
919 if (Left.is(tok::arrow) || Right.is(tok::arrow))
920 return false;
921 if (Left.is(tok::exclaim) || Left.is(tok::tilde))
922 return false;
923 if (Left.is(tok::at) &&
924 (Right.is(tok::identifier) || Right.is(tok::string_literal) ||
925 Right.is(tok::char_constant) || Right.is(tok::numeric_constant) ||
926 Right.is(tok::l_paren) || Right.is(tok::l_brace) ||
927 Right.is(tok::kw_true) || Right.is(tok::kw_false)))
928 return false;
929 if (Left.is(tok::coloncolon))
930 return false;
931 if (Right.is(tok::coloncolon))
Daniel Jasperdaf1a152013-02-07 21:08:36 +0000932 return Left.isNot(tok::identifier) && Left.isNot(tok::greater) &&
933 Left.isNot(tok::l_paren);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000934 if (Left.is(tok::less) || Right.is(tok::greater) || Right.is(tok::less))
935 return false;
936 if (Right.is(tok::amp) || Right.is(tok::star))
937 return Left.FormatTok.Tok.isLiteral() ||
938 (Left.isNot(tok::star) && Left.isNot(tok::amp) &&
Nico Weber95e8e462013-02-12 16:17:07 +0000939 Left.isNot(tok::l_paren) && !Style.PointerBindsToType);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000940 if (Left.is(tok::amp) || Left.is(tok::star))
Nico Weber95e8e462013-02-12 16:17:07 +0000941 return Right.FormatTok.Tok.isLiteral() ||
942 (Right.isNot(tok::star) && Right.isNot(tok::amp) &&
943 Style.PointerBindsToType);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000944 if (Right.is(tok::star) && Left.is(tok::l_paren))
945 return false;
Nico Weber051860e2013-02-10 02:08:05 +0000946 if (Left.is(tok::l_square))
947 return Left.Type == TT_ObjCArrayLiteral && Right.isNot(tok::r_square);
948 if (Right.is(tok::r_square))
949 return Right.Type == TT_ObjCArrayLiteral;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000950 if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr)
951 return false;
952 if (Left.is(tok::period) || Right.is(tok::period))
953 return false;
954 if (Left.is(tok::colon))
955 return Left.Type != TT_ObjCMethodExpr;
956 if (Right.is(tok::colon))
957 return Right.Type != TT_ObjCMethodExpr;
958 if (Left.is(tok::l_paren))
959 return false;
960 if (Right.is(tok::l_paren)) {
961 return Line.Type == LT_ObjCDecl || Left.is(tok::kw_if) ||
962 Left.is(tok::kw_for) || Left.is(tok::kw_while) ||
963 Left.is(tok::kw_switch) || Left.is(tok::kw_return) ||
964 Left.is(tok::kw_catch) || Left.is(tok::kw_new) ||
965 Left.is(tok::kw_delete);
966 }
967 if (Left.is(tok::at) &&
968 Right.FormatTok.Tok.getObjCKeywordID() != tok::objc_not_keyword)
969 return false;
970 if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
971 return false;
972 return true;
973}
974
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000975bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
976 const AnnotatedToken &Tok) {
Daniel Jasper2b4c9242013-02-11 08:01:18 +0000977 if (Tok.FormatTok.Tok.getIdentifierInfo() &&
978 Tok.Parent->FormatTok.Tok.getIdentifierInfo())
979 return true; // Never ever merge two identifiers.
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000980 if (Line.Type == LT_ObjCMethodDecl) {
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000981 if (Tok.Parent->Type == TT_ObjCMethodSpecifier)
982 return true;
983 if (Tok.Parent->is(tok::r_paren) && Tok.is(tok::identifier))
984 // Don't space between ')' and <id>
985 return false;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000986 }
987 if (Line.Type == LT_ObjCProperty &&
988 (Tok.is(tok::equal) || Tok.Parent->is(tok::equal)))
989 return false;
990
991 if (Tok.Parent->is(tok::comma))
992 return true;
993 if (Tok.Type == TT_CtorInitializerColon || Tok.Type == TT_ObjCBlockLParen)
994 return true;
Daniel Jasper2b4c9242013-02-11 08:01:18 +0000995 if (Tok.Parent->FormatTok.Tok.is(tok::kw_operator))
996 return false;
997 if (Tok.Type == TT_OverloadedOperatorLParen)
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000998 return false;
999 if (Tok.is(tok::colon))
1000 return Line.First.isNot(tok::kw_case) && !Tok.Children.empty() &&
1001 Tok.Type != TT_ObjCMethodExpr;
1002 if (Tok.Parent->Type == TT_UnaryOperator || Tok.Parent->Type == TT_CastRParen)
1003 return false;
1004 if (Tok.Type == TT_UnaryOperator)
1005 return Tok.Parent->isNot(tok::l_paren) &&
1006 Tok.Parent->isNot(tok::l_square) && Tok.Parent->isNot(tok::at) &&
1007 (Tok.Parent->isNot(tok::colon) ||
1008 Tok.Parent->Type != TT_ObjCMethodExpr);
1009 if (Tok.Parent->is(tok::greater) && Tok.is(tok::greater)) {
Daniel Jasper29f123b2013-02-08 15:28:42 +00001010 return Tok.Type == TT_TemplateCloser &&
1011 Tok.Parent->Type == TT_TemplateCloser &&
1012 Style.Standard != FormatStyle::LS_Cpp11;
Daniel Jasper32d28ee2013-01-29 21:01:14 +00001013 }
1014 if (Tok.Type == TT_BinaryOperator || Tok.Parent->Type == TT_BinaryOperator)
1015 return true;
1016 if (Tok.Parent->Type == TT_TemplateCloser && Tok.is(tok::l_paren))
1017 return false;
1018 if (Tok.is(tok::less) && Line.First.is(tok::hash))
1019 return true;
1020 if (Tok.Type == TT_TrailingUnaryOperator)
1021 return false;
Daniel Jasper8ff690a2013-02-06 14:22:40 +00001022 return spaceRequiredBetween(Line, *Tok.Parent, Tok);
Daniel Jasper32d28ee2013-01-29 21:01:14 +00001023}
1024
Daniel Jasper8ff690a2013-02-06 14:22:40 +00001025bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
1026 const AnnotatedToken &Right) {
Daniel Jasper32d28ee2013-01-29 21:01:14 +00001027 const AnnotatedToken &Left = *Right.Parent;
Daniel Jasper32d28ee2013-01-29 21:01:14 +00001028 if (Right.Type == TT_StartOfName && Style.AllowReturnTypeOnItsOwnLine)
1029 return true;
1030 if (Right.is(tok::colon) && Right.Type == TT_ObjCMethodExpr)
1031 return false;
1032 if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
1033 return true;
Daniel Jasper63d7ced2013-02-05 10:07:47 +00001034 if (Right.Type == TT_ObjCSelectorName)
Daniel Jasper32d28ee2013-01-29 21:01:14 +00001035 return true;
1036 if (Left.ClosesTemplateDeclaration)
1037 return true;
1038 if (Right.Type == TT_ConditionalExpr || Right.is(tok::question))
1039 return true;
1040 if (Left.Type == TT_RangeBasedForLoopColon)
1041 return true;
1042 if (Left.Type == TT_PointerOrReference || Left.Type == TT_TemplateCloser ||
1043 Left.Type == TT_UnaryOperator || Left.Type == TT_ConditionalExpr ||
1044 Left.is(tok::question))
1045 return false;
1046 if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl)
1047 return false;
1048
1049 if (Right.Type == TT_LineComment)
1050 // We rely on MustBreakBefore being set correctly here as we should not
1051 // change the "binding" behavior of a comment.
1052 return false;
1053
1054 // Allow breaking after a trailing 'const', e.g. after a method declaration,
1055 // unless it is follow by ';', '{' or '='.
1056 if (Left.is(tok::kw_const) && Left.Parent != NULL &&
1057 Left.Parent->is(tok::r_paren))
1058 return Right.isNot(tok::l_brace) && Right.isNot(tok::semi) &&
1059 Right.isNot(tok::equal);
1060
1061 // We only break before r_brace if there was a corresponding break before
1062 // the l_brace, which is tracked by BreakBeforeClosingBrace.
1063 if (Right.is(tok::r_brace))
1064 return false;
1065
1066 if (Right.is(tok::r_paren) || Right.is(tok::greater))
1067 return false;
1068 return (isBinaryOperator(Left) && Left.isNot(tok::lessless)) ||
1069 Left.is(tok::comma) || Right.is(tok::lessless) ||
1070 Right.is(tok::arrow) || Right.is(tok::period) ||
1071 Right.is(tok::colon) || Left.is(tok::coloncolon) ||
1072 Left.is(tok::semi) || Left.is(tok::l_brace) ||
1073 (Left.is(tok::r_paren) && Left.Type != TT_CastRParen &&
1074 Right.is(tok::identifier)) ||
1075 (Left.is(tok::l_paren) && !Right.is(tok::r_paren)) ||
1076 (Left.is(tok::l_square) && !Right.is(tok::r_square));
1077}
1078
1079} // namespace format
1080} // namespace clang