blob: 22e67df1ecac2ba07d7beb6c1631ae93e2b6e24a [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 Jasper6cabab42013-02-14 08:42:54 +0000326 } else if (Contexts.size() == 1) {
327 Tok->Type = TT_InheritanceColon;
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000328 }
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000329 break;
330 case tok::kw_if:
331 case tok::kw_while:
332 if (CurrentToken != NULL && CurrentToken->is(tok::l_paren)) {
333 next();
334 if (!parseParens(/*LookForDecls=*/ true))
335 return false;
336 }
337 break;
338 case tok::kw_for:
Daniel Jasper4e778092013-02-06 10:05:46 +0000339 Contexts.back().ColonIsForRangeExpr = true;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000340 next();
341 if (!parseParens())
342 return false;
343 break;
344 case tok::l_paren:
345 if (!parseParens())
346 return false;
347 break;
348 case tok::l_square:
349 if (!parseSquare())
350 return false;
351 break;
352 case tok::l_brace:
353 if (!parseBrace())
354 return false;
355 break;
356 case tok::less:
357 if (parseAngle())
358 Tok->Type = TT_TemplateOpener;
359 else {
360 Tok->Type = TT_BinaryOperator;
361 CurrentToken = Tok;
362 next();
363 }
364 break;
365 case tok::r_paren:
366 case tok::r_square:
367 return false;
368 case tok::r_brace:
369 // Lines can start with '}'.
370 if (Tok->Parent != NULL)
371 return false;
372 break;
373 case tok::greater:
374 Tok->Type = TT_BinaryOperator;
375 break;
376 case tok::kw_operator:
Daniel Jasper2b4c9242013-02-11 08:01:18 +0000377 while (CurrentToken && CurrentToken->isNot(tok::l_paren)) {
378 if (CurrentToken->is(tok::star) || CurrentToken->is(tok::amp))
379 CurrentToken->Type = TT_PointerOrReference;
380 consumeToken();
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000381 }
Daniel Jasper2b4c9242013-02-11 08:01:18 +0000382 if (CurrentToken)
383 CurrentToken->Type = TT_OverloadedOperatorLParen;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000384 break;
385 case tok::question:
386 parseConditional();
387 break;
388 case tok::kw_template:
389 parseTemplateDeclaration();
390 break;
Nico Weberc2e6d2a2013-02-11 15:32:15 +0000391 case tok::identifier:
392 if (Line.First.is(tok::kw_for) &&
393 Tok->FormatTok.Tok.getIdentifierInfo() == &Ident_in)
394 Tok->Type = TT_ObjCForIn;
395 break;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000396 default:
397 break;
398 }
399 return true;
400 }
401
402 void parseIncludeDirective() {
403 next();
404 if (CurrentToken != NULL && CurrentToken->is(tok::less)) {
405 next();
406 while (CurrentToken != NULL) {
407 if (CurrentToken->isNot(tok::comment) ||
408 !CurrentToken->Children.empty())
409 CurrentToken->Type = TT_ImplicitStringLiteral;
410 next();
411 }
412 } else {
413 while (CurrentToken != NULL) {
414 next();
415 }
416 }
417 }
418
419 void parseWarningOrError() {
420 next();
421 // We still want to format the whitespace left of the first token of the
422 // warning or error.
423 next();
424 while (CurrentToken != NULL) {
425 CurrentToken->Type = TT_ImplicitStringLiteral;
426 next();
427 }
428 }
429
430 void parsePreprocessorDirective() {
431 next();
432 if (CurrentToken == NULL)
433 return;
434 // Hashes in the middle of a line can lead to any strange token
435 // sequence.
436 if (CurrentToken->FormatTok.Tok.getIdentifierInfo() == NULL)
437 return;
438 switch (CurrentToken->FormatTok.Tok.getIdentifierInfo()->getPPKeywordID()) {
439 case tok::pp_include:
440 case tok::pp_import:
441 parseIncludeDirective();
442 break;
443 case tok::pp_error:
444 case tok::pp_warning:
445 parseWarningOrError();
446 break;
447 default:
448 break;
449 }
Daniel Jasper5b7e7b02013-02-05 09:34:14 +0000450 while (CurrentToken != NULL)
451 next();
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000452 }
453
Nico Weber95e8e462013-02-12 16:17:07 +0000454public:
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000455 LineType parseLine() {
456 int PeriodsAndArrows = 0;
457 bool CanBeBuilderTypeStmt = true;
458 if (CurrentToken->is(tok::hash)) {
459 parsePreprocessorDirective();
460 return LT_PreprocessorDirective;
461 }
462 while (CurrentToken != NULL) {
463 if (CurrentToken->is(tok::kw_virtual))
464 KeywordVirtualFound = true;
465 if (CurrentToken->is(tok::period) || CurrentToken->is(tok::arrow))
466 ++PeriodsAndArrows;
467 if (getPrecedence(*CurrentToken) > prec::Assignment &&
468 CurrentToken->isNot(tok::less) && CurrentToken->isNot(tok::greater))
469 CanBeBuilderTypeStmt = false;
470 if (!consumeToken())
471 return LT_Invalid;
472 }
473 if (KeywordVirtualFound)
474 return LT_VirtualFunctionDecl;
475
476 // Assume a builder-type call if there are 2 or more "." and "->".
477 if (PeriodsAndArrows >= 2 && CanBeBuilderTypeStmt)
478 return LT_BuilderTypeCall;
479
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000480 if (Line.First.Type == TT_ObjCMethodSpecifier) {
Daniel Jasper4e778092013-02-06 10:05:46 +0000481 if (Contexts.back().FirstObjCSelectorName != NULL)
482 Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
483 Contexts.back().LongestObjCSelectorName;
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000484 return LT_ObjCMethodDecl;
485 }
486
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000487 return LT_Other;
488 }
489
Nico Weber95e8e462013-02-12 16:17:07 +0000490private:
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000491 void next() {
Daniel Jasper01786732013-02-04 07:21:18 +0000492 if (CurrentToken != NULL) {
493 determineTokenType(*CurrentToken);
Daniel Jasper4e778092013-02-06 10:05:46 +0000494 CurrentToken->BindingStrength = Contexts.back().BindingStrength;
Daniel Jasper01786732013-02-04 07:21:18 +0000495 }
496
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000497 if (CurrentToken != NULL && !CurrentToken->Children.empty())
498 CurrentToken = &CurrentToken->Children[0];
499 else
500 CurrentToken = NULL;
501 }
502
Daniel Jasper4e778092013-02-06 10:05:46 +0000503 /// \brief A struct to hold information valid in a specific context, e.g.
504 /// a pair of parenthesis.
505 struct Context {
506 Context(unsigned BindingStrength, bool IsExpression)
507 : BindingStrength(BindingStrength), LongestObjCSelectorName(0),
508 ColonIsForRangeExpr(false), ColonIsObjCMethodExpr(false),
509 FirstObjCSelectorName(NULL), IsExpression(IsExpression),
510 LookForFunctionName(false) {
511 }
Daniel Jasper01786732013-02-04 07:21:18 +0000512
Daniel Jasper4e778092013-02-06 10:05:46 +0000513 unsigned BindingStrength;
514 unsigned LongestObjCSelectorName;
515 bool ColonIsForRangeExpr;
516 bool ColonIsObjCMethodExpr;
517 AnnotatedToken *FirstObjCSelectorName;
518 bool IsExpression;
519 bool LookForFunctionName;
520 };
521
522 /// \brief Puts a new \c Context onto the stack \c Contexts for the lifetime
523 /// of each instance.
524 struct ScopedContextCreator {
525 AnnotatingParser &P;
526
527 ScopedContextCreator(AnnotatingParser &P, unsigned Increase)
528 : P(P) {
529 P.Contexts.push_back(Context(
530 P.Contexts.back().BindingStrength + Increase,
531 P.Contexts.back().IsExpression));
532 }
533
534 ~ScopedContextCreator() { P.Contexts.pop_back(); }
535 };
Daniel Jasper01786732013-02-04 07:21:18 +0000536
537 void determineTokenType(AnnotatedToken &Current) {
538 if (getPrecedence(Current) == prec::Assignment) {
Daniel Jasper4e778092013-02-06 10:05:46 +0000539 Contexts.back().IsExpression = true;
Nico Weber95e8e462013-02-12 16:17:07 +0000540 for (AnnotatedToken *Previous = Current.Parent;
541 Previous && Previous->isNot(tok::comma);
542 Previous = Previous->Parent) {
Daniel Jasper01786732013-02-04 07:21:18 +0000543 if (Previous->Type == TT_BinaryOperator &&
544 (Previous->is(tok::star) || Previous->is(tok::amp))) {
545 Previous->Type = TT_PointerOrReference;
546 }
Daniel Jasper01786732013-02-04 07:21:18 +0000547 }
Nico Weber95e8e462013-02-12 16:17:07 +0000548 } else if (Current.is(tok::kw_return) || Current.is(tok::kw_throw) ||
549 (Current.is(tok::l_paren) && !Line.MustBeDeclaration &&
550 (!Current.Parent || Current.Parent->isNot(tok::kw_for)))) {
Daniel Jasper4e778092013-02-06 10:05:46 +0000551 Contexts.back().IsExpression = true;
Nico Weber95e8e462013-02-12 16:17:07 +0000552 } else if (Current.is(tok::r_paren) || Current.is(tok::greater) ||
553 Current.is(tok::comma)) {
554 for (AnnotatedToken *Previous = Current.Parent;
555 Previous && (Previous->is(tok::star) || Previous->is(tok::amp));
556 Previous = Previous->Parent)
557 Previous->Type = TT_PointerOrReference;
558 }
Daniel Jasper01786732013-02-04 07:21:18 +0000559
560 if (Current.Type == TT_Unknown) {
Daniel Jasper4e778092013-02-06 10:05:46 +0000561 if (Contexts.back().LookForFunctionName && Current.is(tok::l_paren)) {
Daniel Jasper01786732013-02-04 07:21:18 +0000562 findFunctionName(&Current);
Daniel Jasper4e778092013-02-06 10:05:46 +0000563 Contexts.back().LookForFunctionName = false;
Daniel Jasper01786732013-02-04 07:21:18 +0000564 } else if (Current.is(tok::star) || Current.is(tok::amp)) {
Daniel Jasper4e778092013-02-06 10:05:46 +0000565 Current.Type =
566 determineStarAmpUsage(Current, Contexts.back().IsExpression);
Daniel Jasper01786732013-02-04 07:21:18 +0000567 } else if (Current.is(tok::minus) || Current.is(tok::plus) ||
568 Current.is(tok::caret)) {
569 Current.Type = determinePlusMinusCaretUsage(Current);
570 } else if (Current.is(tok::minusminus) || Current.is(tok::plusplus)) {
571 Current.Type = determineIncrementUsage(Current);
572 } else if (Current.is(tok::exclaim)) {
573 Current.Type = TT_UnaryOperator;
574 } else if (isBinaryOperator(Current)) {
575 Current.Type = TT_BinaryOperator;
576 } else if (Current.is(tok::comment)) {
577 std::string Data(Lexer::getSpelling(Current.FormatTok.Tok, SourceMgr,
578 Lex.getLangOpts()));
579 if (StringRef(Data).startswith("//"))
580 Current.Type = TT_LineComment;
581 else
582 Current.Type = TT_BlockComment;
Nico Weber37d69312013-02-13 04:13:13 +0000583 } else if (Current.is(tok::r_paren)) {
584 bool ParensNotExpr = Current.Parent->Type == TT_PointerOrReference ||
585 Current.Parent->Type == TT_TemplateCloser;
586 bool ParensCouldEndDecl =
587 !Current.Children.empty() && (Current.Children[0].is(tok::equal) ||
588 Current.Children[0].is(tok::semi) ||
589 Current.Children[0].is(tok::l_brace));
590 if (ParensNotExpr && !ParensCouldEndDecl)
591 // FIXME: We need to get smarter and understand more cases of casts.
592 Current.Type = TT_CastRParen;
Daniel Jasper01786732013-02-04 07:21:18 +0000593 } else if (Current.is(tok::at) && Current.Children.size()) {
594 switch (Current.Children[0].FormatTok.Tok.getObjCKeywordID()) {
595 case tok::objc_interface:
596 case tok::objc_implementation:
597 case tok::objc_protocol:
598 Current.Type = TT_ObjCDecl;
599 break;
600 case tok::objc_property:
601 Current.Type = TT_ObjCProperty;
602 break;
603 default:
604 break;
605 }
606 }
607 }
608 }
609
610 /// \brief Starting from \p Current, this searches backwards for an
611 /// identifier which could be the start of a function name and marks it.
612 void findFunctionName(AnnotatedToken *Current) {
613 AnnotatedToken *Parent = Current->Parent;
614 while (Parent != NULL && Parent->Parent != NULL) {
615 if (Parent->is(tok::identifier) &&
616 (Parent->Parent->is(tok::identifier) ||
617 Parent->Parent->Type == TT_PointerOrReference ||
618 Parent->Parent->Type == TT_TemplateCloser)) {
619 Parent->Type = TT_StartOfName;
620 break;
621 }
622 Parent = Parent->Parent;
623 }
624 }
625
626 /// \brief Return the type of the given token assuming it is * or &.
627 TokenType
628 determineStarAmpUsage(const AnnotatedToken &Tok, bool IsExpression) {
629 const AnnotatedToken *PrevToken = getPreviousToken(Tok);
630 if (PrevToken == NULL)
631 return TT_UnaryOperator;
632
633 const AnnotatedToken *NextToken = getNextToken(Tok);
634 if (NextToken == NULL)
635 return TT_Unknown;
636
Daniel Jasper01786732013-02-04 07:21:18 +0000637 if (PrevToken->is(tok::l_paren) || PrevToken->is(tok::l_square) ||
638 PrevToken->is(tok::l_brace) || PrevToken->is(tok::comma) ||
639 PrevToken->is(tok::kw_return) || PrevToken->is(tok::colon) ||
Nico Webere8a97982013-02-06 06:20:11 +0000640 PrevToken->is(tok::equal) || PrevToken->Type == TT_BinaryOperator ||
Daniel Jasper01786732013-02-04 07:21:18 +0000641 PrevToken->Type == TT_UnaryOperator || PrevToken->Type == TT_CastRParen)
642 return TT_UnaryOperator;
643
Nico Webere8a97982013-02-06 06:20:11 +0000644 if (NextToken->is(tok::l_square))
645 return TT_PointerOrReference;
646
Daniel Jasper01786732013-02-04 07:21:18 +0000647 if (PrevToken->FormatTok.Tok.isLiteral() || PrevToken->is(tok::r_paren) ||
648 PrevToken->is(tok::r_square) || NextToken->FormatTok.Tok.isLiteral() ||
Nico Weberee0feec2013-02-05 16:21:00 +0000649 isUnaryOperator(*NextToken) || NextToken->is(tok::l_paren) ||
650 NextToken->is(tok::l_square))
Daniel Jasper01786732013-02-04 07:21:18 +0000651 return TT_BinaryOperator;
652
Daniel Jasper01786732013-02-04 07:21:18 +0000653 // It is very unlikely that we are going to find a pointer or reference type
654 // definition on the RHS of an assignment.
655 if (IsExpression)
656 return TT_BinaryOperator;
657
658 return TT_PointerOrReference;
659 }
660
661 TokenType determinePlusMinusCaretUsage(const AnnotatedToken &Tok) {
662 const AnnotatedToken *PrevToken = getPreviousToken(Tok);
663 if (PrevToken == NULL)
664 return TT_UnaryOperator;
665
666 // Use heuristics to recognize unary operators.
667 if (PrevToken->is(tok::equal) || PrevToken->is(tok::l_paren) ||
668 PrevToken->is(tok::comma) || PrevToken->is(tok::l_square) ||
669 PrevToken->is(tok::question) || PrevToken->is(tok::colon) ||
670 PrevToken->is(tok::kw_return) || PrevToken->is(tok::kw_case) ||
671 PrevToken->is(tok::at) || PrevToken->is(tok::l_brace))
672 return TT_UnaryOperator;
673
Nico Weberee0feec2013-02-05 16:21:00 +0000674 // There can't be two consecutive binary operators.
Daniel Jasper01786732013-02-04 07:21:18 +0000675 if (PrevToken->Type == TT_BinaryOperator)
676 return TT_UnaryOperator;
677
678 // Fall back to marking the token as binary operator.
679 return TT_BinaryOperator;
680 }
681
682 /// \brief Determine whether ++/-- are pre- or post-increments/-decrements.
683 TokenType determineIncrementUsage(const AnnotatedToken &Tok) {
684 const AnnotatedToken *PrevToken = getPreviousToken(Tok);
685 if (PrevToken == NULL)
686 return TT_UnaryOperator;
687 if (PrevToken->is(tok::r_paren) || PrevToken->is(tok::r_square) ||
688 PrevToken->is(tok::identifier))
689 return TT_TrailingUnaryOperator;
690
691 return TT_UnaryOperator;
692 }
Daniel Jasper4e778092013-02-06 10:05:46 +0000693
694 SmallVector<Context, 8> Contexts;
695
696 SourceManager &SourceMgr;
697 Lexer &Lex;
698 AnnotatedLine &Line;
699 AnnotatedToken *CurrentToken;
700 bool KeywordVirtualFound;
Nico Weberc2e6d2a2013-02-11 15:32:15 +0000701 IdentifierInfo &Ident_in;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000702};
703
Daniel Jasper29f123b2013-02-08 15:28:42 +0000704/// \brief Parses binary expressions by inserting fake parenthesis based on
705/// operator precedence.
706class ExpressionParser {
707public:
708 ExpressionParser(AnnotatedLine &Line) : Current(&Line.First) {}
709
710 /// \brief Parse expressions with the given operatore precedence.
Dmitri Gribenkob0112e12013-02-12 22:40:22 +0000711 void parse(int Precedence = prec::Unknown) {
Daniel Jasper29f123b2013-02-08 15:28:42 +0000712 if (Precedence > prec::PointerToMember || Current == NULL)
713 return;
714
715 // Skip over "return" until we can properly parse it.
716 if (Current->is(tok::kw_return))
717 next();
718
719 // Eagerly consume trailing comments.
720 while (isTrailingComment(Current)) {
721 next();
722 }
723
724 AnnotatedToken *Start = Current;
725 bool OperatorFound = false;
726
727 while (Current != NULL) {
728 // Consume operators with higher precedence.
729 parse(Precedence + 1);
730
731 // At the end of the line or when an operator with higher precedence is
732 // found, insert fake parenthesis and return.
733 if (Current == NULL || Current->is(tok::semi) || closesScope(*Current) ||
734 ((Current->Type == TT_BinaryOperator || Current->is(tok::comma)) &&
Aaron Ballman468e3992013-02-12 19:20:48 +0000735 getPrecedence(*Current) < Precedence)) {
Daniel Jasper29f123b2013-02-08 15:28:42 +0000736 if (OperatorFound) {
737 ++Start->FakeLParens;
738 if (Current != NULL)
Daniel Jasper087387a2013-02-08 16:49:27 +0000739 ++Current->Parent->FakeRParens;
Daniel Jasper29f123b2013-02-08 15:28:42 +0000740 }
741 return;
742 }
743
744 // Consume scopes: (), [], <> and {}
745 if (opensScope(*Current)) {
746 while (Current != NULL && !closesScope(*Current)) {
747 next();
748 parse();
749 }
750 next();
751 } else {
752 // Operator found.
753 if (getPrecedence(*Current) == Precedence)
754 OperatorFound = true;
755
756 next();
757 }
758 }
759 }
760
761private:
762 void next() {
763 if (Current != NULL)
764 Current = Current->Children.empty() ? NULL : &Current->Children[0];
765 }
766
767 bool closesScope(const AnnotatedToken &Tok) {
768 return Current->is(tok::r_paren) || Current->Type == TT_TemplateCloser ||
769 Current->is(tok::r_brace) || Current->is(tok::r_square);
770 }
771
772 bool opensScope(const AnnotatedToken &Tok) {
773 return Current->is(tok::l_paren) || Current->Type == TT_TemplateOpener ||
774 Current->is(tok::l_brace) || Current->is(tok::l_square);
775 }
776
777 AnnotatedToken *Current;
778};
779
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000780void TokenAnnotator::annotate(AnnotatedLine &Line) {
Nico Weberc2e6d2a2013-02-11 15:32:15 +0000781 AnnotatingParser Parser(SourceMgr, Lex, Line, Ident_in);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000782 Line.Type = Parser.parseLine();
783 if (Line.Type == LT_Invalid)
784 return;
785
Daniel Jasper29f123b2013-02-08 15:28:42 +0000786 ExpressionParser ExprParser(Line);
787 ExprParser.parse();
788
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000789 if (Line.First.Type == TT_ObjCMethodSpecifier)
790 Line.Type = LT_ObjCMethodDecl;
791 else if (Line.First.Type == TT_ObjCDecl)
792 Line.Type = LT_ObjCDecl;
793 else if (Line.First.Type == TT_ObjCProperty)
794 Line.Type = LT_ObjCProperty;
795
Daniel Jasper729a7432013-02-11 12:36:37 +0000796 Line.First.SpacesRequiredBefore = 1;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000797 Line.First.MustBreakBefore = Line.First.FormatTok.MustBreakBefore;
798 Line.First.CanBreakBefore = Line.First.MustBreakBefore;
799
800 Line.First.TotalLength = Line.First.FormatTok.TokenLength;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000801}
802
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000803void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
804 if (Line.First.Children.empty())
805 return;
806 AnnotatedToken *Current = &Line.First.Children[0];
807 while (Current != NULL) {
Daniel Jasper729a7432013-02-11 12:36:37 +0000808 if (Current->Type == TT_LineComment)
809 Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments;
810 else
811 Current->SpacesRequiredBefore =
812 spaceRequiredBefore(Line, *Current) ? 1 : 0;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000813
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000814 if (Current->FormatTok.MustBreakBefore) {
815 Current->MustBreakBefore = true;
816 } else if (Current->Type == TT_LineComment) {
817 Current->MustBreakBefore = Current->FormatTok.NewlinesBefore > 0;
Daniel Jasper29f123b2013-02-08 15:28:42 +0000818 } else if (isTrailingComment(Current->Parent) ||
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000819 (Current->is(tok::string_literal) &&
820 Current->Parent->is(tok::string_literal))) {
821 Current->MustBreakBefore = true;
822 } else if (Current->is(tok::lessless) && !Current->Children.empty() &&
823 Current->Parent->is(tok::string_literal) &&
824 Current->Children[0].is(tok::string_literal)) {
825 Current->MustBreakBefore = true;
826 } else {
827 Current->MustBreakBefore = false;
828 }
829 Current->CanBreakBefore =
830 Current->MustBreakBefore || canBreakBefore(Line, *Current);
831 if (Current->MustBreakBefore)
832 Current->TotalLength = Current->Parent->TotalLength + Style.ColumnLimit;
833 else
834 Current->TotalLength =
835 Current->Parent->TotalLength + Current->FormatTok.TokenLength +
Daniel Jasper729a7432013-02-11 12:36:37 +0000836 Current->SpacesRequiredBefore;
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000837 // FIXME: Only calculate this if CanBreakBefore is true once static
838 // initializers etc. are sorted out.
839 // FIXME: Move magic numbers to a better place.
840 Current->SplitPenalty =
841 20 * Current->BindingStrength + splitPenalty(Line, *Current);
842
843 Current = Current->Children.empty() ? NULL : &Current->Children[0];
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000844 }
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000845}
846
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000847unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
848 const AnnotatedToken &Tok) {
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000849 const AnnotatedToken &Left = *Tok.Parent;
850 const AnnotatedToken &Right = Tok;
851
Daniel Jaspera03ab102013-02-13 20:33:44 +0000852 if (Right.Type == TT_StartOfName)
853 return Style.PenaltyReturnTypeOnItsOwnLine;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000854 if (Left.is(tok::l_brace) && Right.isNot(tok::l_brace))
855 return 50;
856 if (Left.is(tok::equal) && Right.is(tok::l_brace))
857 return 150;
858 if (Left.is(tok::coloncolon))
859 return 500;
860
Daniel Jasper6cabab42013-02-14 08:42:54 +0000861 if (Left.Type == TT_RangeBasedForLoopColon ||
862 Left.Type == TT_InheritanceColon)
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000863 return 5;
864
865 if (Right.is(tok::arrow) || Right.is(tok::period)) {
866 if (Left.is(tok::r_paren) && Line.Type == LT_BuilderTypeCall)
867 return 5; // Should be smaller than breaking at a nested comma.
868 return 150;
869 }
870
871 // In for-loops, prefer breaking at ',' and ';'.
872 if (Line.First.is(tok::kw_for) &&
873 (Left.isNot(tok::comma) && Left.isNot(tok::semi)))
874 return 20;
875
Daniel Jasper8159d2f2013-02-04 07:30:30 +0000876 if (Left.is(tok::semi))
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000877 return 0;
Daniel Jasper8159d2f2013-02-04 07:30:30 +0000878 if (Left.is(tok::comma))
879 return 1;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000880
881 // In Objective-C method expressions, prefer breaking before "param:" over
882 // breaking after it.
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000883 if (Right.Type == TT_ObjCSelectorName)
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000884 return 0;
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000885 if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000886 return 20;
887
Daniel Jasper01786732013-02-04 07:21:18 +0000888 if (Left.is(tok::l_paren) || Left.is(tok::l_square) ||
889 Left.Type == TT_TemplateOpener)
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000890 return 20;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000891
Daniel Jasper4e8a7b42013-02-06 21:04:05 +0000892 if (Right.is(tok::lessless)) {
893 if (Left.is(tok::string_literal)) {
894 char LastChar =
895 StringRef(Left.FormatTok.Tok.getLiteralData(),
896 Left.FormatTok.TokenLength).drop_back(1).rtrim().back();
897 if (LastChar == ':' || LastChar == '=')
898 return 100;
899 }
Daniel Jasper01786732013-02-04 07:21:18 +0000900 return prec::Shift;
Daniel Jasper4e8a7b42013-02-06 21:04:05 +0000901 }
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000902 if (Left.Type == TT_ConditionalExpr)
903 return prec::Assignment;
904 prec::Level Level = getPrecedence(Left);
905
906 if (Level != prec::Unknown)
907 return Level;
908
909 return 3;
910}
911
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000912bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
913 const AnnotatedToken &Left,
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000914 const AnnotatedToken &Right) {
915 if (Right.is(tok::hashhash))
916 return Left.is(tok::hash);
917 if (Left.is(tok::hashhash) || Left.is(tok::hash))
918 return Right.is(tok::hash);
919 if (Right.is(tok::r_paren) || Right.is(tok::semi) || Right.is(tok::comma))
920 return false;
921 if (Right.is(tok::less) &&
922 (Left.is(tok::kw_template) ||
923 (Line.Type == LT_ObjCDecl && Style.ObjCSpaceBeforeProtocolList)))
924 return true;
925 if (Left.is(tok::arrow) || Right.is(tok::arrow))
926 return false;
927 if (Left.is(tok::exclaim) || Left.is(tok::tilde))
928 return false;
929 if (Left.is(tok::at) &&
930 (Right.is(tok::identifier) || Right.is(tok::string_literal) ||
931 Right.is(tok::char_constant) || Right.is(tok::numeric_constant) ||
932 Right.is(tok::l_paren) || Right.is(tok::l_brace) ||
933 Right.is(tok::kw_true) || Right.is(tok::kw_false)))
934 return false;
935 if (Left.is(tok::coloncolon))
936 return false;
937 if (Right.is(tok::coloncolon))
Daniel Jasperdaf1a152013-02-07 21:08:36 +0000938 return Left.isNot(tok::identifier) && Left.isNot(tok::greater) &&
939 Left.isNot(tok::l_paren);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000940 if (Left.is(tok::less) || Right.is(tok::greater) || Right.is(tok::less))
941 return false;
942 if (Right.is(tok::amp) || Right.is(tok::star))
943 return Left.FormatTok.Tok.isLiteral() ||
944 (Left.isNot(tok::star) && Left.isNot(tok::amp) &&
Nico Weber95e8e462013-02-12 16:17:07 +0000945 Left.isNot(tok::l_paren) && !Style.PointerBindsToType);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000946 if (Left.is(tok::amp) || Left.is(tok::star))
Nico Weber95e8e462013-02-12 16:17:07 +0000947 return Right.FormatTok.Tok.isLiteral() ||
948 (Right.isNot(tok::star) && Right.isNot(tok::amp) &&
949 Style.PointerBindsToType);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000950 if (Right.is(tok::star) && Left.is(tok::l_paren))
951 return false;
Nico Weber051860e2013-02-10 02:08:05 +0000952 if (Left.is(tok::l_square))
953 return Left.Type == TT_ObjCArrayLiteral && Right.isNot(tok::r_square);
954 if (Right.is(tok::r_square))
955 return Right.Type == TT_ObjCArrayLiteral;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000956 if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr)
957 return false;
958 if (Left.is(tok::period) || Right.is(tok::period))
959 return false;
960 if (Left.is(tok::colon))
961 return Left.Type != TT_ObjCMethodExpr;
962 if (Right.is(tok::colon))
963 return Right.Type != TT_ObjCMethodExpr;
964 if (Left.is(tok::l_paren))
965 return false;
966 if (Right.is(tok::l_paren)) {
967 return Line.Type == LT_ObjCDecl || Left.is(tok::kw_if) ||
968 Left.is(tok::kw_for) || Left.is(tok::kw_while) ||
969 Left.is(tok::kw_switch) || Left.is(tok::kw_return) ||
970 Left.is(tok::kw_catch) || Left.is(tok::kw_new) ||
971 Left.is(tok::kw_delete);
972 }
973 if (Left.is(tok::at) &&
974 Right.FormatTok.Tok.getObjCKeywordID() != tok::objc_not_keyword)
975 return false;
976 if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
977 return false;
978 return true;
979}
980
Daniel Jasper8ff690a2013-02-06 14:22:40 +0000981bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
982 const AnnotatedToken &Tok) {
Daniel Jasper2b4c9242013-02-11 08:01:18 +0000983 if (Tok.FormatTok.Tok.getIdentifierInfo() &&
984 Tok.Parent->FormatTok.Tok.getIdentifierInfo())
985 return true; // Never ever merge two identifiers.
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000986 if (Line.Type == LT_ObjCMethodDecl) {
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000987 if (Tok.Parent->Type == TT_ObjCMethodSpecifier)
988 return true;
989 if (Tok.Parent->is(tok::r_paren) && Tok.is(tok::identifier))
990 // Don't space between ')' and <id>
991 return false;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000992 }
993 if (Line.Type == LT_ObjCProperty &&
994 (Tok.is(tok::equal) || Tok.Parent->is(tok::equal)))
995 return false;
996
997 if (Tok.Parent->is(tok::comma))
998 return true;
999 if (Tok.Type == TT_CtorInitializerColon || Tok.Type == TT_ObjCBlockLParen)
1000 return true;
Daniel Jasper2b4c9242013-02-11 08:01:18 +00001001 if (Tok.Parent->FormatTok.Tok.is(tok::kw_operator))
1002 return false;
1003 if (Tok.Type == TT_OverloadedOperatorLParen)
Daniel Jasper32d28ee2013-01-29 21:01:14 +00001004 return false;
1005 if (Tok.is(tok::colon))
1006 return Line.First.isNot(tok::kw_case) && !Tok.Children.empty() &&
1007 Tok.Type != TT_ObjCMethodExpr;
1008 if (Tok.Parent->Type == TT_UnaryOperator || Tok.Parent->Type == TT_CastRParen)
1009 return false;
1010 if (Tok.Type == TT_UnaryOperator)
1011 return Tok.Parent->isNot(tok::l_paren) &&
1012 Tok.Parent->isNot(tok::l_square) && Tok.Parent->isNot(tok::at) &&
1013 (Tok.Parent->isNot(tok::colon) ||
1014 Tok.Parent->Type != TT_ObjCMethodExpr);
1015 if (Tok.Parent->is(tok::greater) && Tok.is(tok::greater)) {
Daniel Jasper29f123b2013-02-08 15:28:42 +00001016 return Tok.Type == TT_TemplateCloser &&
1017 Tok.Parent->Type == TT_TemplateCloser &&
1018 Style.Standard != FormatStyle::LS_Cpp11;
Daniel Jasper32d28ee2013-01-29 21:01:14 +00001019 }
1020 if (Tok.Type == TT_BinaryOperator || Tok.Parent->Type == TT_BinaryOperator)
1021 return true;
1022 if (Tok.Parent->Type == TT_TemplateCloser && Tok.is(tok::l_paren))
1023 return false;
1024 if (Tok.is(tok::less) && Line.First.is(tok::hash))
1025 return true;
1026 if (Tok.Type == TT_TrailingUnaryOperator)
1027 return false;
Daniel Jasper8ff690a2013-02-06 14:22:40 +00001028 return spaceRequiredBetween(Line, *Tok.Parent, Tok);
Daniel Jasper32d28ee2013-01-29 21:01:14 +00001029}
1030
Daniel Jasper8ff690a2013-02-06 14:22:40 +00001031bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
1032 const AnnotatedToken &Right) {
Daniel Jasper32d28ee2013-01-29 21:01:14 +00001033 const AnnotatedToken &Left = *Right.Parent;
Daniel Jaspera03ab102013-02-13 20:33:44 +00001034 if (Right.Type == TT_StartOfName)
Daniel Jasper32d28ee2013-01-29 21:01:14 +00001035 return true;
1036 if (Right.is(tok::colon) && Right.Type == TT_ObjCMethodExpr)
1037 return false;
1038 if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
1039 return true;
Daniel Jasper63d7ced2013-02-05 10:07:47 +00001040 if (Right.Type == TT_ObjCSelectorName)
Daniel Jasper32d28ee2013-01-29 21:01:14 +00001041 return true;
1042 if (Left.ClosesTemplateDeclaration)
1043 return true;
1044 if (Right.Type == TT_ConditionalExpr || Right.is(tok::question))
1045 return true;
Daniel Jasper6cabab42013-02-14 08:42:54 +00001046 if (Right.Type == TT_RangeBasedForLoopColon ||
1047 Right.Type == TT_InheritanceColon)
1048 return false;
1049 if (Left.Type == TT_RangeBasedForLoopColon ||
1050 Left.Type == TT_InheritanceColon)
Daniel Jasper32d28ee2013-01-29 21:01:14 +00001051 return true;
1052 if (Left.Type == TT_PointerOrReference || Left.Type == TT_TemplateCloser ||
1053 Left.Type == TT_UnaryOperator || Left.Type == TT_ConditionalExpr ||
1054 Left.is(tok::question))
1055 return false;
1056 if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl)
1057 return false;
1058
1059 if (Right.Type == TT_LineComment)
1060 // We rely on MustBreakBefore being set correctly here as we should not
1061 // change the "binding" behavior of a comment.
1062 return false;
1063
1064 // Allow breaking after a trailing 'const', e.g. after a method declaration,
1065 // unless it is follow by ';', '{' or '='.
1066 if (Left.is(tok::kw_const) && Left.Parent != NULL &&
1067 Left.Parent->is(tok::r_paren))
1068 return Right.isNot(tok::l_brace) && Right.isNot(tok::semi) &&
1069 Right.isNot(tok::equal);
1070
1071 // We only break before r_brace if there was a corresponding break before
1072 // the l_brace, which is tracked by BreakBeforeClosingBrace.
1073 if (Right.is(tok::r_brace))
1074 return false;
1075
1076 if (Right.is(tok::r_paren) || Right.is(tok::greater))
1077 return false;
1078 return (isBinaryOperator(Left) && Left.isNot(tok::lessless)) ||
1079 Left.is(tok::comma) || Right.is(tok::lessless) ||
1080 Right.is(tok::arrow) || Right.is(tok::period) ||
1081 Right.is(tok::colon) || Left.is(tok::coloncolon) ||
1082 Left.is(tok::semi) || Left.is(tok::l_brace) ||
1083 (Left.is(tok::r_paren) && Left.Type != TT_CastRParen &&
1084 Right.is(tok::identifier)) ||
1085 (Left.is(tok::l_paren) && !Right.is(tok::r_paren)) ||
1086 (Left.is(tok::l_square) && !Right.is(tok::r_square));
1087}
1088
1089} // namespace format
1090} // namespace clang