blob: d2e19af56f13b736963373b39db8a27f5c4934e0 [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 Weber4c2cc602013-02-13 03:48:27 +0000200 Parent->Type == TT_ObjCForIn || Parent->Type == TT_CastRParen ||
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;
Nico Weber37d69312013-02-13 04:13:13 +0000581 } else if (Current.is(tok::r_paren)) {
582 bool ParensNotExpr = Current.Parent->Type == TT_PointerOrReference ||
583 Current.Parent->Type == TT_TemplateCloser;
584 bool ParensCouldEndDecl =
585 !Current.Children.empty() && (Current.Children[0].is(tok::equal) ||
586 Current.Children[0].is(tok::semi) ||
587 Current.Children[0].is(tok::l_brace));
588 if (ParensNotExpr && !ParensCouldEndDecl)
589 // FIXME: We need to get smarter and understand more cases of casts.
590 Current.Type = TT_CastRParen;
Daniel Jasper01786732013-02-04 07:21:18 +0000591 } else if (Current.is(tok::at) && Current.Children.size()) {
592 switch (Current.Children[0].FormatTok.Tok.getObjCKeywordID()) {
593 case tok::objc_interface:
594 case tok::objc_implementation:
595 case tok::objc_protocol:
596 Current.Type = TT_ObjCDecl;
597 break;
598 case tok::objc_property:
599 Current.Type = TT_ObjCProperty;
600 break;
601 default:
602 break;
603 }
604 }
605 }
606 }
607
608 /// \brief Starting from \p Current, this searches backwards for an
609 /// identifier which could be the start of a function name and marks it.
610 void findFunctionName(AnnotatedToken *Current) {
611 AnnotatedToken *Parent = Current->Parent;
612 while (Parent != NULL && Parent->Parent != NULL) {
613 if (Parent->is(tok::identifier) &&
614 (Parent->Parent->is(tok::identifier) ||
615 Parent->Parent->Type == TT_PointerOrReference ||
616 Parent->Parent->Type == TT_TemplateCloser)) {
617 Parent->Type = TT_StartOfName;
618 break;
619 }
620 Parent = Parent->Parent;
621 }
622 }
623
624 /// \brief Return the type of the given token assuming it is * or &.
625 TokenType
626 determineStarAmpUsage(const AnnotatedToken &Tok, bool IsExpression) {
627 const AnnotatedToken *PrevToken = getPreviousToken(Tok);
628 if (PrevToken == NULL)
629 return TT_UnaryOperator;
630
631 const AnnotatedToken *NextToken = getNextToken(Tok);
632 if (NextToken == NULL)
633 return TT_Unknown;
634
Daniel Jasper01786732013-02-04 07:21:18 +0000635 if (PrevToken->is(tok::l_paren) || PrevToken->is(tok::l_square) ||
636 PrevToken->is(tok::l_brace) || PrevToken->is(tok::comma) ||
637 PrevToken->is(tok::kw_return) || PrevToken->is(tok::colon) ||
Nico Webere8a97982013-02-06 06:20:11 +0000638 PrevToken->is(tok::equal) || PrevToken->Type == TT_BinaryOperator ||
Daniel Jasper01786732013-02-04 07:21:18 +0000639 PrevToken->Type == TT_UnaryOperator || PrevToken->Type == TT_CastRParen)
640 return TT_UnaryOperator;
641
Nico Webere8a97982013-02-06 06:20:11 +0000642 if (NextToken->is(tok::l_square))
643 return TT_PointerOrReference;
644
Daniel Jasper01786732013-02-04 07:21:18 +0000645 if (PrevToken->FormatTok.Tok.isLiteral() || PrevToken->is(tok::r_paren) ||
646 PrevToken->is(tok::r_square) || NextToken->FormatTok.Tok.isLiteral() ||
Nico Weberee0feec2013-02-05 16:21:00 +0000647 isUnaryOperator(*NextToken) || NextToken->is(tok::l_paren) ||
648 NextToken->is(tok::l_square))
Daniel Jasper01786732013-02-04 07:21:18 +0000649 return TT_BinaryOperator;
650
Daniel Jasper01786732013-02-04 07:21:18 +0000651 // It is very unlikely that we are going to find a pointer or reference type
652 // definition on the RHS of an assignment.
653 if (IsExpression)
654 return TT_BinaryOperator;
655
656 return TT_PointerOrReference;
657 }
658
659 TokenType determinePlusMinusCaretUsage(const AnnotatedToken &Tok) {
660 const AnnotatedToken *PrevToken = getPreviousToken(Tok);
661 if (PrevToken == NULL)
662 return TT_UnaryOperator;
663
664 // Use heuristics to recognize unary operators.
665 if (PrevToken->is(tok::equal) || PrevToken->is(tok::l_paren) ||
666 PrevToken->is(tok::comma) || PrevToken->is(tok::l_square) ||
667 PrevToken->is(tok::question) || PrevToken->is(tok::colon) ||
668 PrevToken->is(tok::kw_return) || PrevToken->is(tok::kw_case) ||
669 PrevToken->is(tok::at) || PrevToken->is(tok::l_brace))
670 return TT_UnaryOperator;
671
Nico Weberee0feec2013-02-05 16:21:00 +0000672 // There can't be two consecutive binary operators.
Daniel Jasper01786732013-02-04 07:21:18 +0000673 if (PrevToken->Type == TT_BinaryOperator)
674 return TT_UnaryOperator;
675
676 // Fall back to marking the token as binary operator.
677 return TT_BinaryOperator;
678 }
679
680 /// \brief Determine whether ++/-- are pre- or post-increments/-decrements.
681 TokenType determineIncrementUsage(const AnnotatedToken &Tok) {
682 const AnnotatedToken *PrevToken = getPreviousToken(Tok);
683 if (PrevToken == NULL)
684 return TT_UnaryOperator;
685 if (PrevToken->is(tok::r_paren) || PrevToken->is(tok::r_square) ||
686 PrevToken->is(tok::identifier))
687 return TT_TrailingUnaryOperator;
688
689 return TT_UnaryOperator;
690 }
Daniel Jasper4e778092013-02-06 10:05:46 +0000691
692 SmallVector<Context, 8> Contexts;
693
694 SourceManager &SourceMgr;
695 Lexer &Lex;
696 AnnotatedLine &Line;
697 AnnotatedToken *CurrentToken;
698 bool KeywordVirtualFound;
Nico Weberc2e6d2a2013-02-11 15:32:15 +0000699 IdentifierInfo &Ident_in;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000700};
701
Daniel Jasper29f123b2013-02-08 15:28:42 +0000702/// \brief Parses binary expressions by inserting fake parenthesis based on
703/// operator precedence.
704class ExpressionParser {
705public:
706 ExpressionParser(AnnotatedLine &Line) : Current(&Line.First) {}
707
708 /// \brief Parse expressions with the given operatore precedence.
Dmitri Gribenkob0112e12013-02-12 22:40:22 +0000709 void parse(int Precedence = prec::Unknown) {
Daniel Jasper29f123b2013-02-08 15:28:42 +0000710 if (Precedence > prec::PointerToMember || Current == NULL)
711 return;
712
713 // Skip over "return" until we can properly parse it.
714 if (Current->is(tok::kw_return))
715 next();
716
717 // Eagerly consume trailing comments.
718 while (isTrailingComment(Current)) {
719 next();
720 }
721
722 AnnotatedToken *Start = Current;
723 bool OperatorFound = false;
724
725 while (Current != NULL) {
726 // Consume operators with higher precedence.
727 parse(Precedence + 1);
728
729 // At the end of the line or when an operator with higher precedence is
730 // found, insert fake parenthesis and return.
731 if (Current == NULL || Current->is(tok::semi) || closesScope(*Current) ||
732 ((Current->Type == TT_BinaryOperator || Current->is(tok::comma)) &&
Aaron Ballman468e3992013-02-12 19:20:48 +0000733 getPrecedence(*Current) < Precedence)) {
Daniel Jasper29f123b2013-02-08 15:28:42 +0000734 if (OperatorFound) {
735 ++Start->FakeLParens;
736 if (Current != NULL)
Daniel Jasper087387a2013-02-08 16:49:27 +0000737 ++Current->Parent->FakeRParens;
Daniel Jasper29f123b2013-02-08 15:28:42 +0000738 }
739 return;
740 }
741
742 // Consume scopes: (), [], <> and {}
743 if (opensScope(*Current)) {
744 while (Current != NULL && !closesScope(*Current)) {
745 next();
746 parse();
747 }
748 next();
749 } else {
750 // Operator found.
751 if (getPrecedence(*Current) == Precedence)
752 OperatorFound = true;
753
754 next();
755 }
756 }
757 }
758
759private:
760 void next() {
761 if (Current != NULL)
762 Current = Current->Children.empty() ? NULL : &Current->Children[0];
763 }
764
765 bool closesScope(const AnnotatedToken &Tok) {
766 return Current->is(tok::r_paren) || Current->Type == TT_TemplateCloser ||
767 Current->is(tok::r_brace) || Current->is(tok::r_square);
768 }
769
770 bool opensScope(const AnnotatedToken &Tok) {
771 return Current->is(tok::l_paren) || Current->Type == TT_TemplateOpener ||
772 Current->is(tok::l_brace) || Current->is(tok::l_square);
773 }
774
775 AnnotatedToken *Current;
776};
777
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000778void TokenAnnotator::annotate(AnnotatedLine &Line) {
Nico Weberc2e6d2a2013-02-11 15:32:15 +0000779 AnnotatingParser Parser(SourceMgr, Lex, Line, Ident_in);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000780 Line.Type = Parser.parseLine();
781 if (Line.Type == LT_Invalid)
782 return;
783
Daniel Jasper29f123b2013-02-08 15:28:42 +0000784 ExpressionParser ExprParser(Line);
785 ExprParser.parse();
786
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000787 if (Line.First.Type == TT_ObjCMethodSpecifier)
788 Line.Type = LT_ObjCMethodDecl;
789 else if (Line.First.Type == TT_ObjCDecl)
790 Line.Type = LT_ObjCDecl;
791 else if (Line.First.Type == TT_ObjCProperty)
792 Line.Type = LT_ObjCProperty;
793
Daniel Jasper729a7432013-02-11 12:36:37 +0000794 Line.First.SpacesRequiredBefore = 1;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000795 Line.First.MustBreakBefore = Line.First.FormatTok.MustBreakBefore;
796 Line.First.CanBreakBefore = Line.First.MustBreakBefore;
797
798 Line.First.TotalLength = Line.First.FormatTok.TokenLength;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000799}
800
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000801void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
802 if (Line.First.Children.empty())
803 return;
804 AnnotatedToken *Current = &Line.First.Children[0];
805 while (Current != NULL) {
Daniel Jasper729a7432013-02-11 12:36:37 +0000806 if (Current->Type == TT_LineComment)
807 Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments;
808 else
809 Current->SpacesRequiredBefore =
810 spaceRequiredBefore(Line, *Current) ? 1 : 0;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000811
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000812 if (Current->FormatTok.MustBreakBefore) {
813 Current->MustBreakBefore = true;
814 } else if (Current->Type == TT_LineComment) {
815 Current->MustBreakBefore = Current->FormatTok.NewlinesBefore > 0;
Daniel Jasper29f123b2013-02-08 15:28:42 +0000816 } else if (isTrailingComment(Current->Parent) ||
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000817 (Current->is(tok::string_literal) &&
818 Current->Parent->is(tok::string_literal))) {
819 Current->MustBreakBefore = true;
820 } else if (Current->is(tok::lessless) && !Current->Children.empty() &&
821 Current->Parent->is(tok::string_literal) &&
822 Current->Children[0].is(tok::string_literal)) {
823 Current->MustBreakBefore = true;
824 } else {
825 Current->MustBreakBefore = false;
826 }
827 Current->CanBreakBefore =
828 Current->MustBreakBefore || canBreakBefore(Line, *Current);
829 if (Current->MustBreakBefore)
830 Current->TotalLength = Current->Parent->TotalLength + Style.ColumnLimit;
831 else
832 Current->TotalLength =
833 Current->Parent->TotalLength + Current->FormatTok.TokenLength +
Daniel Jasper729a7432013-02-11 12:36:37 +0000834 Current->SpacesRequiredBefore;
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000835 // FIXME: Only calculate this if CanBreakBefore is true once static
836 // initializers etc. are sorted out.
837 // FIXME: Move magic numbers to a better place.
838 Current->SplitPenalty =
839 20 * Current->BindingStrength + splitPenalty(Line, *Current);
840
841 Current = Current->Children.empty() ? NULL : &Current->Children[0];
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000842 }
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000843}
844
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000845unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
846 const AnnotatedToken &Tok) {
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000847 const AnnotatedToken &Left = *Tok.Parent;
848 const AnnotatedToken &Right = Tok;
849
850 if (Left.is(tok::l_brace) && Right.isNot(tok::l_brace))
851 return 50;
852 if (Left.is(tok::equal) && Right.is(tok::l_brace))
853 return 150;
854 if (Left.is(tok::coloncolon))
855 return 500;
856
857 if (Left.Type == TT_RangeBasedForLoopColon)
858 return 5;
859
860 if (Right.is(tok::arrow) || Right.is(tok::period)) {
861 if (Left.is(tok::r_paren) && Line.Type == LT_BuilderTypeCall)
862 return 5; // Should be smaller than breaking at a nested comma.
863 return 150;
864 }
865
866 // In for-loops, prefer breaking at ',' and ';'.
867 if (Line.First.is(tok::kw_for) &&
868 (Left.isNot(tok::comma) && Left.isNot(tok::semi)))
869 return 20;
870
Daniel Jasper8159d2f2013-02-04 07:30:30 +0000871 if (Left.is(tok::semi))
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000872 return 0;
Daniel Jasper8159d2f2013-02-04 07:30:30 +0000873 if (Left.is(tok::comma))
874 return 1;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000875
876 // In Objective-C method expressions, prefer breaking before "param:" over
877 // breaking after it.
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000878 if (Right.Type == TT_ObjCSelectorName)
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000879 return 0;
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000880 if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000881 return 20;
882
Daniel Jasper01786732013-02-04 07:21:18 +0000883 if (Left.is(tok::l_paren) || Left.is(tok::l_square) ||
884 Left.Type == TT_TemplateOpener)
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000885 return 20;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000886
Daniel Jasper4e8a7b42013-02-06 21:04:05 +0000887 if (Right.is(tok::lessless)) {
888 if (Left.is(tok::string_literal)) {
889 char LastChar =
890 StringRef(Left.FormatTok.Tok.getLiteralData(),
891 Left.FormatTok.TokenLength).drop_back(1).rtrim().back();
892 if (LastChar == ':' || LastChar == '=')
893 return 100;
894 }
Daniel Jasper01786732013-02-04 07:21:18 +0000895 return prec::Shift;
Daniel Jasper4e8a7b42013-02-06 21:04:05 +0000896 }
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000897 if (Left.Type == TT_ConditionalExpr)
898 return prec::Assignment;
899 prec::Level Level = getPrecedence(Left);
900
901 if (Level != prec::Unknown)
902 return Level;
903
904 return 3;
905}
906
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000907bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
908 const AnnotatedToken &Left,
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000909 const AnnotatedToken &Right) {
910 if (Right.is(tok::hashhash))
911 return Left.is(tok::hash);
912 if (Left.is(tok::hashhash) || Left.is(tok::hash))
913 return Right.is(tok::hash);
914 if (Right.is(tok::r_paren) || Right.is(tok::semi) || Right.is(tok::comma))
915 return false;
916 if (Right.is(tok::less) &&
917 (Left.is(tok::kw_template) ||
918 (Line.Type == LT_ObjCDecl && Style.ObjCSpaceBeforeProtocolList)))
919 return true;
920 if (Left.is(tok::arrow) || Right.is(tok::arrow))
921 return false;
922 if (Left.is(tok::exclaim) || Left.is(tok::tilde))
923 return false;
924 if (Left.is(tok::at) &&
925 (Right.is(tok::identifier) || Right.is(tok::string_literal) ||
926 Right.is(tok::char_constant) || Right.is(tok::numeric_constant) ||
927 Right.is(tok::l_paren) || Right.is(tok::l_brace) ||
928 Right.is(tok::kw_true) || Right.is(tok::kw_false)))
929 return false;
930 if (Left.is(tok::coloncolon))
931 return false;
932 if (Right.is(tok::coloncolon))
Daniel Jasperdaf1a152013-02-07 21:08:36 +0000933 return Left.isNot(tok::identifier) && Left.isNot(tok::greater) &&
934 Left.isNot(tok::l_paren);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000935 if (Left.is(tok::less) || Right.is(tok::greater) || Right.is(tok::less))
936 return false;
937 if (Right.is(tok::amp) || Right.is(tok::star))
938 return Left.FormatTok.Tok.isLiteral() ||
939 (Left.isNot(tok::star) && Left.isNot(tok::amp) &&
Nico Weber95e8e462013-02-12 16:17:07 +0000940 Left.isNot(tok::l_paren) && !Style.PointerBindsToType);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000941 if (Left.is(tok::amp) || Left.is(tok::star))
Nico Weber95e8e462013-02-12 16:17:07 +0000942 return Right.FormatTok.Tok.isLiteral() ||
943 (Right.isNot(tok::star) && Right.isNot(tok::amp) &&
944 Style.PointerBindsToType);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000945 if (Right.is(tok::star) && Left.is(tok::l_paren))
946 return false;
Nico Weber051860e2013-02-10 02:08:05 +0000947 if (Left.is(tok::l_square))
948 return Left.Type == TT_ObjCArrayLiteral && Right.isNot(tok::r_square);
949 if (Right.is(tok::r_square))
950 return Right.Type == TT_ObjCArrayLiteral;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000951 if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr)
952 return false;
953 if (Left.is(tok::period) || Right.is(tok::period))
954 return false;
955 if (Left.is(tok::colon))
956 return Left.Type != TT_ObjCMethodExpr;
957 if (Right.is(tok::colon))
958 return Right.Type != TT_ObjCMethodExpr;
959 if (Left.is(tok::l_paren))
960 return false;
961 if (Right.is(tok::l_paren)) {
962 return Line.Type == LT_ObjCDecl || Left.is(tok::kw_if) ||
963 Left.is(tok::kw_for) || Left.is(tok::kw_while) ||
964 Left.is(tok::kw_switch) || Left.is(tok::kw_return) ||
965 Left.is(tok::kw_catch) || Left.is(tok::kw_new) ||
966 Left.is(tok::kw_delete);
967 }
968 if (Left.is(tok::at) &&
969 Right.FormatTok.Tok.getObjCKeywordID() != tok::objc_not_keyword)
970 return false;
971 if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
972 return false;
973 return true;
974}
975
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000976bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
977 const AnnotatedToken &Tok) {
Daniel Jasper2b4c9242013-02-11 08:01:18 +0000978 if (Tok.FormatTok.Tok.getIdentifierInfo() &&
979 Tok.Parent->FormatTok.Tok.getIdentifierInfo())
980 return true; // Never ever merge two identifiers.
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000981 if (Line.Type == LT_ObjCMethodDecl) {
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000982 if (Tok.Parent->Type == TT_ObjCMethodSpecifier)
983 return true;
984 if (Tok.Parent->is(tok::r_paren) && Tok.is(tok::identifier))
985 // Don't space between ')' and <id>
986 return false;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000987 }
988 if (Line.Type == LT_ObjCProperty &&
989 (Tok.is(tok::equal) || Tok.Parent->is(tok::equal)))
990 return false;
991
992 if (Tok.Parent->is(tok::comma))
993 return true;
994 if (Tok.Type == TT_CtorInitializerColon || Tok.Type == TT_ObjCBlockLParen)
995 return true;
Daniel Jasper2b4c9242013-02-11 08:01:18 +0000996 if (Tok.Parent->FormatTok.Tok.is(tok::kw_operator))
997 return false;
998 if (Tok.Type == TT_OverloadedOperatorLParen)
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000999 return false;
1000 if (Tok.is(tok::colon))
1001 return Line.First.isNot(tok::kw_case) && !Tok.Children.empty() &&
1002 Tok.Type != TT_ObjCMethodExpr;
1003 if (Tok.Parent->Type == TT_UnaryOperator || Tok.Parent->Type == TT_CastRParen)
1004 return false;
1005 if (Tok.Type == TT_UnaryOperator)
1006 return Tok.Parent->isNot(tok::l_paren) &&
1007 Tok.Parent->isNot(tok::l_square) && Tok.Parent->isNot(tok::at) &&
1008 (Tok.Parent->isNot(tok::colon) ||
1009 Tok.Parent->Type != TT_ObjCMethodExpr);
1010 if (Tok.Parent->is(tok::greater) && Tok.is(tok::greater)) {
Daniel Jasper29f123b2013-02-08 15:28:42 +00001011 return Tok.Type == TT_TemplateCloser &&
1012 Tok.Parent->Type == TT_TemplateCloser &&
1013 Style.Standard != FormatStyle::LS_Cpp11;
Daniel Jasper32d28ee2013-01-29 21:01:14 +00001014 }
1015 if (Tok.Type == TT_BinaryOperator || Tok.Parent->Type == TT_BinaryOperator)
1016 return true;
1017 if (Tok.Parent->Type == TT_TemplateCloser && Tok.is(tok::l_paren))
1018 return false;
1019 if (Tok.is(tok::less) && Line.First.is(tok::hash))
1020 return true;
1021 if (Tok.Type == TT_TrailingUnaryOperator)
1022 return false;
Daniel Jasper8ff690a2013-02-06 14:22:40 +00001023 return spaceRequiredBetween(Line, *Tok.Parent, Tok);
Daniel Jasper32d28ee2013-01-29 21:01:14 +00001024}
1025
Daniel Jasper8ff690a2013-02-06 14:22:40 +00001026bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
1027 const AnnotatedToken &Right) {
Daniel Jasper32d28ee2013-01-29 21:01:14 +00001028 const AnnotatedToken &Left = *Right.Parent;
Daniel Jasper32d28ee2013-01-29 21:01:14 +00001029 if (Right.Type == TT_StartOfName && Style.AllowReturnTypeOnItsOwnLine)
1030 return true;
1031 if (Right.is(tok::colon) && Right.Type == TT_ObjCMethodExpr)
1032 return false;
1033 if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
1034 return true;
Daniel Jasper63d7ced2013-02-05 10:07:47 +00001035 if (Right.Type == TT_ObjCSelectorName)
Daniel Jasper32d28ee2013-01-29 21:01:14 +00001036 return true;
1037 if (Left.ClosesTemplateDeclaration)
1038 return true;
1039 if (Right.Type == TT_ConditionalExpr || Right.is(tok::question))
1040 return true;
1041 if (Left.Type == TT_RangeBasedForLoopColon)
1042 return true;
1043 if (Left.Type == TT_PointerOrReference || Left.Type == TT_TemplateCloser ||
1044 Left.Type == TT_UnaryOperator || Left.Type == TT_ConditionalExpr ||
1045 Left.is(tok::question))
1046 return false;
1047 if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl)
1048 return false;
1049
1050 if (Right.Type == TT_LineComment)
1051 // We rely on MustBreakBefore being set correctly here as we should not
1052 // change the "binding" behavior of a comment.
1053 return false;
1054
1055 // Allow breaking after a trailing 'const', e.g. after a method declaration,
1056 // unless it is follow by ';', '{' or '='.
1057 if (Left.is(tok::kw_const) && Left.Parent != NULL &&
1058 Left.Parent->is(tok::r_paren))
1059 return Right.isNot(tok::l_brace) && Right.isNot(tok::semi) &&
1060 Right.isNot(tok::equal);
1061
1062 // We only break before r_brace if there was a corresponding break before
1063 // the l_brace, which is tracked by BreakBeforeClosingBrace.
1064 if (Right.is(tok::r_brace))
1065 return false;
1066
1067 if (Right.is(tok::r_paren) || Right.is(tok::greater))
1068 return false;
1069 return (isBinaryOperator(Left) && Left.isNot(tok::lessless)) ||
1070 Left.is(tok::comma) || Right.is(tok::lessless) ||
1071 Right.is(tok::arrow) || Right.is(tok::period) ||
1072 Right.is(tok::colon) || Left.is(tok::coloncolon) ||
1073 Left.is(tok::semi) || Left.is(tok::l_brace) ||
1074 (Left.is(tok::r_paren) && Left.Type != TT_CastRParen &&
1075 Right.is(tok::identifier)) ||
1076 (Left.is(tok::l_paren) && !Right.is(tok::r_paren)) ||
1077 (Left.is(tok::l_square) && !Right.is(tok::r_square));
1078}
1079
1080} // namespace format
1081} // namespace clang