diff options
Diffstat (limited to 'lib/Format/TokenAnnotator.cpp')
-rw-r--r-- | lib/Format/TokenAnnotator.cpp | 1096 |
1 files changed, 711 insertions, 385 deletions
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 17abb01..074e1d7 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -15,61 +15,12 @@ #include "TokenAnnotator.h" #include "clang/Basic/SourceManager.h" -#include "clang/Lex/Lexer.h" #include "llvm/Support/Debug.h" namespace clang { namespace format { -bool AnnotatedToken::isUnaryOperator() const { - switch (FormatTok.Tok.getKind()) { - case tok::plus: - case tok::plusplus: - case tok::minus: - case tok::minusminus: - case tok::exclaim: - case tok::tilde: - case tok::kw_sizeof: - case tok::kw_alignof: - return true; - default: - return false; - } -} - -bool AnnotatedToken::isBinaryOperator() const { - // Comma is a binary operator, but does not behave as such wrt. formatting. - return getPrecedence(*this) > prec::Comma; -} - -bool AnnotatedToken::isTrailingComment() const { - return is(tok::comment) && - (Children.empty() || Children[0].FormatTok.NewlinesBefore > 0); -} - -AnnotatedToken *AnnotatedToken::getPreviousNoneComment() const { - AnnotatedToken *Tok = Parent; - while (Tok != NULL && Tok->is(tok::comment)) - Tok = Tok->Parent; - return Tok; -} - -const AnnotatedToken *AnnotatedToken::getNextNoneComment() const { - const AnnotatedToken *Tok = Children.empty() ? NULL : &Children[0]; - while (Tok != NULL && Tok->is(tok::comment)) - Tok = Tok->Children.empty() ? NULL : &Tok->Children[0]; - return Tok; -} - -bool AnnotatedToken::closesScope() const { - return isOneOf(tok::r_paren, tok::r_brace, tok::r_square) || - Type == TT_TemplateCloser; -} - -bool AnnotatedToken::opensScope() const { - return isOneOf(tok::l_paren, tok::l_brace, tok::l_square) || - Type == TT_TemplateOpener; -} +namespace { /// \brief A parser that gathers additional information about tokens. /// @@ -78,11 +29,11 @@ bool AnnotatedToken::opensScope() const { /// into template parameter lists. class AnnotatingParser { public: - AnnotatingParser(SourceManager &SourceMgr, Lexer &Lex, AnnotatedLine &Line, + AnnotatingParser(const FormatStyle &Style, AnnotatedLine &Line, IdentifierInfo &Ident_in) - : SourceMgr(SourceMgr), Lex(Lex), Line(Line), CurrentToken(&Line.First), - KeywordVirtualFound(false), NameFound(false), Ident_in(Ident_in) { - Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/ false)); + : Style(Style), Line(Line), CurrentToken(Line.First), + KeywordVirtualFound(false), AutoFound(false), Ident_in(Ident_in) { + Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false)); } private: @@ -90,7 +41,7 @@ private: if (CurrentToken == NULL) return false; ScopedContextCreator ContextCreator(*this, tok::less, 10); - AnnotatedToken *Left = CurrentToken->Parent; + FormatToken *Left = CurrentToken->Previous; Contexts.back().IsExpression = false; while (CurrentToken != NULL) { if (CurrentToken->is(tok::greater)) { @@ -101,8 +52,18 @@ private: return true; } if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace, - tok::pipepipe, tok::ampamp, tok::question, - tok::colon)) + tok::question, tok::colon)) + return false; + // If a && or || is found and interpreted as a binary operator, this set + // of angles is likely part of something like "a < b && c > d". If the + // angles are inside an expression, the ||/&& might also be a binary + // operator that was misinterpreted because we are parsing template + // parameters. + // FIXME: This is getting out of hand, write a decent parser. + if (CurrentToken->Previous->isOneOf(tok::pipepipe, tok::ampamp) && + (CurrentToken->Previous->Type == TT_BinaryOperator || + Contexts[Contexts.size() - 2].IsExpression) && + Line.First->isNot(tok::kw_template)) return false; updateParameterCount(Left, CurrentToken); if (!consumeToken()) @@ -121,42 +82,66 @@ private: Contexts.size() == 2 && Contexts[0].ColonIsForRangeExpr; bool StartsObjCMethodExpr = false; - AnnotatedToken *Left = CurrentToken->Parent; + FormatToken *Left = CurrentToken->Previous; if (CurrentToken->is(tok::caret)) { // ^( starts a block. Left->Type = TT_ObjCBlockLParen; - } else if (AnnotatedToken *MaybeSel = Left->Parent) { + } else if (FormatToken *MaybeSel = Left->Previous) { // @selector( starts a selector. - if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Parent && - MaybeSel->Parent->is(tok::at)) { + if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Previous && + MaybeSel->Previous->is(tok::at)) { StartsObjCMethodExpr = true; } } + if (Left->Previous && Left->Previous->isOneOf(tok::kw_static_assert, + tok::kw_if, tok::kw_while)) { + // static_assert, if and while usually contain expressions. + Contexts.back().IsExpression = true; + } else if (Left->Previous && Left->Previous->is(tok::r_square) && + Left->Previous->MatchingParen && + Left->Previous->MatchingParen->Type == TT_LambdaLSquare) { + // This is a parameter list of a lambda expression. + Contexts.back().IsExpression = false; + } + if (StartsObjCMethodExpr) { Contexts.back().ColonIsObjCMethodExpr = true; Left->Type = TT_ObjCMethodExpr; } + bool MightBeFunctionType = CurrentToken->is(tok::star); + bool HasMultipleLines = false; + bool HasMultipleParametersOnALine = false; while (CurrentToken != NULL) { // LookForDecls is set when "if (" has been seen. Check for // 'identifier' '*' 'identifier' followed by not '=' -- this // '*' has to be a binary operator but determineStarAmpUsage() will // categorize it as an unary operator, so set the right type here. - if (LookForDecls && !CurrentToken->Children.empty()) { - AnnotatedToken &Prev = *CurrentToken->Parent; - AnnotatedToken &Next = CurrentToken->Children[0]; - if (Prev.Parent->is(tok::identifier) && - Prev.isOneOf(tok::star, tok::amp, tok::ampamp) && - CurrentToken->is(tok::identifier) && Next.isNot(tok::equal)) { - Prev.Type = TT_BinaryOperator; - LookForDecls = false; + if (LookForDecls && CurrentToken->Next) { + FormatToken *Prev = CurrentToken->getPreviousNonComment(); + if (Prev) { + FormatToken *PrevPrev = Prev->getPreviousNonComment(); + FormatToken *Next = CurrentToken->Next; + if (PrevPrev && PrevPrev->is(tok::identifier) && + Prev->isOneOf(tok::star, tok::amp, tok::ampamp) && + CurrentToken->is(tok::identifier) && Next->isNot(tok::equal)) { + Prev->Type = TT_BinaryOperator; + LookForDecls = false; + } } } + if (CurrentToken->Previous->Type == TT_PointerOrReference && + CurrentToken->Previous->Previous->isOneOf(tok::l_paren, + tok::coloncolon)) + MightBeFunctionType = true; if (CurrentToken->is(tok::r_paren)) { - if (CurrentToken->Parent->closesScope()) - CurrentToken->Parent->MatchingParen->NoMoreTokensOnLevel = true; + if (MightBeFunctionType && CurrentToken->Next && + (CurrentToken->Next->is(tok::l_paren) || + (CurrentToken->Next->is(tok::l_square) && + !Contexts.back().IsExpression))) + Left->Type = TT_FunctionTypeLParen; Left->MatchingParen = CurrentToken; CurrentToken->MatchingParen = Left; @@ -168,14 +153,27 @@ private: } } + if (!HasMultipleLines) + Left->PackingKind = PPK_Inconclusive; + else if (HasMultipleParametersOnALine) + Left->PackingKind = PPK_BinPacked; + else + Left->PackingKind = PPK_OnePerLine; + next(); return true; } if (CurrentToken->isOneOf(tok::r_square, tok::r_brace)) return false; updateParameterCount(Left, CurrentToken); + if (CurrentToken->is(tok::comma) && CurrentToken->Next && + !CurrentToken->Next->HasUnescapedNewline && + !CurrentToken->Next->isTrailingComment()) + HasMultipleParametersOnALine = true; if (!consumeToken()) return false; + if (CurrentToken && CurrentToken->HasUnescapedNewline) + HasMultipleLines = true; } return false; } @@ -184,34 +182,35 @@ private: if (!CurrentToken) return false; - // A '[' could be an index subscript (after an indentifier or after + // A '[' could be an index subscript (after an identifier or after // ')' or ']'), it could be the start of an Objective-C method // expression, or it could the the start of an Objective-C array literal. - AnnotatedToken *Left = CurrentToken->Parent; - AnnotatedToken *Parent = Left->getPreviousNoneComment(); + FormatToken *Left = CurrentToken->Previous; + FormatToken *Parent = Left->getPreviousNonComment(); bool StartsObjCMethodExpr = - Contexts.back().CanBeExpression && + Contexts.back().CanBeExpression && Left->Type != TT_LambdaLSquare && (!Parent || Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren, tok::kw_return, tok::kw_throw) || Parent->isUnaryOperator() || Parent->Type == TT_ObjCForIn || Parent->Type == TT_CastRParen || - getBinOpPrecedence(Parent->FormatTok.Tok.getKind(), true, true) > - prec::Unknown); + getBinOpPrecedence(Parent->Tok.getKind(), true, true) > prec::Unknown); ScopedContextCreator ContextCreator(*this, tok::l_square, 10); Contexts.back().IsExpression = true; - bool StartsObjCArrayLiteral = Parent && Parent->is(tok::at); + bool ColonFound = false; if (StartsObjCMethodExpr) { Contexts.back().ColonIsObjCMethodExpr = true; Left->Type = TT_ObjCMethodExpr; - } else if (StartsObjCArrayLiteral) { - Left->Type = TT_ObjCArrayLiteral; + } else if (Parent && Parent->is(tok::at)) { + Left->Type = TT_ArrayInitializerLSquare; + } else if (Left->Type == TT_Unknown) { + Left->Type = TT_ArraySubscriptLSquare; } while (CurrentToken != NULL) { if (CurrentToken->is(tok::r_square)) { - if (!CurrentToken->Children.empty() && - CurrentToken->Children[0].is(tok::l_paren)) { + if (CurrentToken->Next && CurrentToken->Next->is(tok::l_paren) && + Left->Type == TT_ObjCMethodExpr) { // An ObjC method call is rarely followed by an open parenthesis. // FIXME: Do we incorrectly label ":" with this? StartsObjCMethodExpr = false; @@ -224,8 +223,6 @@ private: // binary operator. if (Parent != NULL && Parent->Type == TT_PointerOrReference) Parent->Type = TT_BinaryOperator; - } else if (StartsObjCArrayLiteral) { - CurrentToken->Type = TT_ObjCArrayLiteral; } Left->MatchingParen = CurrentToken; CurrentToken->MatchingParen = Left; @@ -237,6 +234,12 @@ private: } if (CurrentToken->isOneOf(tok::r_paren, tok::r_brace)) return false; + if (CurrentToken->is(tok::colon)) + ColonFound = true; + if (CurrentToken->is(tok::comma) && + (Left->Type == TT_ArraySubscriptLSquare || + (Left->Type == TT_ObjCMethodExpr && !ColonFound))) + Left->Type = TT_ArrayInitializerLSquare; updateParameterCount(Left, CurrentToken); if (!consumeToken()) return false; @@ -246,8 +249,10 @@ private: bool parseBrace() { if (CurrentToken != NULL) { + FormatToken *Left = CurrentToken->Previous; ScopedContextCreator ContextCreator(*this, tok::l_brace, 1); - AnnotatedToken *Left = CurrentToken->Parent; + Contexts.back().ColonIsDictLiteral = true; + while (CurrentToken != NULL) { if (CurrentToken->is(tok::r_brace)) { Left->MatchingParen = CurrentToken; @@ -258,6 +263,8 @@ private: if (CurrentToken->isOneOf(tok::r_paren, tok::r_square)) return false; updateParameterCount(Left, CurrentToken); + if (CurrentToken->is(tok::colon)) + Left->Type = TT_DictLiteral; if (!consumeToken()) return false; } @@ -267,11 +274,15 @@ private: return true; } - void updateParameterCount(AnnotatedToken *Left, AnnotatedToken *Current) { - if (Current->is(tok::comma)) + void updateParameterCount(FormatToken *Left, FormatToken *Current) { + if (Current->is(tok::comma)) { ++Left->ParameterCount; - else if (Left->ParameterCount == 0 && Current->isNot(tok::comment)) + if (!Left->Role) + Left->Role.reset(new CommaSeparatedList(Style)); + Left->Role->CommaFound(Current); + } else if (Left->ParameterCount == 0 && Current->isNot(tok::comment)) { Left->ParameterCount = 1; + } } bool parseConditional() { @@ -294,40 +305,45 @@ private: if (!parseAngle()) return false; if (CurrentToken != NULL) - CurrentToken->Parent->ClosesTemplateDeclaration = true; + CurrentToken->Previous->ClosesTemplateDeclaration = true; return true; } return false; } bool consumeToken() { - AnnotatedToken *Tok = CurrentToken; + FormatToken *Tok = CurrentToken; next(); - switch (Tok->FormatTok.Tok.getKind()) { + switch (Tok->Tok.getKind()) { case tok::plus: case tok::minus: - if (Tok->Parent == NULL && Line.MustBeDeclaration) + if (Tok->Previous == NULL && Line.MustBeDeclaration) Tok->Type = TT_ObjCMethodSpecifier; break; case tok::colon: - if (Tok->Parent == NULL) + if (Tok->Previous == NULL) return false; // Colons from ?: are handled in parseConditional(). - if (Tok->Parent->is(tok::r_paren) && Contexts.size() == 1) { + if (Tok->Previous->is(tok::r_paren) && Contexts.size() == 1) { Tok->Type = TT_CtorInitializerColon; + } else if (Contexts.back().ColonIsDictLiteral) { + Tok->Type = TT_DictLiteral; } else if (Contexts.back().ColonIsObjCMethodExpr || - Line.First.Type == TT_ObjCMethodSpecifier) { + Line.First->Type == TT_ObjCMethodSpecifier) { Tok->Type = TT_ObjCMethodExpr; - Tok->Parent->Type = TT_ObjCSelectorName; - if (Tok->Parent->FormatTok.TokenLength > - Contexts.back().LongestObjCSelectorName) - Contexts.back().LongestObjCSelectorName = - Tok->Parent->FormatTok.TokenLength; + Tok->Previous->Type = TT_ObjCSelectorName; + if (Tok->Previous->ColumnWidth > + Contexts.back().LongestObjCSelectorName) { + Contexts.back().LongestObjCSelectorName = Tok->Previous->ColumnWidth; + } if (Contexts.back().FirstObjCSelectorName == NULL) - Contexts.back().FirstObjCSelectorName = Tok->Parent; + Contexts.back().FirstObjCSelectorName = Tok->Previous; } else if (Contexts.back().ColonIsForRangeExpr) { Tok->Type = TT_RangeBasedForLoopColon; - } else if (Contexts.size() == 1) { + } else if (CurrentToken != NULL && + CurrentToken->is(tok::numeric_constant)) { + Tok->Type = TT_BitFieldColon; + } else if (Contexts.size() == 1 && Line.First->isNot(tok::kw_enum)) { Tok->Type = TT_InheritanceColon; } else if (Contexts.back().ContextKind == tok::l_paren) { Tok->Type = TT_InlineASMColon; @@ -337,7 +353,7 @@ private: case tok::kw_while: if (CurrentToken != NULL && CurrentToken->is(tok::l_paren)) { next(); - if (!parseParens(/*LookForDecls=*/ true)) + if (!parseParens(/*LookForDecls=*/true)) return false; } break; @@ -350,7 +366,8 @@ private: case tok::l_paren: if (!parseParens()) return false; - if (Line.MustBeDeclaration && NameFound && !Contexts.back().IsExpression) + if (Line.MustBeDeclaration && Contexts.size() == 1 && + !Contexts.back().IsExpression) Line.MightBeFunctionDecl = true; break; case tok::l_square: @@ -362,7 +379,7 @@ private: return false; break; case tok::less: - if (parseAngle()) + if (Tok->Previous && !Tok->Previous->Tok.isLiteral() && parseAngle()) Tok->Type = TT_TemplateOpener; else { Tok->Type = TT_BinaryOperator; @@ -375,20 +392,26 @@ private: return false; case tok::r_brace: // Lines can start with '}'. - if (Tok->Parent != NULL) + if (Tok->Previous != NULL) return false; break; case tok::greater: Tok->Type = TT_BinaryOperator; break; case tok::kw_operator: - while (CurrentToken && CurrentToken->isNot(tok::l_paren)) { + while (CurrentToken && + !CurrentToken->isOneOf(tok::l_paren, tok::semi, tok::r_paren)) { if (CurrentToken->isOneOf(tok::star, tok::amp)) CurrentToken->Type = TT_PointerOrReference; consumeToken(); + if (CurrentToken && CurrentToken->Previous->Type == TT_BinaryOperator) + CurrentToken->Previous->Type = TT_OverloadedOperator; } - if (CurrentToken) + if (CurrentToken) { CurrentToken->Type = TT_OverloadedOperatorLParen; + if (CurrentToken->Previous->Type == TT_BinaryOperator) + CurrentToken->Previous->Type = TT_OverloadedOperator; + } break; case tok::question: parseConditional(); @@ -397,13 +420,15 @@ private: parseTemplateDeclaration(); break; case tok::identifier: - if (Line.First.is(tok::kw_for) && - Tok->FormatTok.Tok.getIdentifierInfo() == &Ident_in) + if (Line.First->is(tok::kw_for) && + Tok->Tok.getIdentifierInfo() == &Ident_in) Tok->Type = TT_ObjCForIn; break; case tok::comma: if (Contexts.back().FirstStartOfName) Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt = true; + if (Contexts.back().InCtorInitializer) + Tok->Type = TT_CtorInitializerComma; break; default: break; @@ -416,8 +441,7 @@ private: if (CurrentToken != NULL && CurrentToken->is(tok::less)) { next(); while (CurrentToken != NULL) { - if (CurrentToken->isNot(tok::comment) || - !CurrentToken->Children.empty()) + if (CurrentToken->isNot(tok::comment) || CurrentToken->Next) CurrentToken->Type = TT_ImplicitStringLiteral; next(); } @@ -447,11 +471,15 @@ private: next(); if (CurrentToken == NULL) return; + if (CurrentToken->Tok.is(tok::numeric_constant)) { + CurrentToken->SpacesRequiredBefore = 1; + return; + } // Hashes in the middle of a line can lead to any strange token // sequence. - if (CurrentToken->FormatTok.Tok.getIdentifierInfo() == NULL) + if (CurrentToken->Tok.getIdentifierInfo() == NULL) return; - switch (CurrentToken->FormatTok.Tok.getIdentifierInfo()->getPPKeywordID()) { + switch (CurrentToken->Tok.getIdentifierInfo()->getPPKeywordID()) { case tok::pp_include: case tok::pp_import: parseIncludeDirective(); @@ -473,9 +501,6 @@ private: public: LineType parseLine() { - int PeriodsAndArrows = 0; - AnnotatedToken *LastPeriodOrArrow = NULL; - bool CanBeBuilderTypeStmt = true; if (CurrentToken->is(tok::hash)) { parsePreprocessorDirective(); return LT_PreprocessorDirective; @@ -483,27 +508,13 @@ public: while (CurrentToken != NULL) { if (CurrentToken->is(tok::kw_virtual)) KeywordVirtualFound = true; - if (CurrentToken->isOneOf(tok::period, tok::arrow)) { - ++PeriodsAndArrows; - LastPeriodOrArrow = CurrentToken; - } - AnnotatedToken *TheToken = CurrentToken; if (!consumeToken()) return LT_Invalid; - if (getPrecedence(*TheToken) > prec::Assignment && - TheToken->Type == TT_BinaryOperator) - CanBeBuilderTypeStmt = false; } if (KeywordVirtualFound) return LT_VirtualFunctionDecl; - // Assume a builder-type call if there are 2 or more "." and "->". - if (PeriodsAndArrows >= 2 && CanBeBuilderTypeStmt) { - LastPeriodOrArrow->LastInChainOfCalls = true; - return LT_BuilderTypeCall; - } - - if (Line.First.Type == TT_ObjCMethodSpecifier) { + if (Line.First->Type == TT_ObjCMethodSpecifier) { if (Contexts.back().FirstObjCSelectorName != NULL) Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = Contexts.back().LongestObjCSelectorName; @@ -520,15 +531,20 @@ private: CurrentToken->BindingStrength = Contexts.back().BindingStrength; } - if (CurrentToken != NULL && !CurrentToken->Children.empty()) - CurrentToken = &CurrentToken->Children[0]; - else - CurrentToken = NULL; - - // Reset token type in case we have already looked at it and then recovered - // from an error (e.g. failure to find the matching >). if (CurrentToken != NULL) - CurrentToken->Type = TT_Unknown; + CurrentToken = CurrentToken->Next; + + if (CurrentToken != NULL) { + // Reset token type in case we have already looked at it and then + // recovered from an error (e.g. failure to find the matching >). + if (CurrentToken->Type != TT_LambdaLSquare && + CurrentToken->Type != TT_ImplicitStringLiteral) + CurrentToken->Type = TT_Unknown; + if (CurrentToken->Role) + CurrentToken->Role.reset(NULL); + CurrentToken->FakeLParens.clear(); + CurrentToken->FakeRParens = 0; + } } /// \brief A struct to hold information valid in a specific context, e.g. @@ -538,19 +554,22 @@ private: bool IsExpression) : ContextKind(ContextKind), BindingStrength(BindingStrength), LongestObjCSelectorName(0), ColonIsForRangeExpr(false), - ColonIsObjCMethodExpr(false), FirstObjCSelectorName(NULL), - FirstStartOfName(NULL), IsExpression(IsExpression), - CanBeExpression(true) {} + ColonIsDictLiteral(false), ColonIsObjCMethodExpr(false), + FirstObjCSelectorName(NULL), FirstStartOfName(NULL), + IsExpression(IsExpression), CanBeExpression(true), + InCtorInitializer(false) {} tok::TokenKind ContextKind; unsigned BindingStrength; unsigned LongestObjCSelectorName; bool ColonIsForRangeExpr; + bool ColonIsDictLiteral; bool ColonIsObjCMethodExpr; - AnnotatedToken *FirstObjCSelectorName; - AnnotatedToken *FirstStartOfName; + FormatToken *FirstObjCSelectorName; + FormatToken *FirstStartOfName; bool IsExpression; bool CanBeExpression; + bool InCtorInitializer; }; /// \brief Puts a new \c Context onto the stack \c Contexts for the lifetime @@ -561,21 +580,22 @@ private: ScopedContextCreator(AnnotatingParser &P, tok::TokenKind ContextKind, unsigned Increase) : P(P) { - P.Contexts.push_back( - Context(ContextKind, P.Contexts.back().BindingStrength + Increase, - P.Contexts.back().IsExpression)); + P.Contexts.push_back(Context(ContextKind, + P.Contexts.back().BindingStrength + Increase, + P.Contexts.back().IsExpression)); } ~ScopedContextCreator() { P.Contexts.pop_back(); } }; - void determineTokenType(AnnotatedToken &Current) { - if (getPrecedence(Current) == prec::Assignment && - (!Current.Parent || Current.Parent->isNot(tok::kw_operator))) { + void determineTokenType(FormatToken &Current) { + if (Current.getPrecedence() == prec::Assignment && + !Line.First->isOneOf(tok::kw_template, tok::kw_using) && + (!Current.Previous || Current.Previous->isNot(tok::kw_operator))) { Contexts.back().IsExpression = true; - for (AnnotatedToken *Previous = Current.Parent; - Previous && Previous->isNot(tok::comma); - Previous = Previous->Parent) { + for (FormatToken *Previous = Current.Previous; + Previous && !Previous->isOneOf(tok::comma, tok::semi); + Previous = Previous->Previous) { if (Previous->is(tok::r_square)) Previous = Previous->MatchingParen; if (Previous->Type == TT_BinaryOperator && @@ -585,69 +605,93 @@ private: } } else if (Current.isOneOf(tok::kw_return, tok::kw_throw) || (Current.is(tok::l_paren) && !Line.MustBeDeclaration && - (!Current.Parent || Current.Parent->isNot(tok::kw_for)))) { + !Line.InPPDirective && + (!Current.Previous || + !Current.Previous->isOneOf(tok::kw_for, tok::kw_catch)))) { Contexts.back().IsExpression = true; } else if (Current.isOneOf(tok::r_paren, tok::greater, tok::comma)) { - for (AnnotatedToken *Previous = Current.Parent; + for (FormatToken *Previous = Current.Previous; Previous && Previous->isOneOf(tok::star, tok::amp); - Previous = Previous->Parent) + Previous = Previous->Previous) Previous->Type = TT_PointerOrReference; - } else if (Current.Parent && - Current.Parent->Type == TT_CtorInitializerColon) { + } else if (Current.Previous && + Current.Previous->Type == TT_CtorInitializerColon) { Contexts.back().IsExpression = true; + Contexts.back().InCtorInitializer = true; } else if (Current.is(tok::kw_new)) { Contexts.back().CanBeExpression = false; - } else if (Current.is(tok::semi)) { + } else if (Current.is(tok::semi) || Current.is(tok::exclaim)) { // This should be the condition or increment in a for-loop. Contexts.back().IsExpression = true; } if (Current.Type == TT_Unknown) { - if (Current.Parent && Current.is(tok::identifier) && - ((Current.Parent->is(tok::identifier) && - Current.Parent->FormatTok.Tok.getIdentifierInfo() - ->getPPKeywordID() == tok::pp_not_keyword) || - isSimpleTypeSpecifier(*Current.Parent) || - Current.Parent->Type == TT_PointerOrReference || - Current.Parent->Type == TT_TemplateCloser)) { + // Line.MightBeFunctionDecl can only be true after the parentheses of a + // function declaration have been found. In this case, 'Current' is a + // trailing token of this declaration and thus cannot be a name. + if (isStartOfName(Current) && !Line.MightBeFunctionDecl) { Contexts.back().FirstStartOfName = &Current; Current.Type = TT_StartOfName; - NameFound = true; + } else if (Current.is(tok::kw_auto)) { + AutoFound = true; + } else if (Current.is(tok::arrow) && AutoFound && + Line.MustBeDeclaration) { + Current.Type = TT_TrailingReturnArrow; } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) { Current.Type = - determineStarAmpUsage(Current, Contexts.back().IsExpression); + determineStarAmpUsage(Current, Contexts.back().CanBeExpression && + Contexts.back().IsExpression); } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) { Current.Type = determinePlusMinusCaretUsage(Current); } else if (Current.isOneOf(tok::minusminus, tok::plusplus)) { Current.Type = determineIncrementUsage(Current); } else if (Current.is(tok::exclaim)) { Current.Type = TT_UnaryOperator; - } else if (Current.isBinaryOperator()) { + } else if (Current.isBinaryOperator() && + (!Current.Previous || + Current.Previous->isNot(tok::l_square))) { Current.Type = TT_BinaryOperator; } else if (Current.is(tok::comment)) { - std::string Data(Lexer::getSpelling(Current.FormatTok.Tok, SourceMgr, - Lex.getLangOpts())); - if (StringRef(Data).startswith("//")) + if (Current.TokenText.startswith("//")) Current.Type = TT_LineComment; else Current.Type = TT_BlockComment; } else if (Current.is(tok::r_paren)) { - bool ParensNotExpr = !Current.Parent || - Current.Parent->Type == TT_PointerOrReference || - Current.Parent->Type == TT_TemplateCloser; + FormatToken *LeftOfParens = NULL; + if (Current.MatchingParen) + LeftOfParens = Current.MatchingParen->getPreviousNonComment(); + bool IsCast = false; + bool ParensAreEmpty = Current.Previous == Current.MatchingParen; + bool ParensAreType = !Current.Previous || + Current.Previous->Type == TT_PointerOrReference || + Current.Previous->Type == TT_TemplateCloser || + isSimpleTypeSpecifier(*Current.Previous); bool ParensCouldEndDecl = - !Current.Children.empty() && - Current.Children[0].isOneOf(tok::equal, tok::semi, tok::l_brace); + Current.Next && + Current.Next->isOneOf(tok::equal, tok::semi, tok::l_brace); bool IsSizeOfOrAlignOf = - Current.MatchingParen && Current.MatchingParen->Parent && - Current.MatchingParen->Parent->isOneOf(tok::kw_sizeof, - tok::kw_alignof); - if (ParensNotExpr && !ParensCouldEndDecl && !IsSizeOfOrAlignOf && - Contexts.back().IsExpression) - // FIXME: We need to get smarter and understand more cases of casts. + LeftOfParens && + LeftOfParens->isOneOf(tok::kw_sizeof, tok::kw_alignof); + if (ParensAreType && !ParensCouldEndDecl && !IsSizeOfOrAlignOf && + (Contexts.back().IsExpression || + (Current.Next && Current.Next->isBinaryOperator()))) + IsCast = true; + if (Current.Next && Current.Next->isNot(tok::string_literal) && + (Current.Next->Tok.isLiteral() || + Current.Next->isOneOf(tok::kw_sizeof, tok::kw_alignof))) + IsCast = true; + // If there is an identifier after the (), it is likely a cast, unless + // there is also an identifier before the (). + if (LeftOfParens && (LeftOfParens->Tok.getIdentifierInfo() == NULL || + LeftOfParens->is(tok::kw_return)) && + LeftOfParens->Type != TT_OverloadedOperator && + LeftOfParens->Type != TT_TemplateCloser && Current.Next && + Current.Next->is(tok::identifier)) + IsCast = true; + if (IsCast && !ParensAreEmpty) Current.Type = TT_CastRParen; - } else if (Current.is(tok::at) && Current.Children.size()) { - switch (Current.Children[0].FormatTok.Tok.getObjCKeywordID()) { + } else if (Current.is(tok::at) && Current.Next) { + switch (Current.Next->Tok.getObjCKeywordID()) { case tok::objc_interface: case tok::objc_implementation: case tok::objc_protocol: @@ -659,27 +703,63 @@ private: default: break; } + } else if (Current.is(tok::period)) { + FormatToken *PreviousNoComment = Current.getPreviousNonComment(); + if (PreviousNoComment && + PreviousNoComment->isOneOf(tok::comma, tok::l_brace)) + Current.Type = TT_DesignatedInitializerPeriod; } } } + /// \brief Take a guess at whether \p Tok starts a name of a function or + /// variable declaration. + /// + /// This is a heuristic based on whether \p Tok is an identifier following + /// something that is likely a type. + bool isStartOfName(const FormatToken &Tok) { + if (Tok.isNot(tok::identifier) || Tok.Previous == NULL) + return false; + + // Skip "const" as it does not have an influence on whether this is a name. + FormatToken *PreviousNotConst = Tok.Previous; + while (PreviousNotConst != NULL && PreviousNotConst->is(tok::kw_const)) + PreviousNotConst = PreviousNotConst->Previous; + + if (PreviousNotConst == NULL) + return false; + + bool IsPPKeyword = PreviousNotConst->is(tok::identifier) && + PreviousNotConst->Previous && + PreviousNotConst->Previous->is(tok::hash); + + if (PreviousNotConst->Type == TT_TemplateCloser) + return PreviousNotConst && PreviousNotConst->MatchingParen && + PreviousNotConst->MatchingParen->Previous && + PreviousNotConst->MatchingParen->Previous->isNot(tok::kw_template); + + return (!IsPPKeyword && PreviousNotConst->is(tok::identifier)) || + PreviousNotConst->Type == TT_PointerOrReference || + isSimpleTypeSpecifier(*PreviousNotConst); + } + /// \brief Return the type of the given token assuming it is * or &. - TokenType - determineStarAmpUsage(const AnnotatedToken &Tok, bool IsExpression) { - const AnnotatedToken *PrevToken = Tok.getPreviousNoneComment(); + TokenType determineStarAmpUsage(const FormatToken &Tok, bool IsExpression) { + const FormatToken *PrevToken = Tok.getPreviousNonComment(); if (PrevToken == NULL) return TT_UnaryOperator; - const AnnotatedToken *NextToken = Tok.getNextNoneComment(); + const FormatToken *NextToken = Tok.getNextNonComment(); if (NextToken == NULL) return TT_Unknown; - if (PrevToken->is(tok::l_paren) && !IsExpression) + if (PrevToken->is(tok::coloncolon) || + (PrevToken->is(tok::l_paren) && !IsExpression)) return TT_PointerOrReference; if (PrevToken->isOneOf(tok::l_paren, tok::l_square, tok::l_brace, tok::comma, tok::semi, tok::kw_return, tok::colon, - tok::equal) || + tok::equal, tok::kw_delete, tok::kw_sizeof) || PrevToken->Type == TT_BinaryOperator || PrevToken->Type == TT_UnaryOperator || PrevToken->Type == TT_CastRParen) return TT_UnaryOperator; @@ -687,9 +767,14 @@ private: if (NextToken->is(tok::l_square)) return TT_PointerOrReference; - if (PrevToken->FormatTok.Tok.isLiteral() || + if (PrevToken->is(tok::r_paren) && PrevToken->MatchingParen && + PrevToken->MatchingParen->Previous && + PrevToken->MatchingParen->Previous->is(tok::kw_typeof)) + return TT_PointerOrReference; + + if (PrevToken->Tok.isLiteral() || PrevToken->isOneOf(tok::r_paren, tok::r_square) || - NextToken->FormatTok.Tok.isLiteral() || NextToken->isUnaryOperator()) + NextToken->Tok.isLiteral() || NextToken->isUnaryOperator()) return TT_BinaryOperator; // It is very unlikely that we are going to find a pointer or reference type @@ -700,9 +785,9 @@ private: return TT_PointerOrReference; } - TokenType determinePlusMinusCaretUsage(const AnnotatedToken &Tok) { - const AnnotatedToken *PrevToken = Tok.getPreviousNoneComment(); - if (PrevToken == NULL) + TokenType determinePlusMinusCaretUsage(const FormatToken &Tok) { + const FormatToken *PrevToken = Tok.getPreviousNonComment(); + if (PrevToken == NULL || PrevToken->Type == TT_CastRParen) return TT_UnaryOperator; // Use heuristics to recognize unary operators. @@ -720,9 +805,9 @@ private: } /// \brief Determine whether ++/-- are pre- or post-increments/-decrements. - TokenType determineIncrementUsage(const AnnotatedToken &Tok) { - const AnnotatedToken *PrevToken = Tok.getPreviousNoneComment(); - if (PrevToken == NULL) + TokenType determineIncrementUsage(const FormatToken &Tok) { + const FormatToken *PrevToken = Tok.getPreviousNonComment(); + if (PrevToken == NULL || PrevToken->Type == TT_CastRParen) return TT_UnaryOperator; if (PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::identifier)) return TT_TrailingUnaryOperator; @@ -733,8 +818,8 @@ private: // FIXME: This is copy&pasted from Sema. Put it in a common place and remove // duplication. /// \brief Determine whether the token kind starts a simple-type-specifier. - bool isSimpleTypeSpecifier(const AnnotatedToken &Tok) const { - switch (Tok.FormatTok.Tok.getKind()) { + bool isSimpleTypeSpecifier(const FormatToken &Tok) const { + switch (Tok.Tok.getKind()) { case tok::kw_short: case tok::kw_long: case tok::kw___int64: @@ -750,71 +835,90 @@ private: case tok::kw_wchar_t: case tok::kw_bool: case tok::kw___underlying_type: - return true; case tok::annot_typename: case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_typeof: case tok::kw_decltype: - return Lex.getLangOpts().CPlusPlus; + return true; default: - break; + return false; } - return false; } SmallVector<Context, 8> Contexts; - SourceManager &SourceMgr; - Lexer &Lex; + const FormatStyle &Style; AnnotatedLine &Line; - AnnotatedToken *CurrentToken; + FormatToken *CurrentToken; bool KeywordVirtualFound; - bool NameFound; + bool AutoFound; IdentifierInfo &Ident_in; }; +static int PrecedenceUnaryOperator = prec::PointerToMember + 1; +static int PrecedenceArrowAndPeriod = prec::PointerToMember + 2; + /// \brief Parses binary expressions by inserting fake parenthesis based on /// operator precedence. class ExpressionParser { public: - ExpressionParser(AnnotatedLine &Line) : Current(&Line.First) {} + ExpressionParser(AnnotatedLine &Line) : Current(Line.First) { + // Skip leading "}", e.g. in "} else if (...) {". + if (Current->is(tok::r_brace)) + next(); + } /// \brief Parse expressions with the given operatore precedence. void parse(int Precedence = 0) { - if (Precedence > prec::PointerToMember || Current == NULL) + // Skip 'return' and ObjC selector colons as they are not part of a binary + // expression. + while (Current && + (Current->is(tok::kw_return) || + (Current->is(tok::colon) && Current->Type == TT_ObjCMethodExpr))) + next(); + + if (Current == NULL || Precedence > PrecedenceArrowAndPeriod) return; - // Eagerly consume trailing comments. - while (Current && Current->isTrailingComment()) { - next(); + // Conditional expressions need to be parsed separately for proper nesting. + if (Precedence == prec::Conditional) { + parseConditionalExpr(); + return; } - AnnotatedToken *Start = Current; - bool OperatorFound = false; + // Parse unary operators, which all have a higher precedence than binary + // operators. + if (Precedence == PrecedenceUnaryOperator) { + parseUnaryOperator(); + return; + } + + FormatToken *Start = Current; + FormatToken *LatestOperator = NULL; while (Current) { // Consume operators with higher precedence. parse(Precedence + 1); - int CurrentPrecedence = 0; - if (Current) { - if (Current->Type == TT_ConditionalExpr) - CurrentPrecedence = 1 + (int) prec::Conditional; - else if (Current->is(tok::semi) || Current->Type == TT_InlineASMColon) - CurrentPrecedence = 1; - else if (Current->Type == TT_BinaryOperator || Current->is(tok::comma)) - CurrentPrecedence = 1 + (int) getPrecedence(*Current); - } + int CurrentPrecedence = getCurrentPrecedence(); + + if (Current && Current->Type == TT_ObjCSelectorName && + Precedence == CurrentPrecedence) + Start = Current; // At the end of the line or when an operator with higher precedence is // found, insert fake parenthesis and return. if (Current == NULL || Current->closesScope() || - (CurrentPrecedence != 0 && CurrentPrecedence < Precedence)) { - if (OperatorFound) { - Start->FakeLParens.push_back(prec::Level(Precedence - 1)); - if (Current) - ++Current->Parent->FakeRParens; + (CurrentPrecedence != -1 && CurrentPrecedence < Precedence)) { + if (LatestOperator) { + if (Precedence == PrecedenceArrowAndPeriod) { + LatestOperator->LastInChainOfCalls = true; + // Call expressions don't have a binary operator precedence. + addFakeParenthesis(Start, prec::Unknown); + } else { + addFakeParenthesis(Start, prec::Level(Precedence)); + } } return; } @@ -829,7 +933,7 @@ public: } else { // Operator found. if (CurrentPrecedence == Precedence) - OperatorFound = true; + LatestOperator = Current; next(); } @@ -837,16 +941,99 @@ public: } private: + /// \brief Gets the precedence (+1) of the given token for binary operators + /// and other tokens that we treat like binary operators. + int getCurrentPrecedence() { + if (Current) { + if (Current->Type == TT_ConditionalExpr) + return prec::Conditional; + else if (Current->is(tok::semi) || Current->Type == TT_InlineASMColon || + Current->Type == TT_ObjCSelectorName) + return 0; + else if (Current->Type == TT_BinaryOperator || Current->is(tok::comma)) + return Current->getPrecedence(); + else if (Current->isOneOf(tok::period, tok::arrow)) + return PrecedenceArrowAndPeriod; + } + return -1; + } + + void addFakeParenthesis(FormatToken *Start, prec::Level Precedence) { + Start->FakeLParens.push_back(Precedence); + if (Precedence > prec::Unknown) + Start->StartsBinaryExpression = true; + if (Current) { + ++Current->Previous->FakeRParens; + if (Precedence > prec::Unknown) + Current->Previous->EndsBinaryExpression = true; + } + } + + /// \brief Parse unary operator expressions and surround them with fake + /// parentheses if appropriate. + void parseUnaryOperator() { + if (Current == NULL || Current->Type != TT_UnaryOperator) { + parse(PrecedenceArrowAndPeriod); + return; + } + + FormatToken *Start = Current; + next(); + parseUnaryOperator(); + + // The actual precedence doesn't matter. + addFakeParenthesis(Start, prec::Unknown); + } + + void parseConditionalExpr() { + FormatToken *Start = Current; + parse(prec::LogicalOr); + if (!Current || !Current->is(tok::question)) + return; + next(); + parse(prec::LogicalOr); + if (!Current || Current->Type != TT_ConditionalExpr) + return; + next(); + parseConditionalExpr(); + addFakeParenthesis(Start, prec::Conditional); + } + void next() { - if (Current != NULL) - Current = Current->Children.empty() ? NULL : &Current->Children[0]; + if (Current) + Current = Current->Next; + while (Current && Current->isTrailingComment()) + Current = Current->Next; } - AnnotatedToken *Current; + FormatToken *Current; }; +} // end anonymous namespace + +void +TokenAnnotator::setCommentLineLevels(SmallVectorImpl<AnnotatedLine *> &Lines) { + const AnnotatedLine *NextNonCommentLine = NULL; + for (SmallVectorImpl<AnnotatedLine *>::reverse_iterator I = Lines.rbegin(), + E = Lines.rend(); + I != E; ++I) { + if (NextNonCommentLine && (*I)->First->is(tok::comment) && + (*I)->First->Next == NULL) + (*I)->Level = NextNonCommentLine->Level; + else + NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : NULL; + + setCommentLineLevels((*I)->Children); + } +} + void TokenAnnotator::annotate(AnnotatedLine &Line) { - AnnotatingParser Parser(SourceMgr, Lex, Line, Ident_in); + for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(), + E = Line.Children.end(); + I != E; ++I) { + annotate(**I); + } + AnnotatingParser Parser(Style, Line, Ident_in); Line.Type = Parser.parseLine(); if (Line.Type == LT_Invalid) return; @@ -854,84 +1041,114 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) { ExpressionParser ExprParser(Line); ExprParser.parse(); - if (Line.First.Type == TT_ObjCMethodSpecifier) + if (Line.First->Type == TT_ObjCMethodSpecifier) Line.Type = LT_ObjCMethodDecl; - else if (Line.First.Type == TT_ObjCDecl) + else if (Line.First->Type == TT_ObjCDecl) Line.Type = LT_ObjCDecl; - else if (Line.First.Type == TT_ObjCProperty) + else if (Line.First->Type == TT_ObjCProperty) Line.Type = LT_ObjCProperty; - Line.First.SpacesRequiredBefore = 1; - Line.First.MustBreakBefore = Line.First.FormatTok.MustBreakBefore; - Line.First.CanBreakBefore = Line.First.MustBreakBefore; - - Line.First.TotalLength = Line.First.FormatTok.TokenLength; + Line.First->SpacesRequiredBefore = 1; + Line.First->CanBreakBefore = Line.First->MustBreakBefore; } void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { - if (Line.First.Children.empty()) + Line.First->TotalLength = + Line.First->IsMultiline ? Style.ColumnLimit : Line.First->ColumnWidth; + if (!Line.First->Next) return; - AnnotatedToken *Current = &Line.First.Children[0]; + FormatToken *Current = Line.First->Next; + bool InFunctionDecl = Line.MightBeFunctionDecl; while (Current != NULL) { if (Current->Type == TT_LineComment) Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments; - else - Current->SpacesRequiredBefore = - spaceRequiredBefore(Line, *Current) ? 1 : 0; - - if (Current->FormatTok.MustBreakBefore) { - Current->MustBreakBefore = true; - } else if (Current->Type == TT_LineComment) { - Current->MustBreakBefore = Current->FormatTok.NewlinesBefore > 0; - } else if (Current->Parent->isTrailingComment() || - (Current->is(tok::string_literal) && - Current->Parent->is(tok::string_literal))) { - Current->MustBreakBefore = true; - } else if (Current->is(tok::lessless) && !Current->Children.empty() && - Current->Parent->is(tok::string_literal) && - Current->Children[0].is(tok::string_literal)) { - Current->MustBreakBefore = true; - } else { - Current->MustBreakBefore = false; - } + else if (Current->SpacesRequiredBefore == 0 && + spaceRequiredBefore(Line, *Current)) + Current->SpacesRequiredBefore = 1; + + Current->MustBreakBefore = + Current->MustBreakBefore || mustBreakBefore(Line, *Current); + Current->CanBreakBefore = Current->MustBreakBefore || canBreakBefore(Line, *Current); - if (Current->MustBreakBefore) - Current->TotalLength = Current->Parent->TotalLength + Style.ColumnLimit; + if (Current->MustBreakBefore || !Current->Children.empty() || + Current->IsMultiline) + Current->TotalLength = Current->Previous->TotalLength + Style.ColumnLimit; else - Current->TotalLength = - Current->Parent->TotalLength + Current->FormatTok.TokenLength + - Current->SpacesRequiredBefore; + Current->TotalLength = Current->Previous->TotalLength + + Current->ColumnWidth + + Current->SpacesRequiredBefore; + + if (Current->Type == TT_CtorInitializerColon) + InFunctionDecl = false; + // FIXME: Only calculate this if CanBreakBefore is true once static // initializers etc. are sorted out. // FIXME: Move magic numbers to a better place. - Current->SplitPenalty = - 20 * Current->BindingStrength + splitPenalty(Line, *Current); + Current->SplitPenalty = 20 * Current->BindingStrength + + splitPenalty(Line, *Current, InFunctionDecl); - Current = Current->Children.empty() ? NULL : &Current->Children[0]; + Current = Current->Next; } - DEBUG({ - printDebugInfo(Line); - }); + calculateUnbreakableTailLengths(Line); + for (Current = Line.First; Current != NULL; Current = Current->Next) { + if (Current->Role) + Current->Role->precomputeFormattingInfos(Current); + } + + DEBUG({ printDebugInfo(Line); }); + + for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(), + E = Line.Children.end(); + I != E; ++I) { + calculateFormattingInformation(**I); + } +} + +void TokenAnnotator::calculateUnbreakableTailLengths(AnnotatedLine &Line) { + unsigned UnbreakableTailLength = 0; + FormatToken *Current = Line.Last; + while (Current != NULL) { + Current->UnbreakableTailLength = UnbreakableTailLength; + if (Current->CanBreakBefore || + Current->isOneOf(tok::comment, tok::string_literal)) { + UnbreakableTailLength = 0; + } else { + UnbreakableTailLength += + Current->ColumnWidth + Current->SpacesRequiredBefore; + } + Current = Current->Previous; + } } unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, - const AnnotatedToken &Tok) { - const AnnotatedToken &Left = *Tok.Parent; - const AnnotatedToken &Right = Tok; + const FormatToken &Tok, + bool InFunctionDecl) { + const FormatToken &Left = *Tok.Previous; + const FormatToken &Right = Tok; - if (Right.Type == TT_StartOfName) { - if (Line.First.is(tok::kw_for) && Right.PartOfMultiVariableDeclStmt) + if (Left.is(tok::semi)) + return 0; + if (Left.is(tok::comma)) + return 1; + if (Right.is(tok::l_square)) + return 150; + + if (Right.Type == TT_StartOfName || Right.is(tok::kw_operator)) { + if (Line.First->is(tok::kw_for) && Right.PartOfMultiVariableDeclStmt) return 3; - else if (Line.MightBeFunctionDecl && Right.BindingStrength == 1) + if (Left.Type == TT_StartOfName) + return 20; + if (InFunctionDecl && Right.BindingStrength == 1) // FIXME: Clean up hack of using BindingStrength to find top-level names. return Style.PenaltyReturnTypeOnItsOwnLine; - else - return 200; + return 200; } if (Left.is(tok::equal) && Right.is(tok::l_brace)) return 150; + if (Left.Type == TT_CastRParen) + return 100; if (Left.is(tok::coloncolon)) return 500; if (Left.isOneOf(tok::kw_class, tok::kw_struct)) @@ -941,50 +1158,53 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, Left.Type == TT_InheritanceColon) return 2; - if (Right.isOneOf(tok::arrow, tok::period)) { - if (Line.Type == LT_BuilderTypeCall) - return prec::PointerToMember; + if (Right.isMemberAccess()) { if (Left.isOneOf(tok::r_paren, tok::r_square) && Left.MatchingParen && Left.MatchingParen->ParameterCount > 0) return 20; // Should be smaller than breaking at a nested comma. return 150; } + // Breaking before a trailing 'const' or not-function-like annotation is bad. + if (Left.is(tok::r_paren) && Line.Type != LT_ObjCProperty && + (Right.is(tok::kw_const) || (Right.is(tok::identifier) && Right.Next && + Right.Next->isNot(tok::l_paren)))) + return 100; + // In for-loops, prefer breaking at ',' and ';'. - if (Line.First.is(tok::kw_for) && Left.is(tok::equal)) + if (Line.First->is(tok::kw_for) && Left.is(tok::equal)) return 4; - if (Left.is(tok::semi)) - return 0; - if (Left.is(tok::comma)) - return 1; - // In Objective-C method expressions, prefer breaking before "param:" over // breaking after it. if (Right.Type == TT_ObjCSelectorName) return 0; if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr) - return 20; + return 50; - if (Left.is(tok::l_paren) && Line.MightBeFunctionDecl) + if (Left.is(tok::l_paren) && InFunctionDecl) return 100; if (Left.opensScope()) - return Left.ParameterCount > 1 ? prec::Comma : 20; + return Left.ParameterCount > 1 ? Style.PenaltyBreakBeforeFirstCallParameter + : 19; if (Right.is(tok::lessless)) { if (Left.is(tok::string_literal)) { - StringRef Content = StringRef(Left.FormatTok.Tok.getLiteralData(), - Left.FormatTok.TokenLength); - Content = Content.drop_back(1).drop_front(1).trim(); + StringRef Content = Left.TokenText; + if (Content.startswith("\"")) + Content = Content.drop_front(1); + if (Content.endswith("\"")) + Content = Content.drop_back(1); + Content = Content.trim(); if (Content.size() > 1 && (Content.back() == ':' || Content.back() == '=')) - return 100; + return 25; } - return prec::Shift; + return 1; // Breaking at a << is really cheap. } if (Left.Type == TT_ConditionalExpr) return prec::Conditional; - prec::Level Level = getPrecedence(Left); + prec::Level Level = Left.getPrecedence(); if (Level != prec::Unknown) return Level; @@ -993,13 +1213,23 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, } bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, - const AnnotatedToken &Left, - const AnnotatedToken &Right) { + const FormatToken &Left, + const FormatToken &Right) { if (Right.is(tok::hashhash)) return Left.is(tok::hash); if (Left.isOneOf(tok::hashhash, tok::hash)) return Right.is(tok::hash); - if (Right.isOneOf(tok::r_paren, tok::semi, tok::comma)) + if (Left.is(tok::l_paren) && Right.is(tok::r_paren)) + return Style.SpaceInEmptyParentheses; + if (Left.is(tok::l_paren) || Right.is(tok::r_paren)) + return (Right.Type == TT_CastRParen || + (Left.MatchingParen && Left.MatchingParen->Type == TT_CastRParen)) + ? Style.SpacesInCStyleCastParentheses + : Style.SpacesInParentheses; + if (Style.SpacesInAngles && + ((Left.Type == TT_TemplateOpener) != (Right.Type == TT_TemplateCloser))) + return true; + if (Right.isOneOf(tok::semi, tok::comma)) return false; if (Right.is(tok::less) && (Left.is(tok::kw_template) || @@ -1017,186 +1247,282 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (Left.is(tok::coloncolon)) return false; if (Right.is(tok::coloncolon)) - return !Left.isOneOf(tok::identifier, tok::greater, tok::l_paren); + return (Left.is(tok::less) && Style.Standard == FormatStyle::LS_Cpp03) || + !Left.isOneOf(tok::identifier, tok::greater, tok::l_paren, + tok::r_paren, tok::less); if (Left.is(tok::less) || Right.isOneOf(tok::greater, tok::less)) return false; + if (Right.is(tok::ellipsis)) + return Left.Tok.isLiteral(); + if (Left.is(tok::l_square) && Right.is(tok::amp)) + return false; if (Right.Type == TT_PointerOrReference) - return Left.FormatTok.Tok.isLiteral() || + return Left.Tok.isLiteral() || ((Left.Type != TT_PointerOrReference) && Left.isNot(tok::l_paren) && !Style.PointerBindsToType); + if (Right.Type == TT_FunctionTypeLParen && Left.isNot(tok::l_paren) && + (Left.Type != TT_PointerOrReference || Style.PointerBindsToType)) + return true; if (Left.Type == TT_PointerOrReference) - return Right.FormatTok.Tok.isLiteral() || + return Right.Tok.isLiteral() || Right.Type == TT_BlockComment || ((Right.Type != TT_PointerOrReference) && Right.isNot(tok::l_paren) && Style.PointerBindsToType && - Left.Parent && Left.Parent->isNot(tok::l_paren)); + Left.Previous && + !Left.Previous->isOneOf(tok::l_paren, tok::coloncolon)); if (Right.is(tok::star) && Left.is(tok::l_paren)) return false; if (Left.is(tok::l_square)) - return Left.Type == TT_ObjCArrayLiteral && Right.isNot(tok::r_square); + return Left.Type == TT_ArrayInitializerLSquare && + Right.isNot(tok::r_square); if (Right.is(tok::r_square)) - return Right.Type == TT_ObjCArrayLiteral; - if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr) - return false; - if (Left.is(tok::period) || Right.is(tok::period)) + return Right.MatchingParen && + Right.MatchingParen->Type == TT_ArrayInitializerLSquare; + if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr && + Right.Type != TT_LambdaLSquare && Left.isNot(tok::numeric_constant)) return false; if (Left.is(tok::colon)) return Left.Type != TT_ObjCMethodExpr; if (Right.is(tok::colon)) - return Right.Type != TT_ObjCMethodExpr; - if (Left.is(tok::l_paren)) - return false; + return Right.Type != TT_ObjCMethodExpr && !Left.is(tok::question); if (Right.is(tok::l_paren)) { + if (Left.is(tok::r_paren) && Left.MatchingParen && + Left.MatchingParen->Previous && + Left.MatchingParen->Previous->is(tok::kw___attribute)) + return true; return Line.Type == LT_ObjCDecl || - Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch, - tok::kw_return, tok::kw_catch, tok::kw_new, - tok::kw_delete, tok::semi); + Left.isOneOf(tok::kw_return, tok::kw_new, tok::kw_delete, + tok::semi) || + (Style.SpaceAfterControlStatementKeyword && + Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch, + tok::kw_catch)); } - if (Left.is(tok::at) && - Right.FormatTok.Tok.getObjCKeywordID() != tok::objc_not_keyword) + if (Left.is(tok::at) && Right.Tok.getObjCKeywordID() != tok::objc_not_keyword) return false; if (Left.is(tok::l_brace) && Right.is(tok::r_brace)) + return !Left.Children.empty(); // No spaces in "{}". + if (Left.is(tok::l_brace) || Right.is(tok::r_brace)) + return !Style.Cpp11BracedListStyle; + if (Right.Type == TT_UnaryOperator) + return !Left.isOneOf(tok::l_paren, tok::l_square, tok::at) && + (Left.isNot(tok::colon) || Left.Type != TT_ObjCMethodExpr); + if (Left.isOneOf(tok::identifier, tok::greater, tok::r_square) && + Right.is(tok::l_brace) && Right.getNextNonComment() && + Right.BlockKind != BK_Block) return false; - if (Right.is(tok::ellipsis)) + if (Left.is(tok::period) || Right.is(tok::period)) + return false; + if (Left.Type == TT_BlockComment && Left.TokenText.endswith("=*/")) + return false; + if (Right.is(tok::hash) && Left.is(tok::identifier) && Left.TokenText == "L") return false; return true; } bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, - const AnnotatedToken &Tok) { - if (Tok.FormatTok.Tok.getIdentifierInfo() && - Tok.Parent->FormatTok.Tok.getIdentifierInfo()) + const FormatToken &Tok) { + if (Tok.Tok.getIdentifierInfo() && Tok.Previous->Tok.getIdentifierInfo()) return true; // Never ever merge two identifiers. + if (Tok.Previous->Type == TT_ImplicitStringLiteral) + return Tok.WhitespaceRange.getBegin() != Tok.WhitespaceRange.getEnd(); if (Line.Type == LT_ObjCMethodDecl) { - if (Tok.Parent->Type == TT_ObjCMethodSpecifier) + if (Tok.Previous->Type == TT_ObjCMethodSpecifier) return true; - if (Tok.Parent->is(tok::r_paren) && Tok.is(tok::identifier)) + if (Tok.Previous->is(tok::r_paren) && Tok.is(tok::identifier)) // Don't space between ')' and <id> return false; } if (Line.Type == LT_ObjCProperty && - (Tok.is(tok::equal) || Tok.Parent->is(tok::equal))) + (Tok.is(tok::equal) || Tok.Previous->is(tok::equal))) return false; - if (Tok.Parent->is(tok::comma)) + if (Tok.Type == TT_TrailingReturnArrow || + Tok.Previous->Type == TT_TrailingReturnArrow) + return true; + if (Tok.Previous->is(tok::comma)) return true; if (Tok.is(tok::comma)) return false; if (Tok.Type == TT_CtorInitializerColon || Tok.Type == TT_ObjCBlockLParen) return true; - if (Tok.Parent->FormatTok.Tok.is(tok::kw_operator)) - return false; + if (Tok.Previous->Tok.is(tok::kw_operator)) + return Tok.is(tok::coloncolon); if (Tok.Type == TT_OverloadedOperatorLParen) return false; if (Tok.is(tok::colon)) - return !Line.First.isOneOf(tok::kw_case, tok::kw_default) && - Tok.getNextNoneComment() != NULL && Tok.Type != TT_ObjCMethodExpr; - if (Tok.is(tok::l_paren) && !Tok.Children.empty() && - Tok.Children[0].Type == TT_PointerOrReference && - !Tok.Children[0].Children.empty() && - Tok.Children[0].Children[0].isNot(tok::r_paren) && - Tok.Parent->isNot(tok::l_paren) && - (Tok.Parent->Type != TT_PointerOrReference || Style.PointerBindsToType)) - return true; - if (Tok.Parent->Type == TT_UnaryOperator || Tok.Parent->Type == TT_CastRParen) + return !Line.First->isOneOf(tok::kw_case, tok::kw_default) && + Tok.getNextNonComment() != NULL && Tok.Type != TT_ObjCMethodExpr && + !Tok.Previous->is(tok::question); + if (Tok.Previous->Type == TT_UnaryOperator || + Tok.Previous->Type == TT_CastRParen) return false; - if (Tok.Type == TT_UnaryOperator) - return !Tok.Parent->isOneOf(tok::l_paren, tok::l_square, tok::at) && - (Tok.Parent->isNot(tok::colon) || - Tok.Parent->Type != TT_ObjCMethodExpr); - if (Tok.Parent->is(tok::greater) && Tok.is(tok::greater)) { + if (Tok.Previous->is(tok::greater) && Tok.is(tok::greater)) { return Tok.Type == TT_TemplateCloser && - Tok.Parent->Type == TT_TemplateCloser && - Style.Standard != FormatStyle::LS_Cpp11; + Tok.Previous->Type == TT_TemplateCloser && + (Style.Standard != FormatStyle::LS_Cpp11 || Style.SpacesInAngles); } if (Tok.isOneOf(tok::arrowstar, tok::periodstar) || - Tok.Parent->isOneOf(tok::arrowstar, tok::periodstar)) + Tok.Previous->isOneOf(tok::arrowstar, tok::periodstar)) + return false; + if (!Style.SpaceBeforeAssignmentOperators && + Tok.getPrecedence() == prec::Assignment) return false; - if (Tok.Type == TT_BinaryOperator || Tok.Parent->Type == TT_BinaryOperator) + if ((Tok.Type == TT_BinaryOperator && !Tok.Previous->is(tok::l_paren)) || + Tok.Previous->Type == TT_BinaryOperator) return true; - if (Tok.Parent->Type == TT_TemplateCloser && Tok.is(tok::l_paren)) + if (Tok.Previous->Type == TT_TemplateCloser && Tok.is(tok::l_paren)) return false; - if (Tok.is(tok::less) && Line.First.is(tok::hash)) + if (Tok.is(tok::less) && Tok.Previous->isNot(tok::l_paren) && + Line.First->is(tok::hash)) return true; if (Tok.Type == TT_TrailingUnaryOperator) return false; - return spaceRequiredBetween(Line, *Tok.Parent, Tok); + return spaceRequiredBetween(Line, *Tok.Previous, Tok); +} + +bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, + const FormatToken &Right) { + if (Right.is(tok::comment)) { + return Right.NewlinesBefore > 0; + } else if (Right.Previous->isTrailingComment() || + (Right.is(tok::string_literal) && + Right.Previous->is(tok::string_literal))) { + return true; + } else if (Right.Previous->IsUnterminatedLiteral) { + return true; + } else if (Right.is(tok::lessless) && Right.Next && + Right.Previous->is(tok::string_literal) && + Right.Next->is(tok::string_literal)) { + return true; + } else if (Right.Previous->ClosesTemplateDeclaration && + Right.Previous->MatchingParen && + Right.Previous->MatchingParen->BindingStrength == 1 && + Style.AlwaysBreakTemplateDeclarations) { + // FIXME: Fix horrible hack of using BindingStrength to find top-level <>. + return true; + } else if (Right.Type == TT_CtorInitializerComma && + Style.BreakConstructorInitializersBeforeComma && + !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) { + return true; + } else if (Right.Previous->BlockKind == BK_Block && + Right.Previous->isNot(tok::r_brace) && Right.isNot(tok::r_brace)) { + return true; + } else if (Right.is(tok::l_brace) && (Right.BlockKind == BK_Block)) { + return Style.BreakBeforeBraces == FormatStyle::BS_Allman; + } + return false; } bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, - const AnnotatedToken &Right) { - const AnnotatedToken &Left = *Right.Parent; - if (Right.Type == TT_StartOfName) + const FormatToken &Right) { + const FormatToken &Left = *Right.Previous; + if (Right.Type == TT_StartOfName || Right.is(tok::kw_operator)) return true; - if (Right.is(tok::colon) && Right.Type == TT_ObjCMethodExpr) + if (Right.isTrailingComment()) + // We rely on MustBreakBefore being set correctly here as we should not + // change the "binding" behavior of a comment. return false; - if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr) + if (Left.is(tok::question) && Right.is(tok::colon)) + return false; + if (Right.Type == TT_ConditionalExpr || Right.is(tok::question)) + return Style.BreakBeforeTernaryOperators; + if (Left.Type == TT_ConditionalExpr || Left.is(tok::question)) + return !Style.BreakBeforeTernaryOperators; + if (Right.is(tok::colon) && + (Right.Type == TT_DictLiteral || Right.Type == TT_ObjCMethodExpr)) + return false; + if (Left.is(tok::colon) && + (Left.Type == TT_DictLiteral || Left.Type == TT_ObjCMethodExpr)) return true; if (Right.Type == TT_ObjCSelectorName) return true; - if (Left.ClosesTemplateDeclaration) + if (Left.is(tok::r_paren) && Line.Type == LT_ObjCProperty) return true; - if (Right.Type == TT_ConditionalExpr || Right.is(tok::question)) + if (Left.ClosesTemplateDeclaration) return true; if (Right.Type == TT_RangeBasedForLoopColon || - Right.Type == TT_OverloadedOperatorLParen) + Right.Type == TT_OverloadedOperatorLParen || + Right.Type == TT_OverloadedOperator) return false; if (Left.Type == TT_RangeBasedForLoopColon) return true; if (Right.Type == TT_RangeBasedForLoopColon) return false; if (Left.Type == TT_PointerOrReference || Left.Type == TT_TemplateCloser || - Left.Type == TT_UnaryOperator || Left.Type == TT_ConditionalExpr || - Left.isOneOf(tok::question, tok::kw_operator)) + Left.Type == TT_UnaryOperator || Left.is(tok::kw_operator)) return false; if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl) return false; - if (Left.is(tok::l_paren) && Right.is(tok::l_paren) && Left.Parent && - Left.Parent->is(tok::kw___attribute)) + if (Left.Previous) { + if (Left.is(tok::l_paren) && Right.is(tok::l_paren) && + Left.Previous->is(tok::kw___attribute)) + return false; + if (Left.is(tok::l_paren) && (Left.Previous->Type == TT_BinaryOperator || + Left.Previous->Type == TT_CastRParen)) + return false; + } + if (Right.Type == TT_ImplicitStringLiteral) return false; - if (Right.Type == TT_LineComment) - // We rely on MustBreakBefore being set correctly here as we should not - // change the "binding" behavior of a comment. + if (Right.is(tok::r_paren) || Right.Type == TT_TemplateCloser) return false; + // We only break before r_brace if there was a corresponding break before + // the l_brace, which is tracked by BreakBeforeClosingBrace. + if (Right.is(tok::r_brace)) + return Right.MatchingParen && Right.MatchingParen->BlockKind == BK_Block; + // Allow breaking after a trailing 'const', e.g. after a method declaration, // unless it is follow by ';', '{' or '='. - if (Left.is(tok::kw_const) && Left.Parent != NULL && - Left.Parent->is(tok::r_paren)) + if (Left.is(tok::kw_const) && Left.Previous != NULL && + Left.Previous->is(tok::r_paren)) return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal); if (Right.is(tok::kw___attribute)) return true; - // We only break before r_brace if there was a corresponding break before - // the l_brace, which is tracked by BreakBeforeClosingBrace. - if (Right.isOneOf(tok::r_brace, tok::r_paren, tok::greater)) - return false; if (Left.is(tok::identifier) && Right.is(tok::string_literal)) return true; - return (Left.isBinaryOperator() && Left.isNot(tok::lessless)) || + + if (Left.Type == TT_CtorInitializerComma && + Style.BreakConstructorInitializersBeforeComma) + return false; + if (Right.Type == TT_CtorInitializerComma && + Style.BreakConstructorInitializersBeforeComma) + return true; + if (Right.isBinaryOperator() && Style.BreakBeforeBinaryOperators) + return true; + if (Left.is(tok::greater) && Right.is(tok::greater) && + Left.Type != TT_TemplateCloser) + return false; + if (Left.Type == TT_ArrayInitializerLSquare) + return true; + return (Left.isBinaryOperator() && Left.isNot(tok::lessless) && + !Style.BreakBeforeBinaryOperators) || Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace, tok::kw_class, tok::kw_struct) || - Right.isOneOf(tok::lessless, tok::arrow, tok::period, tok::colon) || - (Left.is(tok::r_paren) && Left.Type != TT_CastRParen && - Right.isOneOf(tok::identifier, tok::kw___attribute)) || - (Left.is(tok::l_paren) && !Right.is(tok::r_paren)) || - (Left.is(tok::l_square) && !Right.is(tok::r_square)); + Right.isOneOf(tok::lessless, tok::arrow, tok::period, tok::colon, + tok::l_square, tok::at) || + (Left.is(tok::r_paren) && + Right.isOneOf(tok::identifier, tok::kw_const, tok::kw___attribute)) || + (Left.is(tok::l_paren) && !Right.is(tok::r_paren)); } void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) { llvm::errs() << "AnnotatedTokens:\n"; - const AnnotatedToken *Tok = &Line.First; + const FormatToken *Tok = Line.First; while (Tok) { llvm::errs() << " M=" << Tok->MustBreakBefore << " C=" << Tok->CanBreakBefore << " T=" << Tok->Type << " S=" << Tok->SpacesRequiredBefore - << " P=" << Tok->SplitPenalty - << " Name=" << Tok->FormatTok.Tok.getName() << " FakeLParens="; + << " P=" << Tok->SplitPenalty << " Name=" << Tok->Tok.getName() + << " L=" << Tok->TotalLength << " PPK=" << Tok->PackingKind + << " FakeLParens="; for (unsigned i = 0, e = Tok->FakeLParens.size(); i != e; ++i) llvm::errs() << Tok->FakeLParens[i] << "/"; llvm::errs() << " FakeRParens=" << Tok->FakeRParens << "\n"; - Tok = Tok->Children.empty() ? NULL : &Tok->Children[0]; + if (Tok->Next == NULL) + assert(Tok == Line.Last); + Tok = Tok->Next; } llvm::errs() << "----\n"; } |