blob: 03717e91c9f9c42f02042446ac72243f5e477087 [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
Daniel Jasper32d28ee2013-01-29 21:01:14 +000023static bool isBinaryOperator(const AnnotatedToken &Tok) {
24 // Comma is a binary operator, but does not behave as such wrt. formatting.
25 return getPrecedence(Tok) > prec::Comma;
26}
27
Daniel Jasper01786732013-02-04 07:21:18 +000028// Returns the previous token ignoring comments.
29static const AnnotatedToken *getPreviousToken(const AnnotatedToken &Tok) {
30 const AnnotatedToken *PrevToken = Tok.Parent;
31 while (PrevToken != NULL && PrevToken->is(tok::comment))
32 PrevToken = PrevToken->Parent;
33 return PrevToken;
34}
35
36// Returns the next token ignoring comments.
37static const AnnotatedToken *getNextToken(const AnnotatedToken &Tok) {
38 if (Tok.Children.empty())
39 return NULL;
40 const AnnotatedToken *NextToken = &Tok.Children[0];
41 while (NextToken->is(tok::comment)) {
42 if (NextToken->Children.empty())
43 return NULL;
44 NextToken = &NextToken->Children[0];
45 }
46 return NextToken;
47}
48
Daniel Jasper32d28ee2013-01-29 21:01:14 +000049/// \brief A parser that gathers additional information about tokens.
50///
51/// The \c TokenAnnotator tries to matches parenthesis and square brakets and
52/// store a parenthesis levels. It also tries to resolve matching "<" and ">"
53/// into template parameter lists.
54class AnnotatingParser {
55public:
Daniel Jasper01786732013-02-04 07:21:18 +000056 AnnotatingParser(SourceManager &SourceMgr, Lexer &Lex, AnnotatedLine &Line)
57 : SourceMgr(SourceMgr), Lex(Lex), Line(Line), CurrentToken(&Line.First),
58 KeywordVirtualFound(false), ColonIsObjCMethodExpr(false),
Daniel Jasper63d7ced2013-02-05 10:07:47 +000059 LongestObjCSelectorName(0), FirstObjCSelectorName(NULL),
Daniel Jasper01786732013-02-04 07:21:18 +000060 ColonIsForRangeExpr(false), IsExpression(false),
61 LookForFunctionName(Line.MustBeDeclaration), BindingStrength(1) {
Daniel Jasper32d28ee2013-01-29 21:01:14 +000062 }
63
64 /// \brief A helper class to manage AnnotatingParser::ColonIsObjCMethodExpr.
65 struct ObjCSelectorRAII {
66 AnnotatingParser &P;
67 bool ColonWasObjCMethodExpr;
68
69 ObjCSelectorRAII(AnnotatingParser &P)
70 : P(P), ColonWasObjCMethodExpr(P.ColonIsObjCMethodExpr) {
71 }
72
73 ~ObjCSelectorRAII() { P.ColonIsObjCMethodExpr = ColonWasObjCMethodExpr; }
74
75 void markStart(AnnotatedToken &Left) {
76 P.ColonIsObjCMethodExpr = true;
Daniel Jasper63d7ced2013-02-05 10:07:47 +000077 P.LongestObjCSelectorName = 0;
78 P.FirstObjCSelectorName = NULL;
Daniel Jasper32d28ee2013-01-29 21:01:14 +000079 Left.Type = TT_ObjCMethodExpr;
80 }
81
82 void markEnd(AnnotatedToken &Right) { Right.Type = TT_ObjCMethodExpr; }
83 };
84
Daniel Jasper01786732013-02-04 07:21:18 +000085 struct ScopedBindingStrengthIncrease {
86 AnnotatingParser &P;
87 unsigned Increase;
88
89 ScopedBindingStrengthIncrease(AnnotatingParser &P, unsigned Increase)
90 : P(P), Increase(Increase) {
91 P.BindingStrength += Increase;
92 }
93
94 ~ScopedBindingStrengthIncrease() { P.BindingStrength -= Increase; }
95 };
96
Daniel Jasper32d28ee2013-01-29 21:01:14 +000097 bool parseAngle() {
98 if (CurrentToken == NULL)
99 return false;
Daniel Jasper01786732013-02-04 07:21:18 +0000100 ScopedBindingStrengthIncrease Increase(*this, 10);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000101 AnnotatedToken *Left = CurrentToken->Parent;
102 while (CurrentToken != NULL) {
103 if (CurrentToken->is(tok::greater)) {
104 Left->MatchingParen = CurrentToken;
105 CurrentToken->MatchingParen = Left;
106 CurrentToken->Type = TT_TemplateCloser;
107 next();
108 return true;
109 }
110 if (CurrentToken->is(tok::r_paren) || CurrentToken->is(tok::r_square) ||
111 CurrentToken->is(tok::r_brace))
112 return false;
113 if (CurrentToken->is(tok::pipepipe) || CurrentToken->is(tok::ampamp) ||
114 CurrentToken->is(tok::question) || CurrentToken->is(tok::colon))
115 return false;
116 if (CurrentToken->is(tok::comma))
117 ++Left->ParameterCount;
118 if (!consumeToken())
119 return false;
120 }
121 return false;
122 }
123
124 bool parseParens(bool LookForDecls = false) {
125 if (CurrentToken == NULL)
126 return false;
Daniel Jasper01786732013-02-04 07:21:18 +0000127 ScopedBindingStrengthIncrease Increase(*this, 1);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000128 bool StartsObjCMethodExpr = false;
129 AnnotatedToken *Left = CurrentToken->Parent;
130 if (CurrentToken->is(tok::caret)) {
131 // ^( starts a block.
132 Left->Type = TT_ObjCBlockLParen;
133 } else if (AnnotatedToken *MaybeSel = Left->Parent) {
134 // @selector( starts a selector.
135 if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Parent &&
136 MaybeSel->Parent->is(tok::at)) {
137 StartsObjCMethodExpr = true;
138 }
139 }
140
141 ObjCSelectorRAII objCSelector(*this);
142 if (StartsObjCMethodExpr)
143 objCSelector.markStart(*Left);
144
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 Jasper32d28ee2013-01-29 21:01:14 +0000166 objCSelector.markEnd(*CurrentToken);
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000167 if (FirstObjCSelectorName != NULL) {
168 FirstObjCSelectorName->LongestObjCSelectorName =
169 LongestObjCSelectorName;
170 }
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 Jasper01786732013-02-04 07:21:18 +0000189 ScopedBindingStrengthIncrease Increase(*this, 10);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000190
191 // A '[' could be an index subscript (after an indentifier or after
192 // ')' or ']'), or it could be the start of an Objective-C method
193 // expression.
194 AnnotatedToken *Left = CurrentToken->Parent;
195 bool StartsObjCMethodExpr =
196 !Left->Parent || Left->Parent->is(tok::colon) ||
197 Left->Parent->is(tok::l_square) || Left->Parent->is(tok::l_paren) ||
198 Left->Parent->is(tok::kw_return) || Left->Parent->is(tok::kw_throw) ||
199 getBinOpPrecedence(Left->Parent->FormatTok.Tok.getKind(), true, true) >
200 prec::Unknown;
201
202 ObjCSelectorRAII objCSelector(*this);
203 if (StartsObjCMethodExpr)
204 objCSelector.markStart(*Left);
205
206 while (CurrentToken != NULL) {
207 if (CurrentToken->is(tok::r_square)) {
208 if (!CurrentToken->Children.empty() &&
209 CurrentToken->Children[0].is(tok::l_paren)) {
210 // An ObjC method call can't be followed by an open parenthesis.
211 // FIXME: Do we incorrectly label ":" with this?
212 StartsObjCMethodExpr = false;
213 Left->Type = TT_Unknown;
214 }
Daniel Jasper01786732013-02-04 07:21:18 +0000215 if (StartsObjCMethodExpr) {
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000216 objCSelector.markEnd(*CurrentToken);
Daniel Jasper01786732013-02-04 07:21:18 +0000217 if (Left->Parent != NULL &&
218 (Left->Parent->is(tok::star) || Left->Parent->is(tok::amp)))
219 Left->Parent->Type = TT_BinaryOperator;
220 }
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000221 Left->MatchingParen = CurrentToken;
222 CurrentToken->MatchingParen = Left;
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000223 if (FirstObjCSelectorName != NULL)
224 FirstObjCSelectorName->LongestObjCSelectorName =
225 LongestObjCSelectorName;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000226 next();
227 return true;
228 }
229 if (CurrentToken->is(tok::r_paren) || CurrentToken->is(tok::r_brace))
230 return false;
231 if (CurrentToken->is(tok::comma))
232 ++Left->ParameterCount;
233 if (!consumeToken())
234 return false;
235 }
236 return false;
237 }
238
239 bool parseBrace() {
240 // Lines are fine to end with '{'.
241 if (CurrentToken == NULL)
242 return true;
Daniel Jasper01786732013-02-04 07:21:18 +0000243 ScopedBindingStrengthIncrease Increase(*this, 1);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000244 AnnotatedToken *Left = CurrentToken->Parent;
245 while (CurrentToken != NULL) {
246 if (CurrentToken->is(tok::r_brace)) {
247 Left->MatchingParen = CurrentToken;
248 CurrentToken->MatchingParen = Left;
249 next();
250 return true;
251 }
252 if (CurrentToken->is(tok::r_paren) || CurrentToken->is(tok::r_square))
253 return false;
Daniel Jasperf343cab2013-01-31 14:59:26 +0000254 if (CurrentToken->is(tok::comma))
255 ++Left->ParameterCount;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000256 if (!consumeToken())
257 return false;
258 }
259 return true;
260 }
261
262 bool parseConditional() {
263 while (CurrentToken != NULL) {
264 if (CurrentToken->is(tok::colon)) {
265 CurrentToken->Type = TT_ConditionalExpr;
266 next();
267 return true;
268 }
269 if (!consumeToken())
270 return false;
271 }
272 return false;
273 }
274
275 bool parseTemplateDeclaration() {
276 if (CurrentToken != NULL && CurrentToken->is(tok::less)) {
277 CurrentToken->Type = TT_TemplateOpener;
278 next();
279 if (!parseAngle())
280 return false;
281 CurrentToken->Parent->ClosesTemplateDeclaration = true;
282 return true;
283 }
284 return false;
285 }
286
287 bool consumeToken() {
288 AnnotatedToken *Tok = CurrentToken;
289 next();
290 switch (Tok->FormatTok.Tok.getKind()) {
291 case tok::plus:
292 case tok::minus:
293 // At the start of the line, +/- specific ObjectiveC method
294 // declarations.
295 if (Tok->Parent == NULL)
296 Tok->Type = TT_ObjCMethodSpecifier;
297 break;
298 case tok::colon:
299 // Colons from ?: are handled in parseConditional().
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000300 if (Tok->Parent->is(tok::r_paren)) {
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000301 Tok->Type = TT_CtorInitializerColon;
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000302 } else if (ColonIsObjCMethodExpr ||
303 Line.First.Type == TT_ObjCMethodSpecifier) {
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000304 Tok->Type = TT_ObjCMethodExpr;
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000305 Tok->Parent->Type = TT_ObjCSelectorName;
306 if (Tok->Parent->FormatTok.TokenLength > LongestObjCSelectorName)
307 LongestObjCSelectorName = Tok->Parent->FormatTok.TokenLength;
308 if (FirstObjCSelectorName == NULL)
309 FirstObjCSelectorName = Tok->Parent;
310 } else if (ColonIsForRangeExpr) {
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000311 Tok->Type = TT_RangeBasedForLoopColon;
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000312 }
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000313 break;
314 case tok::kw_if:
315 case tok::kw_while:
316 if (CurrentToken != NULL && CurrentToken->is(tok::l_paren)) {
317 next();
318 if (!parseParens(/*LookForDecls=*/ true))
319 return false;
320 }
321 break;
322 case tok::kw_for:
323 ColonIsForRangeExpr = true;
324 next();
325 if (!parseParens())
326 return false;
327 break;
328 case tok::l_paren:
329 if (!parseParens())
330 return false;
331 break;
332 case tok::l_square:
333 if (!parseSquare())
334 return false;
335 break;
336 case tok::l_brace:
337 if (!parseBrace())
338 return false;
339 break;
340 case tok::less:
341 if (parseAngle())
342 Tok->Type = TT_TemplateOpener;
343 else {
344 Tok->Type = TT_BinaryOperator;
345 CurrentToken = Tok;
346 next();
347 }
348 break;
349 case tok::r_paren:
350 case tok::r_square:
351 return false;
352 case tok::r_brace:
353 // Lines can start with '}'.
354 if (Tok->Parent != NULL)
355 return false;
356 break;
357 case tok::greater:
358 Tok->Type = TT_BinaryOperator;
359 break;
360 case tok::kw_operator:
361 if (CurrentToken != NULL && CurrentToken->is(tok::l_paren)) {
362 CurrentToken->Type = TT_OverloadedOperator;
363 next();
364 if (CurrentToken != NULL && CurrentToken->is(tok::r_paren)) {
365 CurrentToken->Type = TT_OverloadedOperator;
366 next();
367 }
368 } else {
369 while (CurrentToken != NULL && CurrentToken->isNot(tok::l_paren)) {
370 CurrentToken->Type = TT_OverloadedOperator;
371 next();
372 }
373 }
374 break;
375 case tok::question:
376 parseConditional();
377 break;
378 case tok::kw_template:
379 parseTemplateDeclaration();
380 break;
381 default:
382 break;
383 }
384 return true;
385 }
386
387 void parseIncludeDirective() {
388 next();
389 if (CurrentToken != NULL && CurrentToken->is(tok::less)) {
390 next();
391 while (CurrentToken != NULL) {
392 if (CurrentToken->isNot(tok::comment) ||
393 !CurrentToken->Children.empty())
394 CurrentToken->Type = TT_ImplicitStringLiteral;
395 next();
396 }
397 } else {
398 while (CurrentToken != NULL) {
399 next();
400 }
401 }
402 }
403
404 void parseWarningOrError() {
405 next();
406 // We still want to format the whitespace left of the first token of the
407 // warning or error.
408 next();
409 while (CurrentToken != NULL) {
410 CurrentToken->Type = TT_ImplicitStringLiteral;
411 next();
412 }
413 }
414
415 void parsePreprocessorDirective() {
416 next();
417 if (CurrentToken == NULL)
418 return;
419 // Hashes in the middle of a line can lead to any strange token
420 // sequence.
421 if (CurrentToken->FormatTok.Tok.getIdentifierInfo() == NULL)
422 return;
423 switch (CurrentToken->FormatTok.Tok.getIdentifierInfo()->getPPKeywordID()) {
424 case tok::pp_include:
425 case tok::pp_import:
426 parseIncludeDirective();
427 break;
428 case tok::pp_error:
429 case tok::pp_warning:
430 parseWarningOrError();
431 break;
432 default:
433 break;
434 }
Daniel Jasper5b7e7b02013-02-05 09:34:14 +0000435 while (CurrentToken != NULL)
436 next();
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000437 }
438
439 LineType parseLine() {
440 int PeriodsAndArrows = 0;
441 bool CanBeBuilderTypeStmt = true;
442 if (CurrentToken->is(tok::hash)) {
443 parsePreprocessorDirective();
444 return LT_PreprocessorDirective;
445 }
446 while (CurrentToken != NULL) {
447 if (CurrentToken->is(tok::kw_virtual))
448 KeywordVirtualFound = true;
449 if (CurrentToken->is(tok::period) || CurrentToken->is(tok::arrow))
450 ++PeriodsAndArrows;
451 if (getPrecedence(*CurrentToken) > prec::Assignment &&
452 CurrentToken->isNot(tok::less) && CurrentToken->isNot(tok::greater))
453 CanBeBuilderTypeStmt = false;
454 if (!consumeToken())
455 return LT_Invalid;
456 }
457 if (KeywordVirtualFound)
458 return LT_VirtualFunctionDecl;
459
460 // Assume a builder-type call if there are 2 or more "." and "->".
461 if (PeriodsAndArrows >= 2 && CanBeBuilderTypeStmt)
462 return LT_BuilderTypeCall;
463
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000464 if (Line.First.Type == TT_ObjCMethodSpecifier) {
465 if (FirstObjCSelectorName != NULL)
466 FirstObjCSelectorName->LongestObjCSelectorName =
467 LongestObjCSelectorName;
468 return LT_ObjCMethodDecl;
469 }
470
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000471 return LT_Other;
472 }
473
474 void next() {
Daniel Jasper01786732013-02-04 07:21:18 +0000475 if (CurrentToken != NULL) {
476 determineTokenType(*CurrentToken);
477 CurrentToken->BindingStrength = BindingStrength;
478 }
479
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000480 if (CurrentToken != NULL && !CurrentToken->Children.empty())
481 CurrentToken = &CurrentToken->Children[0];
482 else
483 CurrentToken = NULL;
484 }
485
486private:
Daniel Jasper01786732013-02-04 07:21:18 +0000487 SourceManager &SourceMgr;
488 Lexer &Lex;
489 AnnotatedLine &Line;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000490 AnnotatedToken *CurrentToken;
491 bool KeywordVirtualFound;
492 bool ColonIsObjCMethodExpr;
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000493 unsigned LongestObjCSelectorName;
494 AnnotatedToken *FirstObjCSelectorName;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000495 bool ColonIsForRangeExpr;
Daniel Jasper01786732013-02-04 07:21:18 +0000496 bool IsExpression;
497 bool LookForFunctionName;
498
499 unsigned BindingStrength;
500
501 void determineTokenType(AnnotatedToken &Current) {
502 if (getPrecedence(Current) == prec::Assignment) {
503 IsExpression = true;
504 AnnotatedToken *Previous = Current.Parent;
505 while (Previous != NULL) {
506 if (Previous->Type == TT_BinaryOperator &&
507 (Previous->is(tok::star) || Previous->is(tok::amp))) {
508 Previous->Type = TT_PointerOrReference;
509 }
510 Previous = Previous->Parent;
511 }
512 }
513 if (Current.is(tok::kw_return) || Current.is(tok::kw_throw) ||
514 (Current.is(tok::l_paren) && !Line.MustBeDeclaration &&
515 (Current.Parent == NULL || Current.Parent->isNot(tok::kw_for))))
516 IsExpression = true;
517
518 if (Current.Type == TT_Unknown) {
519 if (LookForFunctionName && Current.is(tok::l_paren)) {
520 findFunctionName(&Current);
521 LookForFunctionName = false;
522 } else if (Current.is(tok::star) || Current.is(tok::amp)) {
523 Current.Type = determineStarAmpUsage(Current, IsExpression);
524 } else if (Current.is(tok::minus) || Current.is(tok::plus) ||
525 Current.is(tok::caret)) {
526 Current.Type = determinePlusMinusCaretUsage(Current);
527 } else if (Current.is(tok::minusminus) || Current.is(tok::plusplus)) {
528 Current.Type = determineIncrementUsage(Current);
529 } else if (Current.is(tok::exclaim)) {
530 Current.Type = TT_UnaryOperator;
531 } else if (isBinaryOperator(Current)) {
532 Current.Type = TT_BinaryOperator;
533 } else if (Current.is(tok::comment)) {
534 std::string Data(Lexer::getSpelling(Current.FormatTok.Tok, SourceMgr,
535 Lex.getLangOpts()));
536 if (StringRef(Data).startswith("//"))
537 Current.Type = TT_LineComment;
538 else
539 Current.Type = TT_BlockComment;
540 } else if (Current.is(tok::r_paren) &&
541 (Current.Parent->Type == TT_PointerOrReference ||
542 Current.Parent->Type == TT_TemplateCloser) &&
543 (Current.Children.empty() ||
544 (Current.Children[0].isNot(tok::equal) &&
545 Current.Children[0].isNot(tok::semi) &&
546 Current.Children[0].isNot(tok::l_brace)))) {
547 // FIXME: We need to get smarter and understand more cases of casts.
548 Current.Type = TT_CastRParen;
549 } else if (Current.is(tok::at) && Current.Children.size()) {
550 switch (Current.Children[0].FormatTok.Tok.getObjCKeywordID()) {
551 case tok::objc_interface:
552 case tok::objc_implementation:
553 case tok::objc_protocol:
554 Current.Type = TT_ObjCDecl;
555 break;
556 case tok::objc_property:
557 Current.Type = TT_ObjCProperty;
558 break;
559 default:
560 break;
561 }
562 }
563 }
564 }
565
566 /// \brief Starting from \p Current, this searches backwards for an
567 /// identifier which could be the start of a function name and marks it.
568 void findFunctionName(AnnotatedToken *Current) {
569 AnnotatedToken *Parent = Current->Parent;
570 while (Parent != NULL && Parent->Parent != NULL) {
571 if (Parent->is(tok::identifier) &&
572 (Parent->Parent->is(tok::identifier) ||
573 Parent->Parent->Type == TT_PointerOrReference ||
574 Parent->Parent->Type == TT_TemplateCloser)) {
575 Parent->Type = TT_StartOfName;
576 break;
577 }
578 Parent = Parent->Parent;
579 }
580 }
581
582 /// \brief Return the type of the given token assuming it is * or &.
583 TokenType
584 determineStarAmpUsage(const AnnotatedToken &Tok, bool IsExpression) {
585 const AnnotatedToken *PrevToken = getPreviousToken(Tok);
586 if (PrevToken == NULL)
587 return TT_UnaryOperator;
588
589 const AnnotatedToken *NextToken = getNextToken(Tok);
590 if (NextToken == NULL)
591 return TT_Unknown;
592
593 if (NextToken->is(tok::l_square))
594 return TT_PointerOrReference;
595
596 if (PrevToken->is(tok::l_paren) || PrevToken->is(tok::l_square) ||
597 PrevToken->is(tok::l_brace) || PrevToken->is(tok::comma) ||
598 PrevToken->is(tok::kw_return) || PrevToken->is(tok::colon) ||
599 PrevToken->Type == TT_BinaryOperator ||
600 PrevToken->Type == TT_UnaryOperator || PrevToken->Type == TT_CastRParen)
601 return TT_UnaryOperator;
602
603 if (PrevToken->FormatTok.Tok.isLiteral() || PrevToken->is(tok::r_paren) ||
604 PrevToken->is(tok::r_square) || NextToken->FormatTok.Tok.isLiteral() ||
605 NextToken->is(tok::plus) || NextToken->is(tok::minus) ||
606 NextToken->is(tok::plusplus) || NextToken->is(tok::minusminus) ||
607 NextToken->is(tok::tilde) || NextToken->is(tok::exclaim) ||
608 NextToken->is(tok::l_paren) || NextToken->is(tok::l_square) ||
609 NextToken->is(tok::kw_alignof) || NextToken->is(tok::kw_sizeof))
610 return TT_BinaryOperator;
611
612 if (NextToken->is(tok::comma) || NextToken->is(tok::r_paren) ||
613 NextToken->is(tok::greater))
614 return TT_PointerOrReference;
615
616 // It is very unlikely that we are going to find a pointer or reference type
617 // definition on the RHS of an assignment.
618 if (IsExpression)
619 return TT_BinaryOperator;
620
621 return TT_PointerOrReference;
622 }
623
624 TokenType determinePlusMinusCaretUsage(const AnnotatedToken &Tok) {
625 const AnnotatedToken *PrevToken = getPreviousToken(Tok);
626 if (PrevToken == NULL)
627 return TT_UnaryOperator;
628
629 // Use heuristics to recognize unary operators.
630 if (PrevToken->is(tok::equal) || PrevToken->is(tok::l_paren) ||
631 PrevToken->is(tok::comma) || PrevToken->is(tok::l_square) ||
632 PrevToken->is(tok::question) || PrevToken->is(tok::colon) ||
633 PrevToken->is(tok::kw_return) || PrevToken->is(tok::kw_case) ||
634 PrevToken->is(tok::at) || PrevToken->is(tok::l_brace))
635 return TT_UnaryOperator;
636
637 // There can't be to consecutive binary operators.
638 if (PrevToken->Type == TT_BinaryOperator)
639 return TT_UnaryOperator;
640
641 // Fall back to marking the token as binary operator.
642 return TT_BinaryOperator;
643 }
644
645 /// \brief Determine whether ++/-- are pre- or post-increments/-decrements.
646 TokenType determineIncrementUsage(const AnnotatedToken &Tok) {
647 const AnnotatedToken *PrevToken = getPreviousToken(Tok);
648 if (PrevToken == NULL)
649 return TT_UnaryOperator;
650 if (PrevToken->is(tok::r_paren) || PrevToken->is(tok::r_square) ||
651 PrevToken->is(tok::identifier))
652 return TT_TrailingUnaryOperator;
653
654 return TT_UnaryOperator;
655 }
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000656};
657
658void TokenAnnotator::annotate() {
Daniel Jasper01786732013-02-04 07:21:18 +0000659 AnnotatingParser Parser(SourceMgr, Lex, Line);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000660 Line.Type = Parser.parseLine();
661 if (Line.Type == LT_Invalid)
662 return;
663
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000664 if (Line.First.Type == TT_ObjCMethodSpecifier)
665 Line.Type = LT_ObjCMethodDecl;
666 else if (Line.First.Type == TT_ObjCDecl)
667 Line.Type = LT_ObjCDecl;
668 else if (Line.First.Type == TT_ObjCProperty)
669 Line.Type = LT_ObjCProperty;
670
671 Line.First.SpaceRequiredBefore = true;
672 Line.First.MustBreakBefore = Line.First.FormatTok.MustBreakBefore;
673 Line.First.CanBreakBefore = Line.First.MustBreakBefore;
674
675 Line.First.TotalLength = Line.First.FormatTok.TokenLength;
676 if (!Line.First.Children.empty())
Daniel Jasper01786732013-02-04 07:21:18 +0000677 calculateFormattingInformation(Line.First.Children[0]);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000678}
679
Daniel Jasper01786732013-02-04 07:21:18 +0000680void TokenAnnotator::calculateFormattingInformation(AnnotatedToken &Current) {
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000681 Current.SpaceRequiredBefore = spaceRequiredBefore(Current);
682
683 if (Current.FormatTok.MustBreakBefore) {
684 Current.MustBreakBefore = true;
Daniel Jasper2752ff32013-02-04 07:32:14 +0000685 } else if (Current.Type == TT_LineComment) {
686 Current.MustBreakBefore = Current.FormatTok.NewlinesBefore > 0;
687 } else if ((Current.Parent->is(tok::comment) &&
688 Current.FormatTok.NewlinesBefore > 0) ||
689 (Current.is(tok::string_literal) &&
690 Current.Parent->is(tok::string_literal))) {
691 Current.MustBreakBefore = true;
Daniel Jasperfa543ac2013-02-04 07:34:48 +0000692 } else if (Current.is(tok::lessless) && !Current.Children.empty() &&
693 Current.Parent->is(tok::string_literal) &&
694 Current.Children[0].is(tok::string_literal)) {
695 Current.MustBreakBefore = true;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000696 } else {
Daniel Jasper2752ff32013-02-04 07:32:14 +0000697 Current.MustBreakBefore = false;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000698 }
699 Current.CanBreakBefore = Current.MustBreakBefore || canBreakBefore(Current);
700 if (Current.MustBreakBefore)
701 Current.TotalLength = Current.Parent->TotalLength + Style.ColumnLimit;
702 else
703 Current.TotalLength =
704 Current.Parent->TotalLength + Current.FormatTok.TokenLength +
705 (Current.SpaceRequiredBefore ? 1 : 0);
706 // FIXME: Only calculate this if CanBreakBefore is true once static
707 // initializers etc. are sorted out.
Daniel Jasper01786732013-02-04 07:21:18 +0000708 // FIXME: Move magic numbers to a better place.
709 Current.SplitPenalty = 20 * Current.BindingStrength + splitPenalty(Current);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000710 if (!Current.Children.empty())
Daniel Jasper01786732013-02-04 07:21:18 +0000711 calculateFormattingInformation(Current.Children[0]);
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000712}
713
714unsigned TokenAnnotator::splitPenalty(const AnnotatedToken &Tok) {
715 const AnnotatedToken &Left = *Tok.Parent;
716 const AnnotatedToken &Right = Tok;
717
718 if (Left.is(tok::l_brace) && Right.isNot(tok::l_brace))
719 return 50;
720 if (Left.is(tok::equal) && Right.is(tok::l_brace))
721 return 150;
722 if (Left.is(tok::coloncolon))
723 return 500;
724
725 if (Left.Type == TT_RangeBasedForLoopColon)
726 return 5;
727
728 if (Right.is(tok::arrow) || Right.is(tok::period)) {
729 if (Left.is(tok::r_paren) && Line.Type == LT_BuilderTypeCall)
730 return 5; // Should be smaller than breaking at a nested comma.
731 return 150;
732 }
733
734 // In for-loops, prefer breaking at ',' and ';'.
735 if (Line.First.is(tok::kw_for) &&
736 (Left.isNot(tok::comma) && Left.isNot(tok::semi)))
737 return 20;
738
Daniel Jasper8159d2f2013-02-04 07:30:30 +0000739 if (Left.is(tok::semi))
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000740 return 0;
Daniel Jasper8159d2f2013-02-04 07:30:30 +0000741 if (Left.is(tok::comma))
742 return 1;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000743
744 // In Objective-C method expressions, prefer breaking before "param:" over
745 // breaking after it.
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000746 if (Right.Type == TT_ObjCSelectorName)
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000747 return 0;
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000748 if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000749 return 20;
750
Daniel Jasper01786732013-02-04 07:21:18 +0000751 if (Left.is(tok::l_paren) || Left.is(tok::l_square) ||
752 Left.Type == TT_TemplateOpener)
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000753 return 20;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000754
Daniel Jasper01786732013-02-04 07:21:18 +0000755 if (Right.is(tok::lessless))
756 return prec::Shift;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000757 if (Left.Type == TT_ConditionalExpr)
758 return prec::Assignment;
759 prec::Level Level = getPrecedence(Left);
760
761 if (Level != prec::Unknown)
762 return Level;
763
764 return 3;
765}
766
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000767bool TokenAnnotator::spaceRequiredBetween(const AnnotatedToken &Left,
768 const AnnotatedToken &Right) {
769 if (Right.is(tok::hashhash))
770 return Left.is(tok::hash);
771 if (Left.is(tok::hashhash) || Left.is(tok::hash))
772 return Right.is(tok::hash);
773 if (Right.is(tok::r_paren) || Right.is(tok::semi) || Right.is(tok::comma))
774 return false;
775 if (Right.is(tok::less) &&
776 (Left.is(tok::kw_template) ||
777 (Line.Type == LT_ObjCDecl && Style.ObjCSpaceBeforeProtocolList)))
778 return true;
779 if (Left.is(tok::arrow) || Right.is(tok::arrow))
780 return false;
781 if (Left.is(tok::exclaim) || Left.is(tok::tilde))
782 return false;
783 if (Left.is(tok::at) &&
784 (Right.is(tok::identifier) || Right.is(tok::string_literal) ||
785 Right.is(tok::char_constant) || Right.is(tok::numeric_constant) ||
786 Right.is(tok::l_paren) || Right.is(tok::l_brace) ||
787 Right.is(tok::kw_true) || Right.is(tok::kw_false)))
788 return false;
789 if (Left.is(tok::coloncolon))
790 return false;
791 if (Right.is(tok::coloncolon))
792 return Left.isNot(tok::identifier) && Left.isNot(tok::greater);
793 if (Left.is(tok::less) || Right.is(tok::greater) || Right.is(tok::less))
794 return false;
795 if (Right.is(tok::amp) || Right.is(tok::star))
796 return Left.FormatTok.Tok.isLiteral() ||
797 (Left.isNot(tok::star) && Left.isNot(tok::amp) &&
798 !Style.PointerAndReferenceBindToType);
799 if (Left.is(tok::amp) || Left.is(tok::star))
800 return Right.FormatTok.Tok.isLiteral() ||
801 Style.PointerAndReferenceBindToType;
802 if (Right.is(tok::star) && Left.is(tok::l_paren))
803 return false;
804 if (Left.is(tok::l_square) || Right.is(tok::r_square))
805 return false;
806 if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr)
807 return false;
808 if (Left.is(tok::period) || Right.is(tok::period))
809 return false;
810 if (Left.is(tok::colon))
811 return Left.Type != TT_ObjCMethodExpr;
812 if (Right.is(tok::colon))
813 return Right.Type != TT_ObjCMethodExpr;
814 if (Left.is(tok::l_paren))
815 return false;
816 if (Right.is(tok::l_paren)) {
817 return Line.Type == LT_ObjCDecl || Left.is(tok::kw_if) ||
818 Left.is(tok::kw_for) || Left.is(tok::kw_while) ||
819 Left.is(tok::kw_switch) || Left.is(tok::kw_return) ||
820 Left.is(tok::kw_catch) || Left.is(tok::kw_new) ||
821 Left.is(tok::kw_delete);
822 }
823 if (Left.is(tok::at) &&
824 Right.FormatTok.Tok.getObjCKeywordID() != tok::objc_not_keyword)
825 return false;
826 if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
827 return false;
828 return true;
829}
830
831bool TokenAnnotator::spaceRequiredBefore(const AnnotatedToken &Tok) {
832 if (Line.Type == LT_ObjCMethodDecl) {
833 if (Tok.is(tok::identifier) && !Tok.Children.empty() &&
834 Tok.Children[0].is(tok::colon) && Tok.Parent->is(tok::identifier))
835 return true;
836 if (Tok.is(tok::colon))
837 return false;
838 if (Tok.Parent->Type == TT_ObjCMethodSpecifier)
839 return true;
840 if (Tok.Parent->is(tok::r_paren) && Tok.is(tok::identifier))
841 // Don't space between ')' and <id>
842 return false;
843 if (Tok.Parent->is(tok::colon) && Tok.is(tok::l_paren))
844 // Don't space between ':' and '('
845 return false;
846 }
847 if (Line.Type == LT_ObjCProperty &&
848 (Tok.is(tok::equal) || Tok.Parent->is(tok::equal)))
849 return false;
850
851 if (Tok.Parent->is(tok::comma))
852 return true;
853 if (Tok.Type == TT_CtorInitializerColon || Tok.Type == TT_ObjCBlockLParen)
854 return true;
855 if (Tok.Type == TT_OverloadedOperator)
856 return Tok.is(tok::identifier) || Tok.is(tok::kw_new) ||
857 Tok.is(tok::kw_delete) || Tok.is(tok::kw_bool);
858 if (Tok.Parent->Type == TT_OverloadedOperator)
859 return false;
860 if (Tok.is(tok::colon))
861 return Line.First.isNot(tok::kw_case) && !Tok.Children.empty() &&
862 Tok.Type != TT_ObjCMethodExpr;
863 if (Tok.Parent->Type == TT_UnaryOperator || Tok.Parent->Type == TT_CastRParen)
864 return false;
865 if (Tok.Type == TT_UnaryOperator)
866 return Tok.Parent->isNot(tok::l_paren) &&
867 Tok.Parent->isNot(tok::l_square) && Tok.Parent->isNot(tok::at) &&
868 (Tok.Parent->isNot(tok::colon) ||
869 Tok.Parent->Type != TT_ObjCMethodExpr);
870 if (Tok.Parent->is(tok::greater) && Tok.is(tok::greater)) {
871 return Tok.Type == TT_TemplateCloser && Tok.Parent->Type ==
872 TT_TemplateCloser && Style.SplitTemplateClosingGreater;
873 }
874 if (Tok.Type == TT_BinaryOperator || Tok.Parent->Type == TT_BinaryOperator)
875 return true;
876 if (Tok.Parent->Type == TT_TemplateCloser && Tok.is(tok::l_paren))
877 return false;
878 if (Tok.is(tok::less) && Line.First.is(tok::hash))
879 return true;
880 if (Tok.Type == TT_TrailingUnaryOperator)
881 return false;
882 return spaceRequiredBetween(*Tok.Parent, Tok);
883}
884
885bool TokenAnnotator::canBreakBefore(const AnnotatedToken &Right) {
886 const AnnotatedToken &Left = *Right.Parent;
887 if (Line.Type == LT_ObjCMethodDecl) {
888 if (Right.is(tok::identifier) && !Right.Children.empty() &&
889 Right.Children[0].is(tok::colon) && Left.is(tok::identifier))
890 return true;
891 if (Right.is(tok::identifier) && Left.is(tok::l_paren) &&
892 Left.Parent->is(tok::colon))
893 // Don't break this identifier as ':' or identifier
894 // before it will break.
895 return false;
896 if (Right.is(tok::colon) && Left.is(tok::identifier) && Left.CanBreakBefore)
897 // Don't break at ':' if identifier before it can beak.
898 return false;
899 }
900 if (Right.Type == TT_StartOfName && Style.AllowReturnTypeOnItsOwnLine)
901 return true;
902 if (Right.is(tok::colon) && Right.Type == TT_ObjCMethodExpr)
903 return false;
904 if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
905 return true;
Daniel Jasper63d7ced2013-02-05 10:07:47 +0000906 if (Right.Type == TT_ObjCSelectorName)
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000907 return true;
908 if (Left.ClosesTemplateDeclaration)
909 return true;
910 if (Right.Type == TT_ConditionalExpr || Right.is(tok::question))
911 return true;
912 if (Left.Type == TT_RangeBasedForLoopColon)
913 return true;
914 if (Left.Type == TT_PointerOrReference || Left.Type == TT_TemplateCloser ||
915 Left.Type == TT_UnaryOperator || Left.Type == TT_ConditionalExpr ||
916 Left.is(tok::question))
917 return false;
918 if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl)
919 return false;
920
921 if (Right.Type == TT_LineComment)
922 // We rely on MustBreakBefore being set correctly here as we should not
923 // change the "binding" behavior of a comment.
924 return false;
925
926 // Allow breaking after a trailing 'const', e.g. after a method declaration,
927 // unless it is follow by ';', '{' or '='.
928 if (Left.is(tok::kw_const) && Left.Parent != NULL &&
929 Left.Parent->is(tok::r_paren))
930 return Right.isNot(tok::l_brace) && Right.isNot(tok::semi) &&
931 Right.isNot(tok::equal);
932
933 // We only break before r_brace if there was a corresponding break before
934 // the l_brace, which is tracked by BreakBeforeClosingBrace.
935 if (Right.is(tok::r_brace))
936 return false;
937
938 if (Right.is(tok::r_paren) || Right.is(tok::greater))
939 return false;
940 return (isBinaryOperator(Left) && Left.isNot(tok::lessless)) ||
941 Left.is(tok::comma) || Right.is(tok::lessless) ||
942 Right.is(tok::arrow) || Right.is(tok::period) ||
943 Right.is(tok::colon) || Left.is(tok::coloncolon) ||
944 Left.is(tok::semi) || Left.is(tok::l_brace) ||
945 (Left.is(tok::r_paren) && Left.Type != TT_CastRParen &&
946 Right.is(tok::identifier)) ||
947 (Left.is(tok::l_paren) && !Right.is(tok::r_paren)) ||
948 (Left.is(tok::l_square) && !Right.is(tok::r_square));
949}
950
951} // namespace format
952} // namespace clang