diff options
Diffstat (limited to 'lib/Format/TokenAnnotator.cpp')
-rw-r--r-- | lib/Format/TokenAnnotator.cpp | 1041 |
1 files changed, 640 insertions, 401 deletions
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 017afe1..4ba3f91 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -32,9 +32,9 @@ namespace { class AnnotatingParser { public: AnnotatingParser(const FormatStyle &Style, AnnotatedLine &Line, - IdentifierInfo &Ident_in) - : Style(Style), Line(Line), CurrentToken(Line.First), - KeywordVirtualFound(false), AutoFound(false), Ident_in(Ident_in) { + const AdditionalKeywords &Keywords) + : Style(Style), Line(Line), CurrentToken(Line.First), AutoFound(false), + Keywords(Keywords) { Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false)); resetTokenMetadata(CurrentToken); } @@ -51,6 +51,10 @@ private: Contexts.back().InTemplateArgument = Left->Previous && Left->Previous->Tok.isNot(tok::kw_template); + if (Style.Language == FormatStyle::LK_Java && + CurrentToken->is(tok::question)) + next(); + while (CurrentToken) { if (CurrentToken->is(tok::greater)) { Left->MatchingParen = CurrentToken; @@ -59,8 +63,13 @@ private: next(); return true; } + if (CurrentToken->is(tok::question) && + Style.Language == FormatStyle::LK_Java) { + next(); + continue; + } if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace, - tok::question, tok::colon)) + tok::colon, tok::question)) 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 @@ -69,12 +78,8 @@ private: // 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 && - // Toplevel bool expressions do not make lots of sense; - // If we're on the top level, it contains only the base context and - // the context for the current opening angle bracket. - Contexts.size() > 2) || - Contexts[Contexts.size() - 2].IsExpression) && + CurrentToken->Previous->is(TT_BinaryOperator) && + Contexts[Contexts.size() - 2].IsExpression && Line.First->isNot(tok::kw_template)) return false; updateParameterCount(Left, CurrentToken); @@ -109,17 +114,17 @@ private: if (Left->Previous && (Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_if, tok::kw_while, tok::l_paren, tok::comma) || - Left->Previous->Type == TT_BinaryOperator)) { + Left->Previous->is(TT_BinaryOperator))) { // static_assert, if and while usually contain expressions. Contexts.back().IsExpression = true; } else if (Line.InPPDirective && (!Left->Previous || - (Left->Previous->isNot(tok::identifier) && - Left->Previous->Type != TT_OverloadedOperator))) { + !Left->Previous->isOneOf(tok::identifier, + TT_OverloadedOperator))) { Contexts.back().IsExpression = true; } else if (Left->Previous && Left->Previous->is(tok::r_square) && Left->Previous->MatchingParen && - Left->Previous->MatchingParen->Type == TT_LambdaLSquare) { + Left->Previous->MatchingParen->is(TT_LambdaLSquare)) { // This is a parameter list of a lambda expression. Contexts.back().IsExpression = false; } else if (Contexts[Contexts.size() - 2].CaretFound) { @@ -131,6 +136,9 @@ private: // The first argument to a foreach macro is a declaration. Contexts.back().IsForEachMacro = true; Contexts.back().IsExpression = false; + } else if (Left->Previous && Left->Previous->MatchingParen && + Left->Previous->MatchingParen->is(TT_ObjCBlockLParen)) { + Contexts.back().IsExpression = false; } if (StartsObjCMethodExpr) { @@ -160,11 +168,11 @@ private: } } - if (CurrentToken->Previous->Type == TT_PointerOrReference && + if (CurrentToken->Previous->is(TT_PointerOrReference) && CurrentToken->Previous->Previous->isOneOf(tok::l_paren, tok::coloncolon)) MightBeFunctionType = true; - if (CurrentToken->Previous->Type == TT_BinaryOperator) + if (CurrentToken->Previous->is(TT_BinaryOperator)) Contexts.back().IsExpression = true; if (CurrentToken->is(tok::r_paren)) { if (MightBeFunctionType && CurrentToken->Next && @@ -183,8 +191,12 @@ private: } } - if (Left->Type == TT_AttributeParen) + if (Left->is(TT_AttributeParen)) CurrentToken->Type = TT_AttributeParen; + if (Left->Previous && Left->Previous->is(TT_JavaAnnotation)) + CurrentToken->Type = TT_JavaAnnotation; + if (Left->Previous && Left->Previous->is(TT_LeadingJavaAnnotation)) + CurrentToken->Type = TT_LeadingJavaAnnotation; if (!HasMultipleLines) Left->PackingKind = PPK_Inconclusive; @@ -227,12 +239,13 @@ private: FormatToken *Left = CurrentToken->Previous; FormatToken *Parent = Left->getPreviousNonComment(); bool StartsObjCMethodExpr = - Contexts.back().CanBeExpression && Left->Type != TT_LambdaLSquare && + Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) && CurrentToken->isNot(tok::l_brace) && - (!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 || + (!Parent || + Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren, + tok::kw_return, tok::kw_throw) || + Parent->isUnaryOperator() || + Parent->isOneOf(TT_ObjCForIn, TT_CastRParen) || getBinOpPrecedence(Parent->Tok.getKind(), true, true) > prec::Unknown); ScopedContextCreator ContextCreator(*this, tok::l_square, 10); Contexts.back().IsExpression = true; @@ -243,14 +256,14 @@ private: Left->Type = TT_ObjCMethodExpr; } else if (Parent && Parent->is(tok::at)) { Left->Type = TT_ArrayInitializerLSquare; - } else if (Left->Type == TT_Unknown) { + } else if (Left->is(TT_Unknown)) { Left->Type = TT_ArraySubscriptLSquare; } while (CurrentToken) { if (CurrentToken->is(tok::r_square)) { if (CurrentToken->Next && CurrentToken->Next->is(tok::l_paren) && - Left->Type == TT_ObjCMethodExpr) { + Left->is(TT_ObjCMethodExpr)) { // An ObjC method call is rarely followed by an open parenthesis. // FIXME: Do we incorrectly label ":" with this? StartsObjCMethodExpr = false; @@ -261,7 +274,7 @@ private: // determineStarAmpUsage() thinks that '*' '[' is allocating an // array of pointers, but if '[' starts a selector then '*' is a // binary operator. - if (Parent && Parent->Type == TT_PointerOrReference) + if (Parent && Parent->is(TT_PointerOrReference)) Parent->Type = TT_BinaryOperator; } Left->MatchingParen = CurrentToken; @@ -277,14 +290,22 @@ private: } if (CurrentToken->isOneOf(tok::r_paren, tok::r_brace)) return false; - if (CurrentToken->is(tok::colon)) + if (CurrentToken->is(tok::colon)) { + if (Left->is(TT_ArraySubscriptLSquare)) { + Left->Type = TT_ObjCMethodExpr; + StartsObjCMethodExpr = true; + Contexts.back().ColonIsObjCMethodExpr = true; + if (Parent && Parent->is(tok::r_paren)) + Parent->Type = TT_CastRParen; + } ColonFound = true; + } if (CurrentToken->is(tok::comma) && Style.Language != FormatStyle::LK_Proto && - (Left->Type == TT_ArraySubscriptLSquare || - (Left->Type == TT_ObjCMethodExpr && !ColonFound))) + (Left->is(TT_ArraySubscriptLSquare) || + (Left->is(TT_ObjCMethodExpr) && !ColonFound))) Left->Type = TT_ArrayInitializerLSquare; - FormatToken* Tok = CurrentToken; + FormatToken *Tok = CurrentToken; if (!consumeToken()) return false; updateParameterCount(Left, Tok); @@ -315,11 +336,14 @@ private: if (CurrentToken->isOneOf(tok::r_paren, tok::r_square)) return false; updateParameterCount(Left, CurrentToken); - if (CurrentToken->is(tok::colon) && - Style.Language != FormatStyle::LK_Proto) { - if (CurrentToken->getPreviousNonComment()->is(tok::identifier)) - CurrentToken->getPreviousNonComment()->Type = TT_SelectorName; - Left->Type = TT_DictLiteral; + if (CurrentToken->isOneOf(tok::colon, tok::l_brace)) { + FormatToken *Previous = CurrentToken->getPreviousNonComment(); + if ((CurrentToken->is(tok::colon) || + Style.Language == FormatStyle::LK_Proto) && + Previous->is(tok::identifier)) + Previous->Type = TT_SelectorName; + if (CurrentToken->is(tok::colon)) + Left->Type = TT_DictLiteral; } if (!consumeToken()) return false; @@ -329,10 +353,10 @@ private: } void updateParameterCount(FormatToken *Left, FormatToken *Current) { - if (Current->Type == TT_LambdaLSquare || - (Current->is(tok::caret) && Current->Type == TT_UnaryOperator) || + if (Current->is(TT_LambdaLSquare) || + (Current->is(tok::caret) && Current->is(TT_UnaryOperator)) || (Style.Language == FormatStyle::LK_JavaScript && - Current->TokenText == "function")) { + Current->is(Keywords.kw_function))) { ++Left->BlockParameterCount; } if (Current->is(tok::comma)) { @@ -390,7 +414,7 @@ private: } else if (Contexts.back().ColonIsDictLiteral) { Tok->Type = TT_DictLiteral; } else if (Contexts.back().ColonIsObjCMethodExpr || - Line.First->Type == TT_ObjCMethodSpecifier) { + Line.First->is(TT_ObjCMethodSpecifier)) { Tok->Type = TT_ObjCMethodExpr; Tok->Previous->Type = TT_SelectorName; if (Tok->Previous->ColumnWidth > @@ -406,6 +430,11 @@ private: } else if (Contexts.size() == 1 && !Line.First->isOneOf(tok::kw_enum, tok::kw_case)) { Tok->Type = TT_InheritanceColon; + } else if (Tok->Previous->is(tok::identifier) && Tok->Next && + Tok->Next->isOneOf(tok::r_paren, tok::comma)) { + // This handles a special macro in ObjC code where selectors including + // the colon are passed as macro arguments. + Tok->Type = TT_ObjCMethodExpr; } else if (Contexts.back().ContextKind == tok::l_paren) { Tok->Type = TT_InlineASMColon; } @@ -428,9 +457,9 @@ private: if (!parseParens()) return false; if (Line.MustBeDeclaration && Contexts.size() == 1 && - !Contexts.back().IsExpression && - Line.First->Type != TT_ObjCProperty && - (!Tok->Previous || Tok->Previous->isNot(tok::kw_decltype))) + !Contexts.back().IsExpression && Line.First->isNot(TT_ObjCProperty) && + (!Tok->Previous || + !Tok->Previous->isOneOf(tok::kw_decltype, TT_LeadingJavaAnnotation))) Line.MightBeFunctionDecl = true; break; case tok::l_square: @@ -442,9 +471,12 @@ private: return false; break; case tok::less: - if (Tok->Previous && !Tok->Previous->Tok.isLiteral() && parseAngle()) + if ((!Tok->Previous || + (!Tok->Previous->Tok.isLiteral() && + !(Tok->Previous->is(tok::r_paren) && Contexts.size() > 1))) && + parseAngle()) { Tok->Type = TT_TemplateOpener; - else { + } else { Tok->Type = TT_BinaryOperator; CurrentToken = Tok; next(); @@ -467,12 +499,12 @@ private: if (CurrentToken->isOneOf(tok::star, tok::amp)) CurrentToken->Type = TT_PointerOrReference; consumeToken(); - if (CurrentToken && CurrentToken->Previous->Type == TT_BinaryOperator) + if (CurrentToken && CurrentToken->Previous->is(TT_BinaryOperator)) CurrentToken->Previous->Type = TT_OverloadedOperator; } if (CurrentToken) { CurrentToken->Type = TT_OverloadedOperatorLParen; - if (CurrentToken->Previous->Type == TT_BinaryOperator) + if (CurrentToken->Previous->is(TT_BinaryOperator)) CurrentToken->Previous->Type = TT_OverloadedOperator; } break; @@ -483,8 +515,8 @@ private: parseTemplateDeclaration(); break; case tok::identifier: - if (Line.First->is(tok::kw_for) && - Tok->Tok.getIdentifierInfo() == &Ident_in) + if (Line.First->is(tok::kw_for) && Tok->is(Keywords.kw_in) && + Tok->Previous->isNot(tok::colon)) Tok->Type = TT_ObjCForIn; break; case tok::comma: @@ -502,7 +534,6 @@ private: } void parseIncludeDirective() { - next(); if (CurrentToken && CurrentToken->is(tok::less)) { next(); while (CurrentToken) { @@ -510,14 +541,6 @@ private: CurrentToken->Type = TT_ImplicitStringLiteral; next(); } - } else { - while (CurrentToken) { - if (CurrentToken->is(tok::string_literal)) - // Mark these string literals as "implicit" literals, too, so that - // they are not split or line-wrapped. - CurrentToken->Type = TT_ImplicitStringLiteral; - next(); - } } } @@ -544,22 +567,25 @@ private: } } - void parsePreprocessorDirective() { + LineType parsePreprocessorDirective() { + LineType Type = LT_PreprocessorDirective; next(); if (!CurrentToken) - return; + return Type; if (CurrentToken->Tok.is(tok::numeric_constant)) { CurrentToken->SpacesRequiredBefore = 1; - return; + return Type; } // Hashes in the middle of a line can lead to any strange token // sequence. if (!CurrentToken->Tok.getIdentifierInfo()) - return; + return Type; switch (CurrentToken->Tok.getIdentifierInfo()->getPPKeywordID()) { case tok::pp_include: case tok::pp_import: + next(); parseIncludeDirective(); + Type = LT_ImportStatement; break; case tok::pp_error: case tok::pp_warning: @@ -578,33 +604,53 @@ private: } while (CurrentToken) next(); + return Type; } public: LineType parseLine() { if (CurrentToken->is(tok::hash)) { - parsePreprocessorDirective(); - return LT_PreprocessorDirective; + return parsePreprocessorDirective(); } // Directly allow to 'import <string-literal>' to support protocol buffer // definitions (code.google.com/p/protobuf) or missing "#" (either way we // should not break the line). IdentifierInfo *Info = CurrentToken->Tok.getIdentifierInfo(); - if (Info && Info->getPPKeywordID() == tok::pp_import && - CurrentToken->Next && CurrentToken->Next->is(tok::string_literal)) + if ((Style.Language == FormatStyle::LK_Java && + CurrentToken->is(Keywords.kw_package)) || + (Info && Info->getPPKeywordID() == tok::pp_import && + CurrentToken->Next && + CurrentToken->Next->isOneOf(tok::string_literal, tok::identifier, + tok::kw_static))) { + next(); parseIncludeDirective(); + return LT_ImportStatement; + } + // If this line starts and ends in '<' and '>', respectively, it is likely + // part of "#define <a/b.h>". + if (CurrentToken->is(tok::less) && Line.Last->is(tok::greater)) { + parseIncludeDirective(); + return LT_ImportStatement; + } + + bool KeywordVirtualFound = false; + bool ImportStatement = false; while (CurrentToken) { if (CurrentToken->is(tok::kw_virtual)) KeywordVirtualFound = true; + if (IsImportStatement(*CurrentToken)) + ImportStatement = true; if (!consumeToken()) return LT_Invalid; } if (KeywordVirtualFound) return LT_VirtualFunctionDecl; + if (ImportStatement) + return LT_ImportStatement; - if (Line.First->Type == TT_ObjCMethodSpecifier) { + if (Line.First->is(TT_ObjCMethodSpecifier)) { if (Contexts.back().FirstObjCSelectorName) Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = Contexts.back().LongestObjCSelectorName; @@ -615,17 +661,26 @@ public: } private: + bool IsImportStatement(const FormatToken &Tok) { + // FIXME: Closure-library specific stuff should not be hard-coded but be + // configurable. + return Style.Language == FormatStyle::LK_JavaScript && + Tok.TokenText == "goog" && Tok.Next && Tok.Next->is(tok::period) && + Tok.Next->Next && (Tok.Next->Next->TokenText == "module" || + Tok.Next->Next->TokenText == "require" || + Tok.Next->Next->TokenText == "provide") && + Tok.Next->Next->Next && Tok.Next->Next->Next->is(tok::l_paren); + } + void resetTokenMetadata(FormatToken *Token) { if (!Token) return; // 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_FunctionLBrace && - CurrentToken->Type != TT_ImplicitStringLiteral && - CurrentToken->Type != TT_RegexLiteral && - CurrentToken->Type != TT_TrailingReturnArrow) + if (!CurrentToken->isOneOf(TT_LambdaLSquare, TT_FunctionLBrace, + TT_ImplicitStringLiteral, TT_RegexLiteral, + TT_TrailingReturnArrow)) CurrentToken->Type = TT_Unknown; CurrentToken->Role.reset(); CurrentToken->FakeLParens.clear(); @@ -634,9 +689,10 @@ private: void next() { if (CurrentToken) { - determineTokenType(*CurrentToken); - CurrentToken->BindingStrength = Contexts.back().BindingStrength; CurrentToken->NestingLevel = Contexts.size() - 1; + CurrentToken->BindingStrength = Contexts.back().BindingStrength; + modifyContext(*CurrentToken); + determineTokenType(*CurrentToken); CurrentToken = CurrentToken->Next; } @@ -688,23 +744,29 @@ private: ~ScopedContextCreator() { P.Contexts.pop_back(); } }; - void determineTokenType(FormatToken &Current) { + void modifyContext(const FormatToken &Current) { if (Current.getPrecedence() == prec::Assignment && - !Line.First->isOneOf(tok::kw_template, tok::kw_using) && + !Line.First->isOneOf(tok::kw_template, tok::kw_using, + TT_UnaryOperator) && (!Current.Previous || Current.Previous->isNot(tok::kw_operator))) { Contexts.back().IsExpression = true; for (FormatToken *Previous = Current.Previous; Previous && !Previous->isOneOf(tok::comma, tok::semi); Previous = Previous->Previous) { - if (Previous->isOneOf(tok::r_square, tok::r_paren)) + if (Previous->isOneOf(tok::r_square, tok::r_paren)) { Previous = Previous->MatchingParen; - if (Previous->Type == TT_BinaryOperator && - Previous->isOneOf(tok::star, tok::amp)) { - Previous->Type = TT_PointerOrReference; + if (!Previous) + break; } + if (Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator) && + Previous->isOneOf(tok::star, tok::amp) && Previous->Previous && + Previous->Previous->isNot(tok::equal)) + Previous->Type = TT_PointerOrReference; } } else if (Current.isOneOf(tok::kw_return, tok::kw_throw)) { Contexts.back().IsExpression = true; + } else if (Current.is(TT_TrailingReturnArrow)) { + Contexts.back().IsExpression = false; } else if (Current.is(tok::l_paren) && !Line.MustBeDeclaration && !Line.InPPDirective && (!Current.Previous || @@ -712,7 +774,7 @@ private: bool ParametersOfFunctionType = Current.Previous && Current.Previous->is(tok::r_paren) && Current.Previous->MatchingParen && - Current.Previous->MatchingParen->Type == TT_FunctionTypeLParen; + Current.Previous->MatchingParen->is(TT_FunctionTypeLParen); bool IsForOrCatch = Current.Previous && Current.Previous->isOneOf(tok::kw_for, tok::kw_catch); Contexts.back().IsExpression = !ParametersOfFunctionType && !IsForOrCatch; @@ -721,8 +783,10 @@ private: Previous && Previous->isOneOf(tok::star, tok::amp); Previous = Previous->Previous) Previous->Type = TT_PointerOrReference; + if (Line.MustBeDeclaration) + Contexts.back().IsExpression = Contexts.front().InCtorInitializer; } else if (Current.Previous && - Current.Previous->Type == TT_CtorInitializerColon) { + Current.Previous->is(TT_CtorInitializerColon)) { Contexts.back().IsExpression = true; Contexts.back().InCtorInitializer = true; } else if (Current.is(tok::kw_new)) { @@ -731,70 +795,99 @@ private: // This should be the condition or increment in a for-loop. Contexts.back().IsExpression = true; } + } + + void determineTokenType(FormatToken &Current) { + if (!Current.is(TT_Unknown)) + // The token type is already known. + return; - if (Current.Type == TT_Unknown) { + // 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 (Current.is(Keywords.kw_instanceof)) { + Current.Type = TT_BinaryOperator; + } else if (isStartOfName(Current) && + (!Line.MightBeFunctionDecl || Current.NestingLevel != 0)) { + Contexts.back().FirstStartOfName = &Current; + Current.Type = TT_StartOfName; + } else if (Current.is(tok::kw_auto)) { + AutoFound = true; + } else if (Current.is(tok::arrow) && + Style.Language == FormatStyle::LK_Java) { + Current.Type = TT_LambdaArrow; + } else if (Current.is(tok::arrow) && AutoFound && Line.MustBeDeclaration && + Current.NestingLevel == 0) { + Current.Type = TT_TrailingReturnArrow; + } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) { + Current.Type = + determineStarAmpUsage(Current, Contexts.back().CanBeExpression && + Contexts.back().IsExpression, + Contexts.back().InTemplateArgument); + } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) { + Current.Type = determinePlusMinusCaretUsage(Current); + if (Current.is(TT_UnaryOperator) && Current.is(tok::caret)) + Contexts.back().CaretFound = true; + } else if (Current.isOneOf(tok::minusminus, tok::plusplus)) { + Current.Type = determineIncrementUsage(Current); + } else if (Current.isOneOf(tok::exclaim, tok::tilde)) { + Current.Type = TT_UnaryOperator; + } else if (Current.is(tok::question)) { + Current.Type = TT_ConditionalExpr; + } else if (Current.isBinaryOperator() && + (!Current.Previous || Current.Previous->isNot(tok::l_square))) { + Current.Type = TT_BinaryOperator; + } else if (Current.is(tok::comment)) { + if (Current.TokenText.startswith("//")) + Current.Type = TT_LineComment; + else + Current.Type = TT_BlockComment; + } else if (Current.is(tok::r_paren)) { + if (rParenEndsCast(Current)) + Current.Type = TT_CastRParen; + } 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: + Current.Type = TT_ObjCDecl; + break; + case tok::objc_property: + Current.Type = TT_ObjCProperty; + break; + 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; + else if (Style.Language == FormatStyle::LK_Java && Current.Previous && + Current.Previous->isOneOf(TT_JavaAnnotation, + TT_LeadingJavaAnnotation)) { + Current.Type = Current.Previous->Type; + } + } else if (Current.isOneOf(tok::identifier, tok::kw_const) && + Current.Previous && + !Current.Previous->isOneOf(tok::equal, tok::at) && + Line.MightBeFunctionDecl && Contexts.size() == 1) { // 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; - } 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().CanBeExpression && - Contexts.back().IsExpression, - Contexts.back().InTemplateArgument); - } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) { - Current.Type = determinePlusMinusCaretUsage(Current); - if (Current.Type == TT_UnaryOperator && Current.is(tok::caret)) - Contexts.back().CaretFound = true; - } 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.is(tok::question)) { - Current.Type = TT_ConditionalExpr; - } else if (Current.isBinaryOperator() && - (!Current.Previous || - Current.Previous->isNot(tok::l_square))) { - Current.Type = TT_BinaryOperator; - } else if (Current.is(tok::comment)) { - if (Current.TokenText.startswith("//")) - Current.Type = TT_LineComment; + // function declaration have been found. + Current.Type = TT_TrailingAnnotation; + } else if (Style.Language == FormatStyle::LK_Java && Current.Previous) { + if (Current.Previous->is(tok::at) && + Current.isNot(Keywords.kw_interface)) { + const FormatToken &AtToken = *Current.Previous; + const FormatToken *Previous = AtToken.getPreviousNonComment(); + if (!Previous || Previous->is(TT_LeadingJavaAnnotation)) + Current.Type = TT_LeadingJavaAnnotation; else - Current.Type = TT_BlockComment; - } else if (Current.is(tok::r_paren)) { - if (rParenEndsCast(Current)) - Current.Type = TT_CastRParen; - } 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: - Current.Type = TT_ObjCDecl; - break; - case tok::objc_property: - Current.Type = TT_ObjCProperty; - break; - 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; - } else if (Current.isOneOf(tok::identifier, tok::kw_const) && - Current.Previous && Current.Previous->isNot(tok::equal) && - Line.MightBeFunctionDecl && Contexts.size() == 1) { - // Line.MightBeFunctionDecl can only be true after the parentheses of a - // function declaration have been found. - Current.Type = TT_TrailingAnnotation; + Current.Type = TT_JavaAnnotation; + } else if (Current.Previous->is(tok::period) && + Current.Previous->isOneOf(TT_JavaAnnotation, + TT_LeadingJavaAnnotation)) { + Current.Type = Current.Previous->Type; } } } @@ -808,6 +901,9 @@ private: if (Tok.isNot(tok::identifier) || !Tok.Previous) return false; + if (Tok.Previous->is(TT_LeadingJavaAnnotation)) + return false; + // Skip "const" as it does not have an influence on whether this is a name. FormatToken *PreviousNotConst = Tok.Previous; while (PreviousNotConst && PreviousNotConst->is(tok::kw_const)) @@ -820,9 +916,10 @@ private: PreviousNotConst->Previous && PreviousNotConst->Previous->is(tok::hash); - if (PreviousNotConst->Type == TT_TemplateCloser) + if (PreviousNotConst->is(TT_TemplateCloser)) return PreviousNotConst && PreviousNotConst->MatchingParen && PreviousNotConst->MatchingParen->Previous && + PreviousNotConst->MatchingParen->Previous->isNot(tok::period) && PreviousNotConst->MatchingParen->Previous->isNot(tok::kw_template); if (PreviousNotConst->is(tok::r_paren) && PreviousNotConst->MatchingParen && @@ -831,7 +928,7 @@ private: return true; return (!IsPPKeyword && PreviousNotConst->is(tok::identifier)) || - PreviousNotConst->Type == TT_PointerOrReference || + PreviousNotConst->is(TT_PointerOrReference) || PreviousNotConst->isSimpleTypeSpecifier(); } @@ -840,14 +937,28 @@ private: FormatToken *LeftOfParens = nullptr; if (Tok.MatchingParen) LeftOfParens = Tok.MatchingParen->getPreviousNonComment(); - if (LeftOfParens && LeftOfParens->is(tok::r_paren)) + if (LeftOfParens && LeftOfParens->is(tok::r_paren) && + LeftOfParens->MatchingParen) + LeftOfParens = LeftOfParens->MatchingParen->Previous; + if (LeftOfParens && LeftOfParens->is(tok::r_square) && + LeftOfParens->MatchingParen && + LeftOfParens->MatchingParen->is(TT_LambdaLSquare)) return false; + if (Tok.Next) { + if (Tok.Next->is(tok::question)) + return false; + if (Style.Language == FormatStyle::LK_JavaScript && + Tok.Next->is(Keywords.kw_in)) + return false; + if (Style.Language == FormatStyle::LK_Java && Tok.Next->is(tok::l_paren)) + return true; + } bool IsCast = false; bool ParensAreEmpty = Tok.Previous == Tok.MatchingParen; - bool ParensAreType = !Tok.Previous || - Tok.Previous->Type == TT_PointerOrReference || - Tok.Previous->Type == TT_TemplateCloser || - Tok.Previous->isSimpleTypeSpecifier(); + bool ParensAreType = + !Tok.Previous || + Tok.Previous->isOneOf(TT_PointerOrReference, TT_TemplateCloser) || + Tok.Previous->isSimpleTypeSpecifier(); bool ParensCouldEndDecl = Tok.Next && Tok.Next->isOneOf(tok::equal, tok::semi, tok::l_brace); bool IsSizeOfOrAlignOf = @@ -862,12 +973,11 @@ private: IsCast = true; // If there is an identifier after the (), it is likely a cast, unless // there is also an identifier before the (). - else if (LeftOfParens && + else if (LeftOfParens && Tok.Next && (LeftOfParens->Tok.getIdentifierInfo() == nullptr || LeftOfParens->is(tok::kw_return)) && - LeftOfParens->Type != TT_OverloadedOperator && - LeftOfParens->isNot(tok::at) && - LeftOfParens->Type != TT_TemplateCloser && Tok.Next) { + !LeftOfParens->isOneOf(TT_OverloadedOperator, tok::at, + TT_TemplateCloser)) { if (Tok.Next->isOneOf(tok::identifier, tok::numeric_constant)) { IsCast = true; } else { @@ -879,8 +989,9 @@ private: if (Prev && Tok.Next && Tok.Next->Next) { bool NextIsUnary = Tok.Next->isUnaryOperator() || Tok.Next->isOneOf(tok::amp, tok::star); - IsCast = NextIsUnary && Tok.Next->Next->isOneOf( - tok::identifier, tok::numeric_constant); + IsCast = + NextIsUnary && !Tok.Next->is(tok::plus) && + Tok.Next->Next->isOneOf(tok::identifier, tok::numeric_constant); } for (; Prev != Tok.MatchingParen; Prev = Prev->Previous) { @@ -897,29 +1008,31 @@ private: /// \brief Return the type of the given token assuming it is * or &. TokenType determineStarAmpUsage(const FormatToken &Tok, bool IsExpression, bool InTemplateArgument) { + if (Style.Language == FormatStyle::LK_JavaScript) + return TT_BinaryOperator; + const FormatToken *PrevToken = Tok.getPreviousNonComment(); if (!PrevToken) return TT_UnaryOperator; const FormatToken *NextToken = Tok.getNextNonComment(); - if (!NextToken || NextToken->is(tok::l_brace)) + if (!NextToken || + (NextToken->is(tok::l_brace) && !NextToken->getNextNonComment())) return TT_Unknown; - if (PrevToken->is(tok::coloncolon) || - (PrevToken->is(tok::l_paren) && !IsExpression)) + if (PrevToken->is(tok::coloncolon)) 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::kw_delete, tok::kw_sizeof) || - PrevToken->Type == TT_BinaryOperator || - PrevToken->Type == TT_ConditionalExpr || - PrevToken->Type == TT_UnaryOperator || PrevToken->Type == TT_CastRParen) + PrevToken->isOneOf(TT_BinaryOperator, TT_ConditionalExpr, + TT_UnaryOperator, TT_CastRParen)) return TT_UnaryOperator; - if (NextToken->is(tok::l_square) && NextToken->Type != TT_LambdaLSquare) + if (NextToken->is(tok::l_square) && NextToken->isNot(TT_LambdaLSquare)) return TT_PointerOrReference; - if (NextToken->is(tok::kw_operator)) + if (NextToken->isOneOf(tok::kw_operator, tok::comma)) return TT_PointerOrReference; if (PrevToken->is(tok::r_paren) && PrevToken->MatchingParen && @@ -930,7 +1043,7 @@ private: if (PrevToken->Tok.isLiteral() || PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::kw_true, - tok::kw_false) || + tok::kw_false, tok::r_brace) || NextToken->Tok.isLiteral() || NextToken->isOneOf(tok::kw_true, tok::kw_false) || NextToken->isUnaryOperator() || @@ -940,6 +1053,10 @@ private: (InTemplateArgument && NextToken->Tok.isAnyIdentifier())) return TT_BinaryOperator; + // "&&(" is quite unlikely to be two successive unary "&". + if (Tok.is(tok::ampamp) && NextToken && NextToken->is(tok::l_paren)) + return TT_BinaryOperator; + // This catches some cases where evaluation order is used as control flow: // aaa && aaa->f(); const FormatToken *NextNextToken = NextToken->getNextNonComment(); @@ -948,7 +1065,7 @@ private: // It is very unlikely that we are going to find a pointer or reference type // definition on the RHS of an assignment. - if (IsExpression) + if (IsExpression && !Contexts.back().CaretFound) return TT_BinaryOperator; return TT_PointerOrReference; @@ -956,7 +1073,7 @@ private: TokenType determinePlusMinusCaretUsage(const FormatToken &Tok) { const FormatToken *PrevToken = Tok.getPreviousNonComment(); - if (!PrevToken || PrevToken->Type == TT_CastRParen) + if (!PrevToken || PrevToken->is(TT_CastRParen)) return TT_UnaryOperator; // Use heuristics to recognize unary operators. @@ -966,7 +1083,7 @@ private: return TT_UnaryOperator; // There can't be two consecutive binary operators. - if (PrevToken->Type == TT_BinaryOperator) + if (PrevToken->is(TT_BinaryOperator)) return TT_UnaryOperator; // Fall back to marking the token as binary operator. @@ -976,7 +1093,7 @@ private: /// \brief Determine whether ++/-- are pre- or post-increments/-decrements. TokenType determineIncrementUsage(const FormatToken &Tok) { const FormatToken *PrevToken = Tok.getPreviousNonComment(); - if (!PrevToken || PrevToken->Type == TT_CastRParen) + if (!PrevToken || PrevToken->is(TT_CastRParen)) return TT_UnaryOperator; if (PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::identifier)) return TT_TrailingUnaryOperator; @@ -989,9 +1106,8 @@ private: const FormatStyle &Style; AnnotatedLine &Line; FormatToken *CurrentToken; - bool KeywordVirtualFound; bool AutoFound; - IdentifierInfo &Ident_in; + const AdditionalKeywords &Keywords; }; static int PrecedenceUnaryOperator = prec::PointerToMember + 1; @@ -1001,20 +1117,17 @@ static int PrecedenceArrowAndPeriod = prec::PointerToMember + 2; /// operator precedence. class ExpressionParser { public: - ExpressionParser(AnnotatedLine &Line) : Current(Line.First) { - // Skip leading "}", e.g. in "} else if (...) {". - if (Current->is(tok::r_brace)) - next(); - } + ExpressionParser(const FormatStyle &Style, const AdditionalKeywords &Keywords, + AnnotatedLine &Line) + : Style(Style), Keywords(Keywords), Current(Line.First) {} /// \brief Parse expressions with the given operatore precedence. void parse(int Precedence = 0) { // 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 || - Current->Type == TT_DictLiteral)))) + while (Current && (Current->is(tok::kw_return) || + (Current->is(tok::colon) && + Current->isOneOf(TT_ObjCMethodExpr, TT_DictLiteral)))) next(); if (!Current || Precedence > PrecedenceArrowAndPeriod) @@ -1043,7 +1156,7 @@ public: int CurrentPrecedence = getCurrentPrecedence(); - if (Current && Current->Type == TT_SelectorName && + if (Current && Current->is(TT_SelectorName) && Precedence == CurrentPrecedence) { if (LatestOperator) addFakeParenthesis(Start, prec::Level(Precedence)); @@ -1052,18 +1165,11 @@ public: // At the end of the line or when an operator with higher precedence is // found, insert fake parenthesis and return. - if (!Current || Current->closesScope() || - (CurrentPrecedence != -1 && CurrentPrecedence < Precedence)) { - if (LatestOperator) { - LatestOperator->LastOperator = true; - if (Precedence == PrecedenceArrowAndPeriod) { - // Call expressions don't have a binary operator precedence. - addFakeParenthesis(Start, prec::Unknown); - } else { - addFakeParenthesis(Start, prec::Level(Precedence)); - } - } - return; + if (!Current || (Current->closesScope() && Current->MatchingParen) || + (CurrentPrecedence != -1 && CurrentPrecedence < Precedence) || + (CurrentPrecedence == prec::Conditional && + Precedence == prec::Assignment && Current->is(tok::colon))) { + break; } // Consume scopes: (), [], <> and {} @@ -1080,8 +1186,17 @@ public: Current->OperatorIndex = OperatorIndex; ++OperatorIndex; } + next(/*SkipPastLeadingComments=*/Precedence > 0); + } + } - next(); + if (LatestOperator && (Current || Precedence > 0)) { + LatestOperator->LastOperator = true; + if (Precedence == PrecedenceArrowAndPeriod) { + // Call expressions don't have a binary operator precedence. + addFakeParenthesis(Start, prec::Unknown); + } else { + addFakeParenthesis(Start, prec::Level(Precedence)); } } } @@ -1091,17 +1206,29 @@ private: /// and other tokens that we treat like binary operators. int getCurrentPrecedence() { if (Current) { - if (Current->Type == TT_ConditionalExpr) + const FormatToken *NextNonComment = Current->getNextNonComment(); + if (Current->is(TT_ConditionalExpr)) return prec::Conditional; - else if (Current->is(tok::semi) || Current->Type == TT_InlineASMColon || - Current->Type == TT_SelectorName) + else if (NextNonComment && NextNonComment->is(tok::colon) && + NextNonComment->is(TT_DictLiteral)) + return prec::Comma; + else if (Current->is(TT_LambdaArrow)) + return prec::Comma; + else if (Current->isOneOf(tok::semi, TT_InlineASMColon, + TT_SelectorName) || + (Current->is(tok::comment) && NextNonComment && + NextNonComment->is(TT_SelectorName))) return 0; - else if (Current->Type == TT_RangeBasedForLoopColon) + else if (Current->is(TT_RangeBasedForLoopColon)) return prec::Comma; - else if (Current->Type == TT_BinaryOperator || Current->is(tok::comma)) + else if (Current->is(TT_BinaryOperator) || Current->is(tok::comma)) return Current->getPrecedence(); else if (Current->isOneOf(tok::period, tok::arrow)) return PrecedenceArrowAndPeriod; + else if (Style.Language == FormatStyle::LK_Java && + Current->isOneOf(Keywords.kw_extends, Keywords.kw_implements, + Keywords.kw_throws)) + return 0; } return -1; } @@ -1111,16 +1238,19 @@ private: if (Precedence > prec::Unknown) Start->StartsBinaryExpression = true; if (Current) { - ++Current->Previous->FakeRParens; + FormatToken *Previous = Current->Previous; + while (Previous->is(tok::comment) && Previous->Previous) + Previous = Previous->Previous; + ++Previous->FakeRParens; if (Precedence > prec::Unknown) - Current->Previous->EndsBinaryExpression = true; + Previous->EndsBinaryExpression = true; } } /// \brief Parse unary operator expressions and surround them with fake /// parentheses if appropriate. void parseUnaryOperator() { - if (!Current || Current->Type != TT_UnaryOperator) { + if (!Current || Current->isNot(TT_UnaryOperator)) { parse(PrecedenceArrowAndPeriod); return; } @@ -1134,33 +1264,40 @@ private: } void parseConditionalExpr() { + while (Current && Current->isTrailingComment()) { + next(); + } FormatToken *Start = Current; parse(prec::LogicalOr); if (!Current || !Current->is(tok::question)) return; next(); - parseConditionalExpr(); - if (!Current || Current->Type != TT_ConditionalExpr) + parse(prec::Assignment); + if (!Current || Current->isNot(TT_ConditionalExpr)) return; next(); - parseConditionalExpr(); + parse(prec::Assignment); addFakeParenthesis(Start, prec::Conditional); } - void next() { + void next(bool SkipPastLeadingComments = true) { if (Current) Current = Current->Next; - while (Current && Current->isTrailingComment()) + while (Current && + (Current->NewlinesBefore == 0 || SkipPastLeadingComments) && + Current->isTrailingComment()) Current = Current->Next; } + const FormatStyle &Style; + const AdditionalKeywords &Keywords; FormatToken *Current; }; } // end anonymous namespace -void -TokenAnnotator::setCommentLineLevels(SmallVectorImpl<AnnotatedLine *> &Lines) { +void TokenAnnotator::setCommentLineLevels( + SmallVectorImpl<AnnotatedLine *> &Lines) { const AnnotatedLine *NextNonCommentLine = nullptr; for (SmallVectorImpl<AnnotatedLine *>::reverse_iterator I = Lines.rbegin(), E = Lines.rend(); @@ -1181,19 +1318,19 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) { I != E; ++I) { annotate(**I); } - AnnotatingParser Parser(Style, Line, Ident_in); + AnnotatingParser Parser(Style, Line, Keywords); Line.Type = Parser.parseLine(); if (Line.Type == LT_Invalid) return; - ExpressionParser ExprParser(Line); + ExpressionParser ExprParser(Style, Keywords, Line); ExprParser.parse(); - if (Line.First->Type == TT_ObjCMethodSpecifier) + if (Line.First->is(TT_ObjCMethodSpecifier)) Line.Type = LT_ObjCMethodDecl; - else if (Line.First->Type == TT_ObjCDecl) + else if (Line.First->is(TT_ObjCDecl)) Line.Type = LT_ObjCDecl; - else if (Line.First->Type == TT_ObjCProperty) + else if (Line.First->is(TT_ObjCProperty)) Line.Type = LT_ObjCProperty; Line.First->SpacesRequiredBefore = 1; @@ -1203,13 +1340,11 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) { // This function heuristically determines whether 'Current' starts the name of a // function declaration. static bool isFunctionDeclarationName(const FormatToken &Current) { - if (Current.Type != TT_StartOfName || - Current.NestingLevel != 0 || - Current.Previous->Type == TT_StartOfName) + if (!Current.is(TT_StartOfName) || Current.NestingLevel != 0) return false; const FormatToken *Next = Current.Next; for (; Next; Next = Next->Next) { - if (Next->Type == TT_TemplateOpener) { + if (Next->is(TT_TemplateOpener)) { Next = Next->MatchingParen; } else if (Next->is(tok::coloncolon)) { Next = Next->Next; @@ -1229,7 +1364,7 @@ static bool isFunctionDeclarationName(const FormatToken &Current) { for (const FormatToken *Tok = Next->Next; Tok != Next->MatchingParen; Tok = Tok->Next) { if (Tok->is(tok::kw_const) || Tok->isSimpleTypeSpecifier() || - Tok->Type == TT_PointerOrReference || Tok->Type == TT_StartOfName) + Tok->isOneOf(TT_PointerOrReference, TT_StartOfName)) return true; if (Tok->isOneOf(tok::l_brace, tok::string_literal) || Tok->Tok.isLiteral()) return false; @@ -1253,7 +1388,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { while (Current) { if (isFunctionDeclarationName(*Current)) Current->Type = TT_FunctionDeclarationName; - if (Current->Type == TT_LineComment) { + if (Current->is(TT_LineComment)) { if (Current->Previous->BlockKind == BK_BracedInit && Current->Previous->opensScope()) Current->SpacesRequiredBefore = Style.Cpp11BracedListStyle ? 0 : 1; @@ -1273,7 +1408,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { if (Parameter->isOneOf(tok::comment, tok::r_brace)) break; if (Parameter->Previous && Parameter->Previous->is(tok::comma)) { - if (Parameter->Previous->Type != TT_CtorInitializerComma && + if (!Parameter->Previous->is(TT_CtorInitializerComma) && Parameter->HasUnescapedNewline) Parameter->MustBreakBefore = true; break; @@ -1288,6 +1423,13 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { Current->MustBreakBefore = Current->MustBreakBefore || mustBreakBefore(Line, *Current); + if (Style.AlwaysBreakAfterDefinitionReturnType && InFunctionDecl && + Current->is(TT_FunctionDeclarationName) && + !Line.Last->isOneOf(tok::semi, tok::comment)) // Only for definitions. + // FIXME: Line.Last points to other characters than tok::semi + // and tok::lbrace. + Current->MustBreakBefore = true; + Current->CanBreakBefore = Current->MustBreakBefore || canBreakBefore(Line, *Current); unsigned ChildSize = 0; @@ -1296,15 +1438,17 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { ChildSize = LastOfChild.isTrailingComment() ? Style.ColumnLimit : LastOfChild.TotalLength + 1; } - if (Current->MustBreakBefore || Current->Previous->Children.size() > 1 || + const FormatToken *Prev = Current->Previous; + if (Current->MustBreakBefore || Prev->Children.size() > 1 || + (Prev->Children.size() == 1 && + Prev->Children[0]->First->MustBreakBefore) || Current->IsMultiline) - Current->TotalLength = Current->Previous->TotalLength + Style.ColumnLimit; + Current->TotalLength = Prev->TotalLength + Style.ColumnLimit; else - Current->TotalLength = Current->Previous->TotalLength + - Current->ColumnWidth + ChildSize + - Current->SpacesRequiredBefore; + Current->TotalLength = Prev->TotalLength + Current->ColumnWidth + + ChildSize + Current->SpacesRequiredBefore; - if (Current->Type == TT_CtorInitializerColon) + if (Current->is(TT_CtorInitializerColon)) InFunctionDecl = false; // FIXME: Only calculate this if CanBreakBefore is true once static @@ -1349,20 +1493,34 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, if (Left.is(tok::semi)) return 0; + + if (Style.Language == FormatStyle::LK_Java) { + if (Right.isOneOf(Keywords.kw_extends, Keywords.kw_throws)) + return 1; + if (Right.is(Keywords.kw_implements)) + return 2; + if (Left.is(tok::comma) && Left.NestingLevel == 0) + return 3; + } else if (Style.Language == FormatStyle::LK_JavaScript) { + if (Right.is(Keywords.kw_function)) + return 100; + } + if (Left.is(tok::comma) || (Right.is(tok::identifier) && Right.Next && - Right.Next->Type == TT_DictLiteral)) + Right.Next->is(TT_DictLiteral))) return 1; if (Right.is(tok::l_square)) { if (Style.Language == FormatStyle::LK_Proto) return 1; - if (Right.Type != TT_ObjCMethodExpr && Right.Type != TT_LambdaLSquare) + if (!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare)) return 500; } - if (Right.Type == TT_StartOfName || - Right.Type == TT_FunctionDeclarationName || Right.is(tok::kw_operator)) { + + if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) || + Right.is(tok::kw_operator)) { if (Line.First->is(tok::kw_for) && Right.PartOfMultiVariableDeclStmt) return 3; - if (Left.Type == TT_StartOfName) + if (Left.is(TT_StartOfName)) return 20; if (InFunctionDecl && Right.NestingLevel == 0) return Style.PenaltyReturnTypeOnItsOwnLine; @@ -1370,7 +1528,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, } if (Left.is(tok::equal) && Right.is(tok::l_brace)) return 150; - if (Left.Type == TT_CastRParen) + if (Left.is(TT_CastRParen)) return 100; if (Left.is(tok::coloncolon) || (Right.is(tok::period) && Style.Language == FormatStyle::LK_Proto)) @@ -1378,8 +1536,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, if (Left.isOneOf(tok::kw_class, tok::kw_struct)) return 5000; - if (Left.Type == TT_RangeBasedForLoopColon || - Left.Type == TT_InheritanceColon) + if (Left.isOneOf(TT_RangeBasedForLoopColon, TT_InheritanceColon)) return 2; if (Right.isMemberAccess()) { @@ -1389,8 +1546,13 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, return 150; } - if (Right.Type == TT_TrailingAnnotation && + if (Right.is(TT_TrailingAnnotation) && (!Right.Next || Right.Next->isNot(tok::l_paren))) { + // Moving trailing annotations to the next line is fine for ObjC method + // declarations. + if (Line.First->is(TT_ObjCMethodSpecifier)) + + return 10; // Generally, breaking before a trailing annotation is bad unless it is // function-like. It seems to be especially preferable to keep standard // annotations (i.e. "const", "final" and "override") on the same line. @@ -1406,18 +1568,27 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, // In Objective-C method expressions, prefer breaking before "param:" over // breaking after it. - if (Right.Type == TT_SelectorName) + if (Right.is(TT_SelectorName)) return 0; - if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr) + if (Left.is(tok::colon) && Left.is(TT_ObjCMethodExpr)) return Line.MightBeFunctionDecl ? 50 : 500; - if (Left.is(tok::l_paren) && InFunctionDecl) + if (Left.is(tok::l_paren) && InFunctionDecl && Style.AlignAfterOpenBracket) return 100; if (Left.is(tok::equal) && InFunctionDecl) return 110; - if (Left.opensScope()) + if (Right.is(tok::r_brace)) + return 1; + if (Left.is(TT_TemplateOpener)) + return 100; + if (Left.opensScope()) { + if (!Style.AlignAfterOpenBracket) + return 0; return Left.ParameterCount > 1 ? Style.PenaltyBreakBeforeFirstCallParameter : 19; + } + if (Left.is(TT_JavaAnnotation)) + return 50; if (Right.is(tok::lessless)) { if (Left.is(tok::string_literal)) { @@ -1433,7 +1604,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, } return 1; // Breaking at a << is really cheap. } - if (Left.Type == TT_ConditionalExpr) + if (Left.is(TT_ConditionalExpr)) return prec::Conditional; prec::Level Level = Left.getPrecedence(); @@ -1446,18 +1617,6 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Left, const FormatToken &Right) { - if (Style.Language == FormatStyle::LK_Proto) { - if (Right.is(tok::period) && - (Left.TokenText == "optional" || Left.TokenText == "required" || - Left.TokenText == "repeated")) - return true; - if (Right.is(tok::l_paren) && - (Left.TokenText == "returns" || Left.TokenText == "option")) - return true; - } else if (Style.Language == FormatStyle::LK_JavaScript) { - if (Left.TokenText == "var") - return true; - } if (Left.is(tok::kw_return) && Right.isNot(tok::semi)) return true; if (Style.ObjCSpaceAfterProperty && Line.Type == LT_ObjCProperty && @@ -1470,21 +1629,16 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, 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)) + return (Right.is(TT_CastRParen) || + (Left.MatchingParen && Left.MatchingParen->is(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) || + (Left.isOneOf(tok::kw_template, tok::r_paren) || (Line.Type == LT_ObjCDecl && Style.ObjCSpaceBeforeProtocolList))) return true; - if (Left.is(tok::arrow) || Right.is(tok::arrow)) - return false; if (Left.isOneOf(tok::exclaim, tok::tilde)) return false; if (Left.is(tok::at) && @@ -1494,69 +1648,72 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return false; if (Left.is(tok::coloncolon)) return false; - if (Right.is(tok::coloncolon) && Left.isNot(tok::l_brace)) - 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) + if (Right.is(TT_PointerOrReference)) return Left.Tok.isLiteral() || - ((Left.Type != TT_PointerOrReference) && Left.isNot(tok::l_paren) && + (!Left.isOneOf(TT_PointerOrReference, tok::l_paren) && Style.PointerAlignment != FormatStyle::PAS_Left); - if (Right.Type == TT_FunctionTypeLParen && Left.isNot(tok::l_paren) && - (Left.Type != TT_PointerOrReference || Style.PointerAlignment != FormatStyle::PAS_Right)) + if (Right.is(TT_FunctionTypeLParen) && Left.isNot(tok::l_paren) && + (!Left.is(TT_PointerOrReference) || + Style.PointerAlignment != FormatStyle::PAS_Right)) return true; - if (Left.Type == TT_PointerOrReference) - return Right.Tok.isLiteral() || Right.Type == TT_BlockComment || - ((Right.Type != TT_PointerOrReference) && - Right.isNot(tok::l_paren) && Style.PointerAlignment != FormatStyle::PAS_Right && - Left.Previous && + if (Left.is(TT_PointerOrReference)) + return Right.Tok.isLiteral() || Right.is(TT_BlockComment) || + (!Right.isOneOf(TT_PointerOrReference, tok::l_paren) && + Style.PointerAlignment != FormatStyle::PAS_Right && 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_ArrayInitializerLSquare && - Style.SpacesInContainerLiterals && Right.isNot(tok::r_square); + return (Left.is(TT_ArrayInitializerLSquare) && + Style.SpacesInContainerLiterals && Right.isNot(tok::r_square)) || + (Left.is(TT_ArraySubscriptLSquare) && Style.SpacesInSquareBrackets && + Right.isNot(tok::r_square)); if (Right.is(tok::r_square)) - return Right.MatchingParen && Style.SpacesInContainerLiterals && - Right.MatchingParen->Type == TT_ArrayInitializerLSquare; - if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr && - Right.Type != TT_LambdaLSquare && Left.isNot(tok::numeric_constant) && - Left.Type != TT_DictLiteral) + return Right.MatchingParen && + ((Style.SpacesInContainerLiterals && + Right.MatchingParen->is(TT_ArrayInitializerLSquare)) || + (Style.SpacesInSquareBrackets && + Right.MatchingParen->is(TT_ArraySubscriptLSquare))); + if (Right.is(tok::l_square) && + !Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare) && + !Left.isOneOf(tok::numeric_constant, TT_DictLiteral)) return false; if (Left.is(tok::colon)) - return Left.Type != TT_ObjCMethodExpr; - if (Left.Type == TT_BlockComment) + return !Left.is(TT_ObjCMethodExpr); + if (Left.is(tok::l_brace) && Right.is(tok::r_brace)) + return !Left.Children.empty(); // No spaces in "{}". + if ((Left.is(tok::l_brace) && Left.BlockKind != BK_Block) || + (Right.is(tok::r_brace) && Right.MatchingParen && + Right.MatchingParen->BlockKind != BK_Block)) + return !Style.Cpp11BracedListStyle; + if (Left.is(TT_BlockComment)) return !Left.TokenText.endswith("=*/"); if (Right.is(tok::l_paren)) { - if (Left.is(tok::r_paren) && Left.Type == TT_AttributeParen) + if (Left.is(tok::r_paren) && Left.is(TT_AttributeParen)) return true; - return Line.Type == LT_ObjCDecl || - Left.isOneOf(tok::kw_new, tok::kw_delete, tok::semi) || + return Line.Type == LT_ObjCDecl || Left.is(tok::semi) || (Style.SpaceBeforeParens != FormatStyle::SBPO_Never && (Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, - tok::kw_switch, tok::kw_catch, tok::kw_case) || + tok::kw_switch, tok::kw_case) || + (Left.isOneOf(tok::kw_try, tok::kw_catch, tok::kw_new, + tok::kw_delete) && + (!Left.Previous || Left.Previous->isNot(tok::period))) || Left.IsForEachMacro)) || (Style.SpaceBeforeParens == FormatStyle::SBPO_Always && - Left.isOneOf(tok::identifier, tok::kw___attribute) && + (Left.is(tok::identifier) || Left.isFunctionLikeKeyword()) && Line.Type != LT_PreprocessorDirective); } 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) && Left.BlockKind != BK_Block) || - (Right.is(tok::r_brace) && Right.MatchingParen && - Right.MatchingParen->BlockKind != BK_Block)) - return !Style.Cpp11BracedListStyle; - if (Right.Type == TT_UnaryOperator) + if (Right.is(TT_UnaryOperator)) return !Left.isOneOf(tok::l_paren, tok::l_square, tok::at) && - (Left.isNot(tok::colon) || Left.Type != TT_ObjCMethodExpr); + (Left.isNot(tok::colon) || Left.isNot(TT_ObjCMethodExpr)); if ((Left.isOneOf(tok::identifier, tok::greater, tok::r_square, tok::r_paren) || Left.isSimpleTypeSpecifier()) && @@ -1567,78 +1724,120 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return false; if (Right.is(tok::hash) && Left.is(tok::identifier) && Left.TokenText == "L") return false; + if (Left.is(TT_TemplateCloser) && Left.MatchingParen && + Left.MatchingParen->Previous && + Left.MatchingParen->Previous->is(tok::period)) + // A.<B>DoSomething(); + return false; + if (Left.is(TT_TemplateCloser) && Right.is(tok::l_square)) + return false; return true; } bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, - const FormatToken &Tok) { - if (Tok.Tok.getIdentifierInfo() && Tok.Previous->Tok.getIdentifierInfo()) + const FormatToken &Right) { + const FormatToken &Left = *Right.Previous; + if (Style.Language == FormatStyle::LK_Proto) { + if (Right.is(tok::period) && + Left.isOneOf(Keywords.kw_optional, Keywords.kw_required, + Keywords.kw_repeated)) + return true; + if (Right.is(tok::l_paren) && + Left.isOneOf(Keywords.kw_returns, Keywords.kw_option)) + return true; + } else if (Style.Language == FormatStyle::LK_JavaScript) { + if (Left.is(Keywords.kw_var)) + return true; + } else if (Style.Language == FormatStyle::LK_Java) { + if (Left.is(tok::r_square) && Right.is(tok::l_brace)) + return true; + if (Left.is(TT_LambdaArrow) || Right.is(TT_LambdaArrow)) + return true; + if (Left.is(Keywords.kw_synchronized) && Right.is(tok::l_paren)) + return Style.SpaceBeforeParens != FormatStyle::SBPO_Never; + if ((Left.isOneOf(tok::kw_static, tok::kw_public, tok::kw_private, + tok::kw_protected) || + Left.isOneOf(Keywords.kw_final, Keywords.kw_abstract, + Keywords.kw_native)) && + Right.is(TT_TemplateOpener)) + return true; + } + if (Right.Tok.getIdentifierInfo() && Left.Tok.getIdentifierInfo()) return true; // Never ever merge two identifiers. - if (Tok.Previous->Type == TT_ImplicitStringLiteral) - return Tok.WhitespaceRange.getBegin() != Tok.WhitespaceRange.getEnd(); + if (Left.is(TT_ImplicitStringLiteral)) + return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd(); if (Line.Type == LT_ObjCMethodDecl) { - if (Tok.Previous->Type == TT_ObjCMethodSpecifier) + if (Left.is(TT_ObjCMethodSpecifier)) return true; - if (Tok.Previous->is(tok::r_paren) && Tok.is(tok::identifier)) + if (Left.is(tok::r_paren) && Right.is(tok::identifier)) // Don't space between ')' and <id> return false; } if (Line.Type == LT_ObjCProperty && - (Tok.is(tok::equal) || Tok.Previous->is(tok::equal))) + (Right.is(tok::equal) || Left.is(tok::equal))) return false; - if (Tok.Type == TT_TrailingReturnArrow || - Tok.Previous->Type == TT_TrailingReturnArrow) + if (Right.is(TT_TrailingReturnArrow) || Left.is(TT_TrailingReturnArrow)) return true; - if (Tok.Previous->is(tok::comma)) + if (Left.is(tok::comma)) return true; - if (Tok.is(tok::comma)) + if (Right.is(tok::comma)) return false; - if (Tok.Type == TT_CtorInitializerColon || Tok.Type == TT_ObjCBlockLParen) + if (Right.isOneOf(TT_CtorInitializerColon, TT_ObjCBlockLParen)) return true; - if (Tok.Previous->Tok.is(tok::kw_operator)) - return Tok.is(tok::coloncolon); - if (Tok.Type == TT_OverloadedOperatorLParen) + if (Left.is(tok::kw_operator)) + return Right.is(tok::coloncolon); + if (Right.is(TT_OverloadedOperatorLParen)) return false; - if (Tok.is(tok::colon)) + if (Right.is(tok::colon)) return !Line.First->isOneOf(tok::kw_case, tok::kw_default) && - Tok.getNextNonComment() && Tok.Type != TT_ObjCMethodExpr && - !Tok.Previous->is(tok::question) && - (Tok.Type != TT_DictLiteral || Style.SpacesInContainerLiterals); - if (Tok.Previous->Type == TT_UnaryOperator || - Tok.Previous->Type == TT_CastRParen) - return Tok.Type == TT_BinaryOperator; - if (Tok.Previous->is(tok::greater) && Tok.is(tok::greater)) { - return Tok.Type == TT_TemplateCloser && - Tok.Previous->Type == TT_TemplateCloser && + Right.getNextNonComment() && Right.isNot(TT_ObjCMethodExpr) && + !Left.is(tok::question) && + !(Right.is(TT_InlineASMColon) && Left.is(tok::coloncolon)) && + (Right.isNot(TT_DictLiteral) || Style.SpacesInContainerLiterals); + if (Left.is(TT_UnaryOperator)) + return Right.is(TT_BinaryOperator); + if (Left.is(TT_CastRParen)) + return Style.SpaceAfterCStyleCast || Right.is(TT_BinaryOperator); + if (Left.is(tok::greater) && Right.is(tok::greater)) { + return Right.is(TT_TemplateCloser) && Left.is(TT_TemplateCloser) && (Style.Standard != FormatStyle::LS_Cpp11 || Style.SpacesInAngles); } - if (Tok.isOneOf(tok::arrowstar, tok::periodstar) || - Tok.Previous->isOneOf(tok::arrowstar, tok::periodstar)) + if (Right.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) || + Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar)) return false; if (!Style.SpaceBeforeAssignmentOperators && - Tok.getPrecedence() == prec::Assignment) + Right.getPrecedence() == prec::Assignment) return false; - if ((Tok.Type == TT_BinaryOperator && !Tok.Previous->is(tok::l_paren)) || - Tok.Previous->Type == TT_BinaryOperator || - Tok.Previous->Type == TT_ConditionalExpr) + if (Right.is(tok::coloncolon) && Left.isNot(tok::l_brace)) + return (Left.is(TT_TemplateOpener) && + Style.Standard == FormatStyle::LS_Cpp03) || + !(Left.isOneOf(tok::identifier, tok::l_paren, tok::r_paren) || + Left.isOneOf(TT_TemplateCloser, TT_TemplateOpener)); + if ((Left.is(TT_TemplateOpener)) != (Right.is(TT_TemplateCloser))) + return Style.SpacesInAngles; + if ((Right.is(TT_BinaryOperator) && !Left.is(tok::l_paren)) || + Left.isOneOf(TT_BinaryOperator, TT_ConditionalExpr)) return true; - if (Tok.Previous->Type == TT_TemplateCloser && Tok.is(tok::l_paren)) + if (Left.is(TT_TemplateCloser) && Right.is(tok::l_paren)) + return Style.SpaceBeforeParens == FormatStyle::SBPO_Always; + if (Right.is(TT_TemplateOpener) && Left.is(tok::r_paren) && + Left.MatchingParen && Left.MatchingParen->is(TT_OverloadedOperatorLParen)) return false; - if (Tok.is(tok::less) && Tok.Previous->isNot(tok::l_paren) && + if (Right.is(tok::less) && Left.isNot(tok::l_paren) && Line.First->is(tok::hash)) return true; - if (Tok.Type == TT_TrailingUnaryOperator) + if (Right.is(TT_TrailingUnaryOperator)) return false; - if (Tok.Previous->Type == TT_RegexLiteral) + if (Left.is(TT_RegexLiteral)) return false; - return spaceRequiredBetween(Line, *Tok.Previous, Tok); + return spaceRequiredBetween(Line, Left, Right); } // Returns 'true' if 'Tok' is a brace we'd want to break before in Allman style. static bool isAllmanBrace(const FormatToken &Tok) { return Tok.is(tok::l_brace) && Tok.BlockKind == BK_Block && - Tok.Type != TT_ObjCBlockLBrace && Tok.Type != TT_DictLiteral; + !Tok.isOneOf(TT_ObjCBlockLBrace, TT_DictLiteral); } bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, @@ -1646,54 +1845,66 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, const FormatToken &Left = *Right.Previous; if (Right.NewlinesBefore > 1) return true; - if (Right.is(tok::comment)) { - return Right.Previous->BlockKind != BK_BracedInit && - Right.Previous->Type != TT_CtorInitializerColon && + + // If the last token before a '}' is a comma or a trailing comment, the + // intention is to insert a line break after it in order to make shuffling + // around entries easier. + const FormatToken *BeforeClosingBrace = nullptr; + if (Left.is(tok::l_brace) && Left.BlockKind != BK_Block && Left.MatchingParen) + BeforeClosingBrace = Left.MatchingParen->Previous; + else if (Right.is(tok::r_brace) && Right.BlockKind != BK_Block) + BeforeClosingBrace = &Left; + if (BeforeClosingBrace && (BeforeClosingBrace->is(tok::comma) || + BeforeClosingBrace->isTrailingComment())) + return true; + + if (Right.is(tok::comment)) + return Left.BlockKind != BK_BracedInit && + Left.isNot(TT_CtorInitializerColon) && (Right.NewlinesBefore > 0 && Right.HasUnescapedNewline); - } else if (Right.Previous->isTrailingComment() || - (Right.isStringLiteral() && Right.Previous->isStringLiteral())) { + if (Right.Previous->isTrailingComment() || + (Right.isStringLiteral() && Right.Previous->isStringLiteral())) return true; - } else if (Right.Previous->IsUnterminatedLiteral) { + 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)) { + 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->NestingLevel == 0 && - Style.AlwaysBreakTemplateDeclarations) { + if (Right.Previous->ClosesTemplateDeclaration && + Right.Previous->MatchingParen && + Right.Previous->MatchingParen->NestingLevel == 0 && + Style.AlwaysBreakTemplateDeclarations) return true; - } else if ((Right.Type == TT_CtorInitializerComma || - Right.Type == TT_CtorInitializerColon) && - Style.BreakConstructorInitializersBeforeComma && - !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) { + if ((Right.isOneOf(TT_CtorInitializerComma, TT_CtorInitializerColon)) && + Style.BreakConstructorInitializersBeforeComma && + !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) return true; - } else if (Right.is(tok::string_literal) && - Right.TokenText.startswith("R\"")) { + if (Right.is(tok::string_literal) && Right.TokenText.startswith("R\"")) // Raw string literals are special wrt. line breaks. The author has made a // deliberate choice and might have aligned the contents of the string // literal accordingly. Thus, we try keep existing line breaks. return Right.NewlinesBefore > 0; - } else if (Right.Previous->is(tok::l_brace) && Right.NestingLevel == 1 && - Style.Language == FormatStyle::LK_Proto) { - // Don't enums onto single lines in protocol buffers. + if (Right.Previous->is(tok::l_brace) && Right.NestingLevel == 1 && + Style.Language == FormatStyle::LK_Proto) + // Don't put enums onto single lines in protocol buffers. return true; - } else if (isAllmanBrace(Left) || isAllmanBrace(Right)) { + if (Style.Language == FormatStyle::LK_JavaScript && Right.is(tok::r_brace) && + Left.is(tok::l_brace) && !Left.Children.empty()) + // Support AllowShortFunctionsOnASingleLine for JavaScript. + return Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_None || + (Left.NestingLevel == 0 && Line.Level == 0 && + Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline); + if (isAllmanBrace(Left) || isAllmanBrace(Right)) return Style.BreakBeforeBraces == FormatStyle::BS_Allman || Style.BreakBeforeBraces == FormatStyle::BS_GNU; - } - - // If the last token before a '}' is a comma or a comment, the intention is to - // insert a line break after it in order to make shuffling around entries - // easier. - const FormatToken *BeforeClosingBrace = nullptr; - if (Left.is(tok::l_brace) && Left.MatchingParen) - BeforeClosingBrace = Left.MatchingParen->Previous; - else if (Right.is(tok::r_brace)) - BeforeClosingBrace = Right.Previous; - if (BeforeClosingBrace && - BeforeClosingBrace->isOneOf(tok::comma, tok::comment)) + if (Style.Language == FormatStyle::LK_Proto && Left.isNot(tok::l_brace) && + Right.is(TT_SelectorName)) + return true; + if (Left.is(TT_ObjCBlockLBrace) && !Style.AllowShortBlocksOnASingleLine) + return true; + if (Right.is(tok::lessless) && Left.is(tok::identifier) && + Left.TokenText == "endl") return true; if (Style.Language == FormatStyle::LK_JavaScript) { @@ -1701,6 +1912,17 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, if (Right.is(tok::char_constant) && Left.is(tok::plus) && Left.Previous && Left.Previous->is(tok::char_constant)) return true; + if (Left.is(TT_DictLiteral) && Left.is(tok::l_brace) && + Left.NestingLevel == 0) + return true; + } else if (Style.Language == FormatStyle::LK_Java) { + if (Left.is(TT_LeadingJavaAnnotation) && + Right.isNot(TT_LeadingJavaAnnotation) && Right.isNot(tok::l_paren) && + Line.Last->is(tok::l_brace)) + return true; + if (Right.is(tok::plus) && Left.is(tok::string_literal) && Right.Next && + Right.Next->is(tok::string_literal)) + return true; } return false; @@ -1709,12 +1931,24 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, const FormatToken &Right) { const FormatToken &Left = *Right.Previous; + + if (Style.Language == FormatStyle::LK_Java) { + if (Left.isOneOf(Keywords.kw_throws, Keywords.kw_extends, + Keywords.kw_implements)) + return false; + if (Right.isOneOf(Keywords.kw_throws, Keywords.kw_extends, + Keywords.kw_implements)) + return true; + } + if (Left.is(tok::at)) return false; if (Left.Tok.getObjCKeywordID() == tok::objc_interface) return false; - if (Right.Type == TT_StartOfName || - Right.Type == TT_FunctionDeclarationName || Right.is(tok::kw_operator)) + if (Left.isOneOf(TT_JavaAnnotation, TT_LeadingJavaAnnotation)) + return !Right.is(tok::l_paren); + if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) || + Right.is(tok::kw_operator)) return true; if (Right.isTrailingComment()) // We rely on MustBreakBefore being set correctly here as we should not @@ -1725,47 +1959,46 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, return Left.BlockKind == BK_BracedInit; if (Left.is(tok::question) && Right.is(tok::colon)) return false; - if (Right.Type == TT_ConditionalExpr || Right.is(tok::question)) + if (Right.is(TT_ConditionalExpr) || Right.is(tok::question)) return Style.BreakBeforeTernaryOperators; - if (Left.Type == TT_ConditionalExpr || Left.is(tok::question)) + if (Left.is(TT_ConditionalExpr) || Left.is(tok::question)) return !Style.BreakBeforeTernaryOperators; - if (Right.Type == TT_InheritanceColon) + if (Right.is(TT_InheritanceColon)) return true; - if (Right.is(tok::colon) && (Right.Type != TT_CtorInitializerColon && - Right.Type != TT_InlineASMColon)) + if (Right.is(tok::colon) && + !Right.isOneOf(TT_CtorInitializerColon, TT_InlineASMColon)) return false; - if (Left.is(tok::colon) && - (Left.Type == TT_DictLiteral || Left.Type == TT_ObjCMethodExpr)) + if (Left.is(tok::colon) && (Left.isOneOf(TT_DictLiteral, TT_ObjCMethodExpr))) return true; - if (Right.Type == TT_SelectorName) + if (Right.is(TT_SelectorName)) return true; if (Left.is(tok::r_paren) && Line.Type == LT_ObjCProperty) return true; if (Left.ClosesTemplateDeclaration) return true; - if (Right.Type == TT_RangeBasedForLoopColon || - Right.Type == TT_OverloadedOperatorLParen || - Right.Type == TT_OverloadedOperator) + if (Right.isOneOf(TT_RangeBasedForLoopColon, TT_OverloadedOperatorLParen, + TT_OverloadedOperator)) return false; - if (Left.Type == TT_RangeBasedForLoopColon) + if (Left.is(TT_RangeBasedForLoopColon)) return true; - if (Right.Type == TT_RangeBasedForLoopColon) + if (Right.is(TT_RangeBasedForLoopColon)) return false; - if (Left.Type == TT_PointerOrReference || Left.Type == TT_TemplateCloser || - Left.Type == TT_UnaryOperator || Left.is(tok::kw_operator)) + if (Left.isOneOf(TT_PointerOrReference, TT_TemplateCloser, + 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) && Left.Type == TT_AttributeParen) + if (Left.is(tok::l_paren) && Left.is(TT_AttributeParen)) return false; if (Left.is(tok::l_paren) && Left.Previous && - (Left.Previous->Type == TT_BinaryOperator || - Left.Previous->Type == TT_CastRParen || Left.Previous->is(tok::kw_if))) + (Left.Previous->isOneOf(TT_BinaryOperator, TT_CastRParen) || + Left.Previous->is(tok::kw_if))) return false; - if (Right.Type == TT_ImplicitStringLiteral) + if (Right.is(TT_ImplicitStringLiteral)) return false; - if (Right.is(tok::r_paren) || Right.Type == TT_TemplateCloser) + if (Right.is(tok::r_paren) || Right.is(TT_TemplateCloser)) return false; // We only break before r_brace if there was a corresponding break before @@ -1775,7 +2008,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, // Allow breaking after a trailing annotation, e.g. after a method // declaration. - if (Left.Type == TT_TrailingAnnotation) + if (Left.is(TT_TrailingAnnotation)) return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal, tok::l_paren, tok::less, tok::coloncolon); @@ -1785,29 +2018,35 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, if (Left.is(tok::identifier) && Right.is(tok::string_literal)) return true; - if (Right.is(tok::identifier) && Right.Next && - Right.Next->Type == TT_DictLiteral) + if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral)) return true; - if (Left.Type == TT_CtorInitializerComma && + if (Left.is(TT_CtorInitializerComma) && Style.BreakConstructorInitializersBeforeComma) return false; - if (Right.Type == TT_CtorInitializerComma && + if (Right.is(TT_CtorInitializerComma) && Style.BreakConstructorInitializersBeforeComma) return true; if (Left.is(tok::greater) && Right.is(tok::greater) && - Left.Type != TT_TemplateCloser) + Left.isNot(TT_TemplateCloser)) return false; - if (Right.Type == TT_BinaryOperator && Style.BreakBeforeBinaryOperators) + if (Right.is(TT_BinaryOperator) && + Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None && + (Style.BreakBeforeBinaryOperators == FormatStyle::BOS_All || + Right.getPrecedence() != prec::Assignment)) + return true; + if (Left.is(TT_ArrayInitializerLSquare)) + return true; + if (Right.is(tok::kw_typename) && Left.isNot(tok::kw_const)) return true; - if (Left.Type == TT_ArrayInitializerLSquare) + if (Left.isBinaryOperator() && !Left.isOneOf(tok::arrowstar, tok::lessless) && + Style.BreakBeforeBinaryOperators != FormatStyle::BOS_All && + (Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None || + Left.getPrecedence() == prec::Assignment)) return true; - return (Left.isBinaryOperator() && - !Left.isOneOf(tok::arrowstar, tok::lessless) && - !Style.BreakBeforeBinaryOperators) || - Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace, + return Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace, tok::kw_class, tok::kw_struct) || - Right.isMemberAccess() || + Right.isMemberAccess() || Right.is(TT_TrailingReturnArrow) || Right.isOneOf(tok::lessless, tok::colon, tok::l_square, tok::at) || (Left.is(tok::r_paren) && Right.isOneOf(tok::identifier, tok::kw_const)) || |