blob: ecc9b4e468a44bf8df90537f9423d3bd8cadaf1a [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
23/// \brief Returns if a token is an Objective-C selector name.
24///
25/// For example, "bar" is a selector name in [foo bar:(4 + 5)].
26static bool isObjCSelectorName(const AnnotatedToken &Tok) {
27 return Tok.is(tok::identifier) && !Tok.Children.empty() &&
28 Tok.Children[0].is(tok::colon) &&
29 Tok.Children[0].Type == TT_ObjCMethodExpr;
30}
31
32static bool isBinaryOperator(const AnnotatedToken &Tok) {
33 // Comma is a binary operator, but does not behave as such wrt. formatting.
34 return getPrecedence(Tok) > prec::Comma;
35}
36
37/// \brief A parser that gathers additional information about tokens.
38///
39/// The \c TokenAnnotator tries to matches parenthesis and square brakets and
40/// store a parenthesis levels. It also tries to resolve matching "<" and ">"
41/// into template parameter lists.
42class AnnotatingParser {
43public:
44 AnnotatingParser(AnnotatedToken &RootToken)
45 : CurrentToken(&RootToken), KeywordVirtualFound(false),
46 ColonIsObjCMethodExpr(false), ColonIsForRangeExpr(false) {
47 }
48
49 /// \brief A helper class to manage AnnotatingParser::ColonIsObjCMethodExpr.
50 struct ObjCSelectorRAII {
51 AnnotatingParser &P;
52 bool ColonWasObjCMethodExpr;
53
54 ObjCSelectorRAII(AnnotatingParser &P)
55 : P(P), ColonWasObjCMethodExpr(P.ColonIsObjCMethodExpr) {
56 }
57
58 ~ObjCSelectorRAII() { P.ColonIsObjCMethodExpr = ColonWasObjCMethodExpr; }
59
60 void markStart(AnnotatedToken &Left) {
61 P.ColonIsObjCMethodExpr = true;
62 Left.Type = TT_ObjCMethodExpr;
63 }
64
65 void markEnd(AnnotatedToken &Right) { Right.Type = TT_ObjCMethodExpr; }
66 };
67
68 bool parseAngle() {
69 if (CurrentToken == NULL)
70 return false;
71 AnnotatedToken *Left = CurrentToken->Parent;
72 while (CurrentToken != NULL) {
73 if (CurrentToken->is(tok::greater)) {
74 Left->MatchingParen = CurrentToken;
75 CurrentToken->MatchingParen = Left;
76 CurrentToken->Type = TT_TemplateCloser;
77 next();
78 return true;
79 }
80 if (CurrentToken->is(tok::r_paren) || CurrentToken->is(tok::r_square) ||
81 CurrentToken->is(tok::r_brace))
82 return false;
83 if (CurrentToken->is(tok::pipepipe) || CurrentToken->is(tok::ampamp) ||
84 CurrentToken->is(tok::question) || CurrentToken->is(tok::colon))
85 return false;
86 if (CurrentToken->is(tok::comma))
87 ++Left->ParameterCount;
88 if (!consumeToken())
89 return false;
90 }
91 return false;
92 }
93
94 bool parseParens(bool LookForDecls = false) {
95 if (CurrentToken == NULL)
96 return false;
97 bool StartsObjCMethodExpr = false;
98 AnnotatedToken *Left = CurrentToken->Parent;
99 if (CurrentToken->is(tok::caret)) {
100 // ^( starts a block.
101 Left->Type = TT_ObjCBlockLParen;
102 } else if (AnnotatedToken *MaybeSel = Left->Parent) {
103 // @selector( starts a selector.
104 if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Parent &&
105 MaybeSel->Parent->is(tok::at)) {
106 StartsObjCMethodExpr = true;
107 }
108 }
109
110 ObjCSelectorRAII objCSelector(*this);
111 if (StartsObjCMethodExpr)
112 objCSelector.markStart(*Left);
113
114 while (CurrentToken != NULL) {
115 // LookForDecls is set when "if (" has been seen. Check for
116 // 'identifier' '*' 'identifier' followed by not '=' -- this
117 // '*' has to be a binary operator but determineStarAmpUsage() will
118 // categorize it as an unary operator, so set the right type here.
119 if (LookForDecls && !CurrentToken->Children.empty()) {
120 AnnotatedToken &Prev = *CurrentToken->Parent;
121 AnnotatedToken &Next = CurrentToken->Children[0];
122 if (Prev.Parent->is(tok::identifier) &&
123 (Prev.is(tok::star) || Prev.is(tok::amp)) &&
124 CurrentToken->is(tok::identifier) && Next.isNot(tok::equal)) {
125 Prev.Type = TT_BinaryOperator;
126 LookForDecls = false;
127 }
128 }
129
130 if (CurrentToken->is(tok::r_paren)) {
131 Left->MatchingParen = CurrentToken;
132 CurrentToken->MatchingParen = Left;
133
134 if (StartsObjCMethodExpr)
135 objCSelector.markEnd(*CurrentToken);
136
137 next();
138 return true;
139 }
140 if (CurrentToken->is(tok::r_square) || CurrentToken->is(tok::r_brace))
141 return false;
142 if (CurrentToken->is(tok::comma))
143 ++Left->ParameterCount;
144 if (!consumeToken())
145 return false;
146 }
147 return false;
148 }
149
150 bool parseSquare() {
151 if (!CurrentToken)
152 return false;
153
154 // A '[' could be an index subscript (after an indentifier or after
155 // ')' or ']'), or it could be the start of an Objective-C method
156 // expression.
157 AnnotatedToken *Left = CurrentToken->Parent;
158 bool StartsObjCMethodExpr =
159 !Left->Parent || Left->Parent->is(tok::colon) ||
160 Left->Parent->is(tok::l_square) || Left->Parent->is(tok::l_paren) ||
161 Left->Parent->is(tok::kw_return) || Left->Parent->is(tok::kw_throw) ||
162 getBinOpPrecedence(Left->Parent->FormatTok.Tok.getKind(), true, true) >
163 prec::Unknown;
164
165 ObjCSelectorRAII objCSelector(*this);
166 if (StartsObjCMethodExpr)
167 objCSelector.markStart(*Left);
168
169 while (CurrentToken != NULL) {
170 if (CurrentToken->is(tok::r_square)) {
171 if (!CurrentToken->Children.empty() &&
172 CurrentToken->Children[0].is(tok::l_paren)) {
173 // An ObjC method call can't be followed by an open parenthesis.
174 // FIXME: Do we incorrectly label ":" with this?
175 StartsObjCMethodExpr = false;
176 Left->Type = TT_Unknown;
177 }
178 if (StartsObjCMethodExpr)
179 objCSelector.markEnd(*CurrentToken);
180 Left->MatchingParen = CurrentToken;
181 CurrentToken->MatchingParen = Left;
182 next();
183 return true;
184 }
185 if (CurrentToken->is(tok::r_paren) || CurrentToken->is(tok::r_brace))
186 return false;
187 if (CurrentToken->is(tok::comma))
188 ++Left->ParameterCount;
189 if (!consumeToken())
190 return false;
191 }
192 return false;
193 }
194
195 bool parseBrace() {
196 // Lines are fine to end with '{'.
197 if (CurrentToken == NULL)
198 return true;
199 AnnotatedToken *Left = CurrentToken->Parent;
200 while (CurrentToken != NULL) {
201 if (CurrentToken->is(tok::r_brace)) {
202 Left->MatchingParen = CurrentToken;
203 CurrentToken->MatchingParen = Left;
204 next();
205 return true;
206 }
207 if (CurrentToken->is(tok::r_paren) || CurrentToken->is(tok::r_square))
208 return false;
Daniel Jasperf343cab2013-01-31 14:59:26 +0000209 if (CurrentToken->is(tok::comma))
210 ++Left->ParameterCount;
Daniel Jasper32d28ee2013-01-29 21:01:14 +0000211 if (!consumeToken())
212 return false;
213 }
214 return true;
215 }
216
217 bool parseConditional() {
218 while (CurrentToken != NULL) {
219 if (CurrentToken->is(tok::colon)) {
220 CurrentToken->Type = TT_ConditionalExpr;
221 next();
222 return true;
223 }
224 if (!consumeToken())
225 return false;
226 }
227 return false;
228 }
229
230 bool parseTemplateDeclaration() {
231 if (CurrentToken != NULL && CurrentToken->is(tok::less)) {
232 CurrentToken->Type = TT_TemplateOpener;
233 next();
234 if (!parseAngle())
235 return false;
236 CurrentToken->Parent->ClosesTemplateDeclaration = true;
237 return true;
238 }
239 return false;
240 }
241
242 bool consumeToken() {
243 AnnotatedToken *Tok = CurrentToken;
244 next();
245 switch (Tok->FormatTok.Tok.getKind()) {
246 case tok::plus:
247 case tok::minus:
248 // At the start of the line, +/- specific ObjectiveC method
249 // declarations.
250 if (Tok->Parent == NULL)
251 Tok->Type = TT_ObjCMethodSpecifier;
252 break;
253 case tok::colon:
254 // Colons from ?: are handled in parseConditional().
255 if (Tok->Parent->is(tok::r_paren))
256 Tok->Type = TT_CtorInitializerColon;
257 else if (ColonIsObjCMethodExpr)
258 Tok->Type = TT_ObjCMethodExpr;
259 else if (ColonIsForRangeExpr)
260 Tok->Type = TT_RangeBasedForLoopColon;
261 break;
262 case tok::kw_if:
263 case tok::kw_while:
264 if (CurrentToken != NULL && CurrentToken->is(tok::l_paren)) {
265 next();
266 if (!parseParens(/*LookForDecls=*/ true))
267 return false;
268 }
269 break;
270 case tok::kw_for:
271 ColonIsForRangeExpr = true;
272 next();
273 if (!parseParens())
274 return false;
275 break;
276 case tok::l_paren:
277 if (!parseParens())
278 return false;
279 break;
280 case tok::l_square:
281 if (!parseSquare())
282 return false;
283 break;
284 case tok::l_brace:
285 if (!parseBrace())
286 return false;
287 break;
288 case tok::less:
289 if (parseAngle())
290 Tok->Type = TT_TemplateOpener;
291 else {
292 Tok->Type = TT_BinaryOperator;
293 CurrentToken = Tok;
294 next();
295 }
296 break;
297 case tok::r_paren:
298 case tok::r_square:
299 return false;
300 case tok::r_brace:
301 // Lines can start with '}'.
302 if (Tok->Parent != NULL)
303 return false;
304 break;
305 case tok::greater:
306 Tok->Type = TT_BinaryOperator;
307 break;
308 case tok::kw_operator:
309 if (CurrentToken != NULL && CurrentToken->is(tok::l_paren)) {
310 CurrentToken->Type = TT_OverloadedOperator;
311 next();
312 if (CurrentToken != NULL && CurrentToken->is(tok::r_paren)) {
313 CurrentToken->Type = TT_OverloadedOperator;
314 next();
315 }
316 } else {
317 while (CurrentToken != NULL && CurrentToken->isNot(tok::l_paren)) {
318 CurrentToken->Type = TT_OverloadedOperator;
319 next();
320 }
321 }
322 break;
323 case tok::question:
324 parseConditional();
325 break;
326 case tok::kw_template:
327 parseTemplateDeclaration();
328 break;
329 default:
330 break;
331 }
332 return true;
333 }
334
335 void parseIncludeDirective() {
336 next();
337 if (CurrentToken != NULL && CurrentToken->is(tok::less)) {
338 next();
339 while (CurrentToken != NULL) {
340 if (CurrentToken->isNot(tok::comment) ||
341 !CurrentToken->Children.empty())
342 CurrentToken->Type = TT_ImplicitStringLiteral;
343 next();
344 }
345 } else {
346 while (CurrentToken != NULL) {
347 next();
348 }
349 }
350 }
351
352 void parseWarningOrError() {
353 next();
354 // We still want to format the whitespace left of the first token of the
355 // warning or error.
356 next();
357 while (CurrentToken != NULL) {
358 CurrentToken->Type = TT_ImplicitStringLiteral;
359 next();
360 }
361 }
362
363 void parsePreprocessorDirective() {
364 next();
365 if (CurrentToken == NULL)
366 return;
367 // Hashes in the middle of a line can lead to any strange token
368 // sequence.
369 if (CurrentToken->FormatTok.Tok.getIdentifierInfo() == NULL)
370 return;
371 switch (CurrentToken->FormatTok.Tok.getIdentifierInfo()->getPPKeywordID()) {
372 case tok::pp_include:
373 case tok::pp_import:
374 parseIncludeDirective();
375 break;
376 case tok::pp_error:
377 case tok::pp_warning:
378 parseWarningOrError();
379 break;
380 default:
381 break;
382 }
383 }
384
385 LineType parseLine() {
386 int PeriodsAndArrows = 0;
387 bool CanBeBuilderTypeStmt = true;
388 if (CurrentToken->is(tok::hash)) {
389 parsePreprocessorDirective();
390 return LT_PreprocessorDirective;
391 }
392 while (CurrentToken != NULL) {
393 if (CurrentToken->is(tok::kw_virtual))
394 KeywordVirtualFound = true;
395 if (CurrentToken->is(tok::period) || CurrentToken->is(tok::arrow))
396 ++PeriodsAndArrows;
397 if (getPrecedence(*CurrentToken) > prec::Assignment &&
398 CurrentToken->isNot(tok::less) && CurrentToken->isNot(tok::greater))
399 CanBeBuilderTypeStmt = false;
400 if (!consumeToken())
401 return LT_Invalid;
402 }
403 if (KeywordVirtualFound)
404 return LT_VirtualFunctionDecl;
405
406 // Assume a builder-type call if there are 2 or more "." and "->".
407 if (PeriodsAndArrows >= 2 && CanBeBuilderTypeStmt)
408 return LT_BuilderTypeCall;
409
410 return LT_Other;
411 }
412
413 void next() {
414 if (CurrentToken != NULL && !CurrentToken->Children.empty())
415 CurrentToken = &CurrentToken->Children[0];
416 else
417 CurrentToken = NULL;
418 }
419
420private:
421 AnnotatedToken *CurrentToken;
422 bool KeywordVirtualFound;
423 bool ColonIsObjCMethodExpr;
424 bool ColonIsForRangeExpr;
425};
426
427void TokenAnnotator::annotate() {
428 AnnotatingParser Parser(Line.First);
429 Line.Type = Parser.parseLine();
430 if (Line.Type == LT_Invalid)
431 return;
432
433 bool LookForFunctionName = Line.MustBeDeclaration;
434 determineTokenTypes(Line.First, /*IsExpression=*/ false, LookForFunctionName);
435
436 if (Line.First.Type == TT_ObjCMethodSpecifier)
437 Line.Type = LT_ObjCMethodDecl;
438 else if (Line.First.Type == TT_ObjCDecl)
439 Line.Type = LT_ObjCDecl;
440 else if (Line.First.Type == TT_ObjCProperty)
441 Line.Type = LT_ObjCProperty;
442
443 Line.First.SpaceRequiredBefore = true;
444 Line.First.MustBreakBefore = Line.First.FormatTok.MustBreakBefore;
445 Line.First.CanBreakBefore = Line.First.MustBreakBefore;
446
447 Line.First.TotalLength = Line.First.FormatTok.TokenLength;
448 if (!Line.First.Children.empty())
449 calculateExtraInformation(Line.First.Children[0]);
450}
451
452void TokenAnnotator::calculateExtraInformation(AnnotatedToken &Current) {
453 Current.SpaceRequiredBefore = spaceRequiredBefore(Current);
454
455 if (Current.FormatTok.MustBreakBefore) {
456 Current.MustBreakBefore = true;
457 } else {
458 if (Current.Type == TT_LineComment) {
459 Current.MustBreakBefore = Current.FormatTok.NewlinesBefore > 0;
460 } else if ((Current.Parent->is(tok::comment) &&
461 Current.FormatTok.NewlinesBefore > 0) ||
462 (Current.is(tok::string_literal) &&
463 Current.Parent->is(tok::string_literal))) {
464 Current.MustBreakBefore = true;
465 } else {
466 Current.MustBreakBefore = false;
467 }
468 }
469 Current.CanBreakBefore = Current.MustBreakBefore || canBreakBefore(Current);
470 if (Current.MustBreakBefore)
471 Current.TotalLength = Current.Parent->TotalLength + Style.ColumnLimit;
472 else
473 Current.TotalLength =
474 Current.Parent->TotalLength + Current.FormatTok.TokenLength +
475 (Current.SpaceRequiredBefore ? 1 : 0);
476 // FIXME: Only calculate this if CanBreakBefore is true once static
477 // initializers etc. are sorted out.
478 Current.SplitPenalty = splitPenalty(Current);
479 if (!Current.Children.empty())
480 calculateExtraInformation(Current.Children[0]);
481}
482
483unsigned TokenAnnotator::splitPenalty(const AnnotatedToken &Tok) {
484 const AnnotatedToken &Left = *Tok.Parent;
485 const AnnotatedToken &Right = Tok;
486
487 if (Left.is(tok::l_brace) && Right.isNot(tok::l_brace))
488 return 50;
489 if (Left.is(tok::equal) && Right.is(tok::l_brace))
490 return 150;
491 if (Left.is(tok::coloncolon))
492 return 500;
493
494 if (Left.Type == TT_RangeBasedForLoopColon)
495 return 5;
496
497 if (Right.is(tok::arrow) || Right.is(tok::period)) {
498 if (Left.is(tok::r_paren) && Line.Type == LT_BuilderTypeCall)
499 return 5; // Should be smaller than breaking at a nested comma.
500 return 150;
501 }
502
503 // In for-loops, prefer breaking at ',' and ';'.
504 if (Line.First.is(tok::kw_for) &&
505 (Left.isNot(tok::comma) && Left.isNot(tok::semi)))
506 return 20;
507
508 if (Left.is(tok::semi) || Left.is(tok::comma))
509 return 0;
510
511 // In Objective-C method expressions, prefer breaking before "param:" over
512 // breaking after it.
513 if (isObjCSelectorName(Right))
514 return 0;
515 if (Right.is(tok::colon) && Right.Type == TT_ObjCMethodExpr)
516 return 20;
517
518 if (Left.is(tok::l_paren))
519 return 20;
520 // FIXME: The penalty for a trailing "<" or "[" being higher than the
521 // penalty for a trainling "(" is a temporary workaround until we can
522 // properly avoid breaking in array subscripts or template parameters.
523 if (Left.is(tok::l_square) || Left.Type == TT_TemplateOpener)
524 return 50;
525
526 if (Left.Type == TT_ConditionalExpr)
527 return prec::Assignment;
528 prec::Level Level = getPrecedence(Left);
529
530 if (Level != prec::Unknown)
531 return Level;
532
533 return 3;
534}
535
536void TokenAnnotator::determineTokenTypes(
537 AnnotatedToken &Current, bool IsExpression, bool LookForFunctionName) {
538 if (getPrecedence(Current) == prec::Assignment) {
539 IsExpression = true;
540 AnnotatedToken *Previous = Current.Parent;
541 while (Previous != NULL) {
542 if (Previous->Type == TT_BinaryOperator &&
543 (Previous->is(tok::star) || Previous->is(tok::amp))) {
544 Previous->Type = TT_PointerOrReference;
545 }
546 Previous = Previous->Parent;
547 }
548 }
549 if (Current.is(tok::kw_return) || Current.is(tok::kw_throw) ||
550 (Current.is(tok::l_paren) && !Line.MustBeDeclaration &&
551 (Current.Parent == NULL || Current.Parent->isNot(tok::kw_for))))
552 IsExpression = true;
553
554 if (Current.Type == TT_Unknown) {
555 if (LookForFunctionName && Current.is(tok::l_paren)) {
556 findFunctionName(&Current);
557 LookForFunctionName = false;
558 } else if (Current.is(tok::star) || Current.is(tok::amp)) {
559 Current.Type = determineStarAmpUsage(Current, IsExpression);
560 } else if (Current.is(tok::minus) || Current.is(tok::plus) ||
561 Current.is(tok::caret)) {
562 Current.Type = determinePlusMinusCaretUsage(Current);
563 } else if (Current.is(tok::minusminus) || Current.is(tok::plusplus)) {
564 Current.Type = determineIncrementUsage(Current);
565 } else if (Current.is(tok::exclaim)) {
566 Current.Type = TT_UnaryOperator;
567 } else if (isBinaryOperator(Current)) {
568 Current.Type = TT_BinaryOperator;
569 } else if (Current.is(tok::comment)) {
570 std::string Data(Lexer::getSpelling(Current.FormatTok.Tok, SourceMgr,
571 Lex.getLangOpts()));
572 if (StringRef(Data).startswith("//"))
573 Current.Type = TT_LineComment;
574 else
575 Current.Type = TT_BlockComment;
576 } else if (Current.is(tok::r_paren) &&
577 (Current.Parent->Type == TT_PointerOrReference ||
578 Current.Parent->Type == TT_TemplateCloser) &&
579 (Current.Children.empty() ||
580 (Current.Children[0].isNot(tok::equal) &&
581 Current.Children[0].isNot(tok::semi) &&
582 Current.Children[0].isNot(tok::l_brace)))) {
583 // FIXME: We need to get smarter and understand more cases of casts.
584 Current.Type = TT_CastRParen;
585 } else if (Current.is(tok::at) && Current.Children.size()) {
586 switch (Current.Children[0].FormatTok.Tok.getObjCKeywordID()) {
587 case tok::objc_interface:
588 case tok::objc_implementation:
589 case tok::objc_protocol:
590 Current.Type = TT_ObjCDecl;
591 break;
592 case tok::objc_property:
593 Current.Type = TT_ObjCProperty;
594 break;
595 default:
596 break;
597 }
598 }
599 }
600
601 if (!Current.Children.empty())
602 determineTokenTypes(Current.Children[0], IsExpression, LookForFunctionName);
603}
604
605void TokenAnnotator::findFunctionName(AnnotatedToken *Current) {
606 AnnotatedToken *Parent = Current->Parent;
607 while (Parent != NULL && Parent->Parent != NULL) {
608 if (Parent->is(tok::identifier) &&
609 (Parent->Parent->is(tok::identifier) || Parent->Parent->Type ==
610 TT_PointerOrReference || Parent->Parent->Type == TT_TemplateCloser)) {
611 Parent->Type = TT_StartOfName;
612 break;
613 }
614 Parent = Parent->Parent;
615 }
616}
617
618TokenType TokenAnnotator::determineStarAmpUsage(const AnnotatedToken &Tok,
619 bool IsExpression) {
620 const AnnotatedToken *PrevToken = getPreviousToken(Tok);
621 if (PrevToken == NULL)
622 return TT_UnaryOperator;
623
624 const AnnotatedToken *NextToken = getNextToken(Tok);
625 if (NextToken == NULL)
626 return TT_Unknown;
627
628 if (NextToken->is(tok::l_square) && NextToken->Type != TT_ObjCMethodExpr)
629 return TT_PointerOrReference;
630
631 if (PrevToken->is(tok::l_paren) || PrevToken->is(tok::l_square) ||
632 PrevToken->is(tok::l_brace) || PrevToken->is(tok::comma) ||
633 PrevToken->is(tok::kw_return) || PrevToken->is(tok::colon) ||
634 PrevToken->Type == TT_BinaryOperator ||
635 PrevToken->Type == TT_UnaryOperator || PrevToken->Type == TT_CastRParen)
636 return TT_UnaryOperator;
637
638 if (PrevToken->FormatTok.Tok.isLiteral() || PrevToken->is(tok::r_paren) ||
639 PrevToken->is(tok::r_square) || NextToken->FormatTok.Tok.isLiteral() ||
640 NextToken->is(tok::plus) || NextToken->is(tok::minus) ||
641 NextToken->is(tok::plusplus) || NextToken->is(tok::minusminus) ||
642 NextToken->is(tok::tilde) || NextToken->is(tok::exclaim) ||
643 NextToken->is(tok::l_paren) || NextToken->is(tok::l_square) ||
644 NextToken->is(tok::kw_alignof) || NextToken->is(tok::kw_sizeof))
645 return TT_BinaryOperator;
646
647 if (NextToken->is(tok::comma) || NextToken->is(tok::r_paren) ||
648 NextToken->is(tok::greater))
649 return TT_PointerOrReference;
650
651 // 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
659TokenType
660TokenAnnotator::determinePlusMinusCaretUsage(const AnnotatedToken &Tok) {
661 const AnnotatedToken *PrevToken = getPreviousToken(Tok);
662 if (PrevToken == NULL)
663 return TT_UnaryOperator;
664
665 // Use heuristics to recognize unary operators.
666 if (PrevToken->is(tok::equal) || PrevToken->is(tok::l_paren) ||
667 PrevToken->is(tok::comma) || PrevToken->is(tok::l_square) ||
668 PrevToken->is(tok::question) || PrevToken->is(tok::colon) ||
669 PrevToken->is(tok::kw_return) || PrevToken->is(tok::kw_case) ||
670 PrevToken->is(tok::at) || PrevToken->is(tok::l_brace))
671 return TT_UnaryOperator;
672
673 // There can't be to consecutive binary operators.
674 if (PrevToken->Type == TT_BinaryOperator)
675 return TT_UnaryOperator;
676
677 // Fall back to marking the token as binary operator.
678 return TT_BinaryOperator;
679}
680
681TokenType TokenAnnotator::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}
691
692bool TokenAnnotator::spaceRequiredBetween(const AnnotatedToken &Left,
693 const AnnotatedToken &Right) {
694 if (Right.is(tok::hashhash))
695 return Left.is(tok::hash);
696 if (Left.is(tok::hashhash) || Left.is(tok::hash))
697 return Right.is(tok::hash);
698 if (Right.is(tok::r_paren) || Right.is(tok::semi) || Right.is(tok::comma))
699 return false;
700 if (Right.is(tok::less) &&
701 (Left.is(tok::kw_template) ||
702 (Line.Type == LT_ObjCDecl && Style.ObjCSpaceBeforeProtocolList)))
703 return true;
704 if (Left.is(tok::arrow) || Right.is(tok::arrow))
705 return false;
706 if (Left.is(tok::exclaim) || Left.is(tok::tilde))
707 return false;
708 if (Left.is(tok::at) &&
709 (Right.is(tok::identifier) || Right.is(tok::string_literal) ||
710 Right.is(tok::char_constant) || Right.is(tok::numeric_constant) ||
711 Right.is(tok::l_paren) || Right.is(tok::l_brace) ||
712 Right.is(tok::kw_true) || Right.is(tok::kw_false)))
713 return false;
714 if (Left.is(tok::coloncolon))
715 return false;
716 if (Right.is(tok::coloncolon))
717 return Left.isNot(tok::identifier) && Left.isNot(tok::greater);
718 if (Left.is(tok::less) || Right.is(tok::greater) || Right.is(tok::less))
719 return false;
720 if (Right.is(tok::amp) || Right.is(tok::star))
721 return Left.FormatTok.Tok.isLiteral() ||
722 (Left.isNot(tok::star) && Left.isNot(tok::amp) &&
723 !Style.PointerAndReferenceBindToType);
724 if (Left.is(tok::amp) || Left.is(tok::star))
725 return Right.FormatTok.Tok.isLiteral() ||
726 Style.PointerAndReferenceBindToType;
727 if (Right.is(tok::star) && Left.is(tok::l_paren))
728 return false;
729 if (Left.is(tok::l_square) || Right.is(tok::r_square))
730 return false;
731 if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr)
732 return false;
733 if (Left.is(tok::period) || Right.is(tok::period))
734 return false;
735 if (Left.is(tok::colon))
736 return Left.Type != TT_ObjCMethodExpr;
737 if (Right.is(tok::colon))
738 return Right.Type != TT_ObjCMethodExpr;
739 if (Left.is(tok::l_paren))
740 return false;
741 if (Right.is(tok::l_paren)) {
742 return Line.Type == LT_ObjCDecl || Left.is(tok::kw_if) ||
743 Left.is(tok::kw_for) || Left.is(tok::kw_while) ||
744 Left.is(tok::kw_switch) || Left.is(tok::kw_return) ||
745 Left.is(tok::kw_catch) || Left.is(tok::kw_new) ||
746 Left.is(tok::kw_delete);
747 }
748 if (Left.is(tok::at) &&
749 Right.FormatTok.Tok.getObjCKeywordID() != tok::objc_not_keyword)
750 return false;
751 if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
752 return false;
753 return true;
754}
755
756bool TokenAnnotator::spaceRequiredBefore(const AnnotatedToken &Tok) {
757 if (Line.Type == LT_ObjCMethodDecl) {
758 if (Tok.is(tok::identifier) && !Tok.Children.empty() &&
759 Tok.Children[0].is(tok::colon) && Tok.Parent->is(tok::identifier))
760 return true;
761 if (Tok.is(tok::colon))
762 return false;
763 if (Tok.Parent->Type == TT_ObjCMethodSpecifier)
764 return true;
765 if (Tok.Parent->is(tok::r_paren) && Tok.is(tok::identifier))
766 // Don't space between ')' and <id>
767 return false;
768 if (Tok.Parent->is(tok::colon) && Tok.is(tok::l_paren))
769 // Don't space between ':' and '('
770 return false;
771 }
772 if (Line.Type == LT_ObjCProperty &&
773 (Tok.is(tok::equal) || Tok.Parent->is(tok::equal)))
774 return false;
775
776 if (Tok.Parent->is(tok::comma))
777 return true;
778 if (Tok.Type == TT_CtorInitializerColon || Tok.Type == TT_ObjCBlockLParen)
779 return true;
780 if (Tok.Type == TT_OverloadedOperator)
781 return Tok.is(tok::identifier) || Tok.is(tok::kw_new) ||
782 Tok.is(tok::kw_delete) || Tok.is(tok::kw_bool);
783 if (Tok.Parent->Type == TT_OverloadedOperator)
784 return false;
785 if (Tok.is(tok::colon))
786 return Line.First.isNot(tok::kw_case) && !Tok.Children.empty() &&
787 Tok.Type != TT_ObjCMethodExpr;
788 if (Tok.Parent->Type == TT_UnaryOperator || Tok.Parent->Type == TT_CastRParen)
789 return false;
790 if (Tok.Type == TT_UnaryOperator)
791 return Tok.Parent->isNot(tok::l_paren) &&
792 Tok.Parent->isNot(tok::l_square) && Tok.Parent->isNot(tok::at) &&
793 (Tok.Parent->isNot(tok::colon) ||
794 Tok.Parent->Type != TT_ObjCMethodExpr);
795 if (Tok.Parent->is(tok::greater) && Tok.is(tok::greater)) {
796 return Tok.Type == TT_TemplateCloser && Tok.Parent->Type ==
797 TT_TemplateCloser && Style.SplitTemplateClosingGreater;
798 }
799 if (Tok.Type == TT_BinaryOperator || Tok.Parent->Type == TT_BinaryOperator)
800 return true;
801 if (Tok.Parent->Type == TT_TemplateCloser && Tok.is(tok::l_paren))
802 return false;
803 if (Tok.is(tok::less) && Line.First.is(tok::hash))
804 return true;
805 if (Tok.Type == TT_TrailingUnaryOperator)
806 return false;
807 return spaceRequiredBetween(*Tok.Parent, Tok);
808}
809
810bool TokenAnnotator::canBreakBefore(const AnnotatedToken &Right) {
811 const AnnotatedToken &Left = *Right.Parent;
812 if (Line.Type == LT_ObjCMethodDecl) {
813 if (Right.is(tok::identifier) && !Right.Children.empty() &&
814 Right.Children[0].is(tok::colon) && Left.is(tok::identifier))
815 return true;
816 if (Right.is(tok::identifier) && Left.is(tok::l_paren) &&
817 Left.Parent->is(tok::colon))
818 // Don't break this identifier as ':' or identifier
819 // before it will break.
820 return false;
821 if (Right.is(tok::colon) && Left.is(tok::identifier) && Left.CanBreakBefore)
822 // Don't break at ':' if identifier before it can beak.
823 return false;
824 }
825 if (Right.Type == TT_StartOfName && Style.AllowReturnTypeOnItsOwnLine)
826 return true;
827 if (Right.is(tok::colon) && Right.Type == TT_ObjCMethodExpr)
828 return false;
829 if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
830 return true;
831 if (isObjCSelectorName(Right))
832 return true;
833 if (Left.ClosesTemplateDeclaration)
834 return true;
835 if (Right.Type == TT_ConditionalExpr || Right.is(tok::question))
836 return true;
837 if (Left.Type == TT_RangeBasedForLoopColon)
838 return true;
839 if (Left.Type == TT_PointerOrReference || Left.Type == TT_TemplateCloser ||
840 Left.Type == TT_UnaryOperator || Left.Type == TT_ConditionalExpr ||
841 Left.is(tok::question))
842 return false;
843 if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl)
844 return false;
845
846 if (Right.Type == TT_LineComment)
847 // We rely on MustBreakBefore being set correctly here as we should not
848 // change the "binding" behavior of a comment.
849 return false;
850
851 // Allow breaking after a trailing 'const', e.g. after a method declaration,
852 // unless it is follow by ';', '{' or '='.
853 if (Left.is(tok::kw_const) && Left.Parent != NULL &&
854 Left.Parent->is(tok::r_paren))
855 return Right.isNot(tok::l_brace) && Right.isNot(tok::semi) &&
856 Right.isNot(tok::equal);
857
858 // We only break before r_brace if there was a corresponding break before
859 // the l_brace, which is tracked by BreakBeforeClosingBrace.
860 if (Right.is(tok::r_brace))
861 return false;
862
863 if (Right.is(tok::r_paren) || Right.is(tok::greater))
864 return false;
865 return (isBinaryOperator(Left) && Left.isNot(tok::lessless)) ||
866 Left.is(tok::comma) || Right.is(tok::lessless) ||
867 Right.is(tok::arrow) || Right.is(tok::period) ||
868 Right.is(tok::colon) || Left.is(tok::coloncolon) ||
869 Left.is(tok::semi) || Left.is(tok::l_brace) ||
870 (Left.is(tok::r_paren) && Left.Type != TT_CastRParen &&
871 Right.is(tok::identifier)) ||
872 (Left.is(tok::l_paren) && !Right.is(tok::r_paren)) ||
873 (Left.is(tok::l_square) && !Right.is(tok::r_square));
874}
875
876} // namespace format
877} // namespace clang